Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/tools/jlink/plugins/CompressorPluginTest.java
41152 views
1
/*
2
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/*
25
* @test
26
* @summary Test zip compressor
27
* @author Jean-Francois Denise
28
* @modules java.base/jdk.internal.jimage.decompressor
29
* jdk.jlink/jdk.tools.jlink.internal
30
* jdk.jlink/jdk.tools.jlink.internal.plugins
31
* jdk.jlink/jdk.tools.jlink.plugin
32
* @run main CompressorPluginTest
33
*/
34
import java.net.URI;
35
import java.nio.ByteOrder;
36
import java.nio.file.FileSystem;
37
import java.nio.file.FileSystemNotFoundException;
38
import java.nio.file.FileSystems;
39
import java.nio.file.Files;
40
import java.nio.file.Path;
41
import java.nio.file.ProviderNotFoundException;
42
import java.util.Collections;
43
import java.util.HashMap;
44
import java.util.Iterator;
45
import java.util.List;
46
import java.util.Map;
47
import java.util.Properties;
48
import java.util.regex.Pattern;
49
import java.util.stream.Collectors;
50
import java.util.stream.Stream;
51
52
import jdk.internal.jimage.decompressor.CompressedResourceHeader;
53
import jdk.internal.jimage.decompressor.ResourceDecompressor;
54
import jdk.internal.jimage.decompressor.ResourceDecompressorFactory;
55
import jdk.internal.jimage.decompressor.StringSharingDecompressorFactory;
56
import jdk.internal.jimage.decompressor.ZipDecompressorFactory;
57
import jdk.tools.jlink.internal.ResourcePoolManager;
58
import jdk.tools.jlink.internal.StringTable;
59
import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
60
import jdk.tools.jlink.internal.plugins.StringSharingPlugin;
61
import jdk.tools.jlink.internal.plugins.ZipPlugin;
62
import jdk.tools.jlink.plugin.Plugin;
63
import jdk.tools.jlink.plugin.ResourcePool;
64
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
65
import jdk.tools.jlink.plugin.ResourcePoolEntry;
66
67
public class CompressorPluginTest {
68
69
private static int strID = 1;
70
71
public static void main(String[] args) throws Exception {
72
new CompressorPluginTest().test();
73
}
74
75
public void test() throws Exception {
76
FileSystem fs;
77
try {
78
fs = FileSystems.getFileSystem(URI.create("jrt:/"));
79
} catch (ProviderNotFoundException | FileSystemNotFoundException e) {
80
System.err.println("Not an image build, test skipped.");
81
return;
82
}
83
Path javabase = fs.getPath("/modules/java.base");
84
85
checkCompress(gatherResources(javabase), new ZipPlugin(), null,
86
new ResourceDecompressorFactory[]{
87
new ZipDecompressorFactory()
88
});
89
90
ResourcePool classes = gatherClasses(javabase);
91
// compress = String sharing
92
checkCompress(classes, new StringSharingPlugin(), null,
93
new ResourceDecompressorFactory[]{
94
new StringSharingDecompressorFactory()});
95
96
// compress level 0 == no compression
97
Properties options0 = new Properties();
98
DefaultCompressPlugin compressPlugin = new DefaultCompressPlugin();
99
options0.setProperty(compressPlugin.getName(),
100
DefaultCompressPlugin.LEVEL_0);
101
checkCompress(classes, compressPlugin,
102
options0,
103
new ResourceDecompressorFactory[]{
104
});
105
106
// compress level 1 == String sharing
107
Properties options1 = new Properties();
108
compressPlugin = new DefaultCompressPlugin();
109
options1.setProperty(compressPlugin.getName(), DefaultCompressPlugin.LEVEL_1);
110
checkCompress(classes, compressPlugin,
111
options1,
112
new ResourceDecompressorFactory[]{
113
new StringSharingDecompressorFactory()
114
});
115
116
// compress level 1 == String sharing + filter
117
options1.setProperty(DefaultCompressPlugin.FILTER,
118
"**Exception.class");
119
compressPlugin = new DefaultCompressPlugin();
120
options1.setProperty(compressPlugin.getName(), DefaultCompressPlugin.LEVEL_1);
121
checkCompress(classes, compressPlugin,
122
options1,
123
new ResourceDecompressorFactory[]{
124
new StringSharingDecompressorFactory()
125
}, Collections.singletonList(".*Exception.class"));
126
127
// compress level 2 == ZIP
128
Properties options2 = new Properties();
129
options2.setProperty(DefaultCompressPlugin.FILTER,
130
"**Exception.class");
131
compressPlugin = new DefaultCompressPlugin();
132
options2.setProperty(compressPlugin.getName(), DefaultCompressPlugin.LEVEL_2);
133
checkCompress(classes, compressPlugin,
134
options2,
135
new ResourceDecompressorFactory[]{
136
new ZipDecompressorFactory()
137
}, Collections.singletonList(".*Exception.class"));
138
139
// compress level 2 == ZIP + filter
140
options2.setProperty(DefaultCompressPlugin.FILTER,
141
"**Exception.class");
142
compressPlugin = new DefaultCompressPlugin();
143
options2.setProperty(compressPlugin.getName(), DefaultCompressPlugin.LEVEL_2);
144
checkCompress(classes, compressPlugin,
145
options2,
146
new ResourceDecompressorFactory[]{
147
new ZipDecompressorFactory(),
148
}, Collections.singletonList(".*Exception.class"));
149
}
150
151
private ResourcePool gatherResources(Path module) throws Exception {
152
ResourcePoolManager poolMgr = new ResourcePoolManager(ByteOrder.nativeOrder(), new StringTable() {
153
154
@Override
155
public int addString(String str) {
156
return -1;
157
}
158
159
@Override
160
public String getString(int id) {
161
return null;
162
}
163
});
164
165
ResourcePoolBuilder poolBuilder = poolMgr.resourcePoolBuilder();
166
try (Stream<Path> stream = Files.walk(module)) {
167
for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext();) {
168
Path p = iterator.next();
169
if (Files.isRegularFile(p)) {
170
byte[] content = Files.readAllBytes(p);
171
poolBuilder.add(ResourcePoolEntry.create(p.toString(), content));
172
}
173
}
174
}
175
return poolBuilder.build();
176
}
177
178
private ResourcePool gatherClasses(Path module) throws Exception {
179
ResourcePoolManager poolMgr = new ResourcePoolManager(ByteOrder.nativeOrder(), new StringTable() {
180
181
@Override
182
public int addString(String str) {
183
return -1;
184
}
185
186
@Override
187
public String getString(int id) {
188
return null;
189
}
190
});
191
192
ResourcePoolBuilder poolBuilder = poolMgr.resourcePoolBuilder();
193
try (Stream<Path> stream = Files.walk(module)) {
194
for (Iterator<Path> iterator = stream.iterator(); iterator.hasNext();) {
195
Path p = iterator.next();
196
if (Files.isRegularFile(p) && p.toString().endsWith(".class")) {
197
byte[] content = Files.readAllBytes(p);
198
poolBuilder.add(ResourcePoolEntry.create(p.toString(), content));
199
}
200
}
201
}
202
return poolBuilder.build();
203
}
204
205
private void checkCompress(ResourcePool resources, Plugin prov,
206
Properties config,
207
ResourceDecompressorFactory[] factories) throws Exception {
208
checkCompress(resources, prov, config, factories, Collections.emptyList());
209
}
210
211
private void checkCompress(ResourcePool resources, Plugin prov,
212
Properties config,
213
ResourceDecompressorFactory[] factories,
214
List<String> includes) throws Exception {
215
if (factories.length == 0) {
216
// no compression, nothing to check!
217
return;
218
}
219
220
long[] original = new long[1];
221
long[] compressed = new long[1];
222
resources.entries().forEach(resource -> {
223
List<Pattern> includesPatterns = includes.stream()
224
.map(Pattern::compile)
225
.collect(Collectors.toList());
226
227
Map<String, String> props = new HashMap<>();
228
if (config != null) {
229
for (String p : config.stringPropertyNames()) {
230
props.put(p, config.getProperty(p));
231
}
232
}
233
prov.configure(props);
234
final Map<Integer, String> strings = new HashMap<>();
235
ResourcePoolManager inputResourcesMgr = new ResourcePoolManager(ByteOrder.nativeOrder(), new StringTable() {
236
@Override
237
public int addString(String str) {
238
int id = strID;
239
strID += 1;
240
strings.put(id, str);
241
return id;
242
}
243
244
@Override
245
public String getString(int id) {
246
return strings.get(id);
247
}
248
});
249
inputResourcesMgr.add(resource);
250
ResourcePool compressedResources = applyCompressor(prov, inputResourcesMgr, resource, includesPatterns);
251
original[0] += resource.contentLength();
252
compressed[0] += compressedResources.findEntry(resource.path()).get().contentLength();
253
applyDecompressors(factories, inputResourcesMgr.resourcePool(), compressedResources, strings, includesPatterns);
254
});
255
String compressors = Stream.of(factories)
256
.map(Object::getClass)
257
.map(Class::getSimpleName)
258
.collect(Collectors.joining(", "));
259
String size = "Compressed size: " + compressed[0] + ", original size: " + original[0];
260
System.out.println("Used " + compressors + ". " + size);
261
if (original[0] <= compressed[0]) {
262
throw new AssertionError("java.base not compressed.");
263
}
264
}
265
266
private ResourcePool applyCompressor(Plugin plugin,
267
ResourcePoolManager inputResources,
268
ResourcePoolEntry res,
269
List<Pattern> includesPatterns) {
270
ResourcePoolManager resMgr = new ResourcePoolManager(ByteOrder.nativeOrder(),
271
inputResources.getStringTable());
272
ResourcePool compressedResourcePool = plugin.transform(inputResources.resourcePool(),
273
resMgr.resourcePoolBuilder());
274
String path = res.path();
275
ResourcePoolEntry compressed = compressedResourcePool.findEntry(path).get();
276
CompressedResourceHeader header
277
= CompressedResourceHeader.readFromResource(ByteOrder.nativeOrder(), compressed.contentBytes());
278
if (isIncluded(includesPatterns, path)) {
279
if (header == null) {
280
throw new AssertionError("Path should be compressed: " + path);
281
}
282
if (header.getDecompressorNameOffset() == 0) {
283
throw new AssertionError("Invalid plugin offset "
284
+ header.getDecompressorNameOffset());
285
}
286
if (header.getResourceSize() <= 0) {
287
throw new AssertionError("Invalid compressed size "
288
+ header.getResourceSize());
289
}
290
} else if (header != null) {
291
throw new AssertionError("Path should not be compressed: " + path);
292
}
293
return compressedResourcePool;
294
}
295
296
private void applyDecompressors(ResourceDecompressorFactory[] decompressors,
297
ResourcePool inputResources,
298
ResourcePool compressedResources,
299
Map<Integer, String> strings,
300
List<Pattern> includesPatterns) {
301
compressedResources.entries().forEach(compressed -> {
302
CompressedResourceHeader header = CompressedResourceHeader.readFromResource(
303
ByteOrder.nativeOrder(), compressed.contentBytes());
304
String path = compressed.path();
305
ResourcePoolEntry orig = inputResources.findEntry(path).get();
306
if (!isIncluded(includesPatterns, path)) {
307
return;
308
}
309
byte[] decompressed = compressed.contentBytes();
310
for (ResourceDecompressorFactory factory : decompressors) {
311
try {
312
ResourceDecompressor decompressor = factory.newDecompressor(new Properties());
313
decompressed = decompressor.decompress(
314
strings::get, decompressed,
315
CompressedResourceHeader.getSize(), header.getUncompressedSize());
316
} catch (Exception exp) {
317
throw new RuntimeException(exp);
318
}
319
}
320
321
if (decompressed.length != orig.contentLength()) {
322
throw new AssertionError("Invalid uncompressed size "
323
+ header.getUncompressedSize());
324
}
325
byte[] origContent = orig.contentBytes();
326
for (int i = 0; i < decompressed.length; i++) {
327
if (decompressed[i] != origContent[i]) {
328
throw new AssertionError("Decompressed and original differ at index " + i);
329
}
330
}
331
});
332
}
333
334
private boolean isIncluded(List<Pattern> includesPatterns, String path) {
335
return includesPatterns.isEmpty() ||
336
includesPatterns.stream().anyMatch((pattern) -> pattern.matcher(path).matches());
337
}
338
}
339
340