1 /* |
|
2 * Copyright (c) 2015, 2017, 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. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package jdk.internal.module; |
|
27 |
|
28 import java.lang.module.ModuleDescriptor; |
|
29 import java.lang.module.ModuleDescriptor.Builder; |
|
30 import java.lang.module.ModuleDescriptor.Requires; |
|
31 import java.lang.module.ModuleDescriptor.Exports; |
|
32 import java.lang.module.ModuleDescriptor.Opens; |
|
33 import java.lang.module.ModuleDescriptor.Provides; |
|
34 import java.lang.module.ModuleDescriptor.Version; |
|
35 import java.util.ArrayList; |
|
36 import java.util.Collections; |
|
37 import java.util.HashMap; |
|
38 import java.util.HashSet; |
|
39 import java.util.List; |
|
40 import java.util.Map; |
|
41 import java.util.Set; |
|
42 |
|
43 import jdk.internal.misc.JavaLangModuleAccess; |
|
44 import jdk.internal.misc.SharedSecrets; |
|
45 import jdk.internal.org.objectweb.asm.Attribute; |
|
46 import jdk.internal.org.objectweb.asm.ByteVector; |
|
47 import jdk.internal.org.objectweb.asm.ClassReader; |
|
48 import jdk.internal.org.objectweb.asm.ClassWriter; |
|
49 import jdk.internal.org.objectweb.asm.Label; |
|
50 import static jdk.internal.module.ClassFileConstants.*; |
|
51 |
|
52 |
|
53 /** |
|
54 * Provides ASM implementations of {@code Attribute} to read and write the |
|
55 * class file attributes in a module-info class file. |
|
56 */ |
|
57 |
|
58 public final class ClassFileAttributes { |
|
59 |
|
60 private ClassFileAttributes() { } |
|
61 |
|
62 /** |
|
63 * Module_attribute { |
|
64 * // See lang-vm.html for details. |
|
65 * } |
|
66 */ |
|
67 public static class ModuleAttribute extends Attribute { |
|
68 private static final JavaLangModuleAccess JLMA |
|
69 = SharedSecrets.getJavaLangModuleAccess(); |
|
70 |
|
71 private ModuleDescriptor descriptor; |
|
72 private Version replacementVersion; |
|
73 |
|
74 public ModuleAttribute(ModuleDescriptor descriptor) { |
|
75 super(MODULE); |
|
76 this.descriptor = descriptor; |
|
77 } |
|
78 |
|
79 public ModuleAttribute(Version v) { |
|
80 super(MODULE); |
|
81 this.replacementVersion = v; |
|
82 } |
|
83 |
|
84 public ModuleAttribute() { |
|
85 super(MODULE); |
|
86 } |
|
87 |
|
88 @Override |
|
89 protected Attribute read(ClassReader cr, |
|
90 int off, |
|
91 int len, |
|
92 char[] buf, |
|
93 int codeOff, |
|
94 Label[] labels) |
|
95 { |
|
96 // module_name (CONSTANT_Module_info) |
|
97 String mn = cr.readModule(off, buf); |
|
98 off += 2; |
|
99 |
|
100 // module_flags |
|
101 int module_flags = cr.readUnsignedShort(off); |
|
102 off += 2; |
|
103 |
|
104 Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>(); |
|
105 if ((module_flags & ACC_OPEN) != 0) |
|
106 modifiers.add(ModuleDescriptor.Modifier.OPEN); |
|
107 if ((module_flags & ACC_SYNTHETIC) != 0) |
|
108 modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC); |
|
109 if ((module_flags & ACC_MANDATED) != 0) |
|
110 modifiers.add(ModuleDescriptor.Modifier.MANDATED); |
|
111 |
|
112 Builder builder = JLMA.newModuleBuilder(mn, false, modifiers); |
|
113 |
|
114 // module_version |
|
115 String module_version = cr.readUTF8(off, buf); |
|
116 off += 2; |
|
117 if (replacementVersion != null) { |
|
118 builder.version(replacementVersion); |
|
119 } else if (module_version != null) { |
|
120 builder.version(module_version); |
|
121 } |
|
122 |
|
123 // requires_count and requires[requires_count] |
|
124 int requires_count = cr.readUnsignedShort(off); |
|
125 off += 2; |
|
126 for (int i=0; i<requires_count; i++) { |
|
127 // CONSTANT_Module_info |
|
128 String dn = cr.readModule(off, buf); |
|
129 off += 2; |
|
130 |
|
131 // requires_flags |
|
132 int requires_flags = cr.readUnsignedShort(off); |
|
133 off += 2; |
|
134 Set<Requires.Modifier> mods; |
|
135 if (requires_flags == 0) { |
|
136 mods = Collections.emptySet(); |
|
137 } else { |
|
138 mods = new HashSet<>(); |
|
139 if ((requires_flags & ACC_TRANSITIVE) != 0) |
|
140 mods.add(Requires.Modifier.TRANSITIVE); |
|
141 if ((requires_flags & ACC_STATIC_PHASE) != 0) |
|
142 mods.add(Requires.Modifier.STATIC); |
|
143 if ((requires_flags & ACC_SYNTHETIC) != 0) |
|
144 mods.add(Requires.Modifier.SYNTHETIC); |
|
145 if ((requires_flags & ACC_MANDATED) != 0) |
|
146 mods.add(Requires.Modifier.MANDATED); |
|
147 } |
|
148 |
|
149 // requires_version |
|
150 String requires_version = cr.readUTF8(off, buf); |
|
151 off += 2; |
|
152 if (requires_version == null) { |
|
153 builder.requires(mods, dn); |
|
154 } else { |
|
155 JLMA.requires(builder, mods, dn, requires_version); |
|
156 } |
|
157 } |
|
158 |
|
159 // exports_count and exports[exports_count] |
|
160 int exports_count = cr.readUnsignedShort(off); |
|
161 off += 2; |
|
162 if (exports_count > 0) { |
|
163 for (int i=0; i<exports_count; i++) { |
|
164 // CONSTANT_Package_info |
|
165 String pkg = cr.readPackage(off, buf).replace('/', '.'); |
|
166 off += 2; |
|
167 |
|
168 int exports_flags = cr.readUnsignedShort(off); |
|
169 off += 2; |
|
170 Set<Exports.Modifier> mods; |
|
171 if (exports_flags == 0) { |
|
172 mods = Collections.emptySet(); |
|
173 } else { |
|
174 mods = new HashSet<>(); |
|
175 if ((exports_flags & ACC_SYNTHETIC) != 0) |
|
176 mods.add(Exports.Modifier.SYNTHETIC); |
|
177 if ((exports_flags & ACC_MANDATED) != 0) |
|
178 mods.add(Exports.Modifier.MANDATED); |
|
179 } |
|
180 |
|
181 int exports_to_count = cr.readUnsignedShort(off); |
|
182 off += 2; |
|
183 if (exports_to_count > 0) { |
|
184 Set<String> targets = new HashSet<>(); |
|
185 for (int j=0; j<exports_to_count; j++) { |
|
186 String t = cr.readModule(off, buf); |
|
187 off += 2; |
|
188 targets.add(t); |
|
189 } |
|
190 builder.exports(mods, pkg, targets); |
|
191 } else { |
|
192 builder.exports(mods, pkg); |
|
193 } |
|
194 } |
|
195 } |
|
196 |
|
197 // opens_count and opens[opens_count] |
|
198 int open_count = cr.readUnsignedShort(off); |
|
199 off += 2; |
|
200 if (open_count > 0) { |
|
201 for (int i=0; i<open_count; i++) { |
|
202 // CONSTANT_Package_info |
|
203 String pkg = cr.readPackage(off, buf).replace('/', '.'); |
|
204 off += 2; |
|
205 |
|
206 int opens_flags = cr.readUnsignedShort(off); |
|
207 off += 2; |
|
208 Set<Opens.Modifier> mods; |
|
209 if (opens_flags == 0) { |
|
210 mods = Collections.emptySet(); |
|
211 } else { |
|
212 mods = new HashSet<>(); |
|
213 if ((opens_flags & ACC_SYNTHETIC) != 0) |
|
214 mods.add(Opens.Modifier.SYNTHETIC); |
|
215 if ((opens_flags & ACC_MANDATED) != 0) |
|
216 mods.add(Opens.Modifier.MANDATED); |
|
217 } |
|
218 |
|
219 int opens_to_count = cr.readUnsignedShort(off); |
|
220 off += 2; |
|
221 if (opens_to_count > 0) { |
|
222 Set<String> targets = new HashSet<>(); |
|
223 for (int j=0; j<opens_to_count; j++) { |
|
224 String t = cr.readModule(off, buf); |
|
225 off += 2; |
|
226 targets.add(t); |
|
227 } |
|
228 builder.opens(mods, pkg, targets); |
|
229 } else { |
|
230 builder.opens(mods, pkg); |
|
231 } |
|
232 } |
|
233 } |
|
234 |
|
235 // uses_count and uses_index[uses_count] |
|
236 int uses_count = cr.readUnsignedShort(off); |
|
237 off += 2; |
|
238 if (uses_count > 0) { |
|
239 for (int i=0; i<uses_count; i++) { |
|
240 String sn = cr.readClass(off, buf).replace('/', '.'); |
|
241 builder.uses(sn); |
|
242 off += 2; |
|
243 } |
|
244 } |
|
245 |
|
246 // provides_count and provides[provides_count] |
|
247 int provides_count = cr.readUnsignedShort(off); |
|
248 off += 2; |
|
249 if (provides_count > 0) { |
|
250 for (int i=0; i<provides_count; i++) { |
|
251 String service = cr.readClass(off, buf).replace('/', '.'); |
|
252 off += 2; |
|
253 int with_count = cr.readUnsignedShort(off); |
|
254 off += 2; |
|
255 List<String> providers = new ArrayList<>(); |
|
256 for (int j=0; j<with_count; j++) { |
|
257 String cn = cr.readClass(off, buf).replace('/', '.'); |
|
258 off += 2; |
|
259 providers.add(cn); |
|
260 } |
|
261 builder.provides(service, providers); |
|
262 } |
|
263 } |
|
264 |
|
265 return new ModuleAttribute(builder.build()); |
|
266 } |
|
267 |
|
268 @Override |
|
269 protected ByteVector write(ClassWriter cw, |
|
270 byte[] code, |
|
271 int len, |
|
272 int maxStack, |
|
273 int maxLocals) |
|
274 { |
|
275 assert descriptor != null; |
|
276 ByteVector attr = new ByteVector(); |
|
277 |
|
278 // module_name |
|
279 String mn = descriptor.name(); |
|
280 int module_name_index = cw.newModule(mn); |
|
281 attr.putShort(module_name_index); |
|
282 |
|
283 // module_flags |
|
284 Set<ModuleDescriptor.Modifier> modifiers = descriptor.modifiers(); |
|
285 int module_flags = 0; |
|
286 if (modifiers.contains(ModuleDescriptor.Modifier.OPEN)) |
|
287 module_flags |= ACC_OPEN; |
|
288 if (modifiers.contains(ModuleDescriptor.Modifier.SYNTHETIC)) |
|
289 module_flags |= ACC_SYNTHETIC; |
|
290 if (modifiers.contains(ModuleDescriptor.Modifier.MANDATED)) |
|
291 module_flags |= ACC_MANDATED; |
|
292 attr.putShort(module_flags); |
|
293 |
|
294 // module_version |
|
295 String vs = descriptor.rawVersion().orElse(null); |
|
296 if (vs == null) { |
|
297 attr.putShort(0); |
|
298 } else { |
|
299 int module_version_index = cw.newUTF8(vs); |
|
300 attr.putShort(module_version_index); |
|
301 } |
|
302 |
|
303 // requires_count |
|
304 attr.putShort(descriptor.requires().size()); |
|
305 |
|
306 // requires[requires_count] |
|
307 for (Requires r : descriptor.requires()) { |
|
308 int requires_index = cw.newModule(r.name()); |
|
309 attr.putShort(requires_index); |
|
310 |
|
311 int requires_flags = 0; |
|
312 if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) |
|
313 requires_flags |= ACC_TRANSITIVE; |
|
314 if (r.modifiers().contains(Requires.Modifier.STATIC)) |
|
315 requires_flags |= ACC_STATIC_PHASE; |
|
316 if (r.modifiers().contains(Requires.Modifier.SYNTHETIC)) |
|
317 requires_flags |= ACC_SYNTHETIC; |
|
318 if (r.modifiers().contains(Requires.Modifier.MANDATED)) |
|
319 requires_flags |= ACC_MANDATED; |
|
320 attr.putShort(requires_flags); |
|
321 |
|
322 int requires_version_index; |
|
323 vs = r.rawCompiledVersion().orElse(null); |
|
324 if (vs == null) { |
|
325 requires_version_index = 0; |
|
326 } else { |
|
327 requires_version_index = cw.newUTF8(vs); |
|
328 } |
|
329 attr.putShort(requires_version_index); |
|
330 } |
|
331 |
|
332 // exports_count and exports[exports_count]; |
|
333 attr.putShort(descriptor.exports().size()); |
|
334 for (Exports e : descriptor.exports()) { |
|
335 String pkg = e.source().replace('.', '/'); |
|
336 attr.putShort(cw.newPackage(pkg)); |
|
337 |
|
338 int exports_flags = 0; |
|
339 if (e.modifiers().contains(Exports.Modifier.SYNTHETIC)) |
|
340 exports_flags |= ACC_SYNTHETIC; |
|
341 if (e.modifiers().contains(Exports.Modifier.MANDATED)) |
|
342 exports_flags |= ACC_MANDATED; |
|
343 attr.putShort(exports_flags); |
|
344 |
|
345 if (e.isQualified()) { |
|
346 Set<String> ts = e.targets(); |
|
347 attr.putShort(ts.size()); |
|
348 ts.forEach(target -> attr.putShort(cw.newModule(target))); |
|
349 } else { |
|
350 attr.putShort(0); |
|
351 } |
|
352 } |
|
353 |
|
354 // opens_counts and opens[opens_counts] |
|
355 attr.putShort(descriptor.opens().size()); |
|
356 for (Opens obj : descriptor.opens()) { |
|
357 String pkg = obj.source().replace('.', '/'); |
|
358 attr.putShort(cw.newPackage(pkg)); |
|
359 |
|
360 int opens_flags = 0; |
|
361 if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC)) |
|
362 opens_flags |= ACC_SYNTHETIC; |
|
363 if (obj.modifiers().contains(Opens.Modifier.MANDATED)) |
|
364 opens_flags |= ACC_MANDATED; |
|
365 attr.putShort(opens_flags); |
|
366 |
|
367 if (obj.isQualified()) { |
|
368 Set<String> ts = obj.targets(); |
|
369 attr.putShort(ts.size()); |
|
370 ts.forEach(target -> attr.putShort(cw.newModule(target))); |
|
371 } else { |
|
372 attr.putShort(0); |
|
373 } |
|
374 } |
|
375 |
|
376 // uses_count and uses_index[uses_count] |
|
377 if (descriptor.uses().isEmpty()) { |
|
378 attr.putShort(0); |
|
379 } else { |
|
380 attr.putShort(descriptor.uses().size()); |
|
381 for (String s : descriptor.uses()) { |
|
382 String service = s.replace('.', '/'); |
|
383 int index = cw.newClass(service); |
|
384 attr.putShort(index); |
|
385 } |
|
386 } |
|
387 |
|
388 // provides_count and provides[provides_count] |
|
389 if (descriptor.provides().isEmpty()) { |
|
390 attr.putShort(0); |
|
391 } else { |
|
392 attr.putShort(descriptor.provides().size()); |
|
393 for (Provides p : descriptor.provides()) { |
|
394 String service = p.service().replace('.', '/'); |
|
395 attr.putShort(cw.newClass(service)); |
|
396 int with_count = p.providers().size(); |
|
397 attr.putShort(with_count); |
|
398 for (String provider : p.providers()) { |
|
399 attr.putShort(cw.newClass(provider.replace('.', '/'))); |
|
400 } |
|
401 } |
|
402 } |
|
403 |
|
404 return attr; |
|
405 } |
|
406 } |
|
407 |
|
408 /** |
|
409 * ModulePackages attribute. |
|
410 * |
|
411 * <pre> {@code |
|
412 * |
|
413 * ModulePackages_attribute { |
|
414 * // index to CONSTANT_utf8_info structure in constant pool representing |
|
415 * // the string "ModulePackages" |
|
416 * u2 attribute_name_index; |
|
417 * u4 attribute_length; |
|
418 * |
|
419 * // the number of entries in the packages table |
|
420 * u2 packages_count; |
|
421 * { // index to CONSTANT_Package_info structure with the package name |
|
422 * u2 package_index |
|
423 * } packages[package_count]; |
|
424 * |
|
425 * }</pre> |
|
426 */ |
|
427 public static class ModulePackagesAttribute extends Attribute { |
|
428 private final Set<String> packages; |
|
429 |
|
430 public ModulePackagesAttribute(Set<String> packages) { |
|
431 super(MODULE_PACKAGES); |
|
432 this.packages = packages; |
|
433 } |
|
434 |
|
435 public ModulePackagesAttribute() { |
|
436 this(null); |
|
437 } |
|
438 |
|
439 @Override |
|
440 protected Attribute read(ClassReader cr, |
|
441 int off, |
|
442 int len, |
|
443 char[] buf, |
|
444 int codeOff, |
|
445 Label[] labels) |
|
446 { |
|
447 // package count |
|
448 int package_count = cr.readUnsignedShort(off); |
|
449 off += 2; |
|
450 |
|
451 // packages |
|
452 Set<String> packages = new HashSet<>(); |
|
453 for (int i=0; i<package_count; i++) { |
|
454 String pkg = cr.readPackage(off, buf).replace('/', '.'); |
|
455 packages.add(pkg); |
|
456 off += 2; |
|
457 } |
|
458 |
|
459 return new ModulePackagesAttribute(packages); |
|
460 } |
|
461 |
|
462 @Override |
|
463 protected ByteVector write(ClassWriter cw, |
|
464 byte[] code, |
|
465 int len, |
|
466 int maxStack, |
|
467 int maxLocals) |
|
468 { |
|
469 assert packages != null; |
|
470 |
|
471 ByteVector attr = new ByteVector(); |
|
472 |
|
473 // package_count |
|
474 attr.putShort(packages.size()); |
|
475 |
|
476 // packages |
|
477 packages.stream() |
|
478 .map(p -> p.replace('.', '/')) |
|
479 .forEach(p -> attr.putShort(cw.newPackage(p))); |
|
480 |
|
481 return attr; |
|
482 } |
|
483 |
|
484 } |
|
485 |
|
486 /** |
|
487 * ModuleMainClass attribute. |
|
488 * |
|
489 * <pre> {@code |
|
490 * |
|
491 * MainClass_attribute { |
|
492 * // index to CONSTANT_utf8_info structure in constant pool representing |
|
493 * // the string "ModuleMainClass" |
|
494 * u2 attribute_name_index; |
|
495 * u4 attribute_length; |
|
496 * |
|
497 * // index to CONSTANT_Class_info structure with the main class name |
|
498 * u2 main_class_index; |
|
499 * } |
|
500 * |
|
501 * } </pre> |
|
502 */ |
|
503 public static class ModuleMainClassAttribute extends Attribute { |
|
504 private final String mainClass; |
|
505 |
|
506 public ModuleMainClassAttribute(String mainClass) { |
|
507 super(MODULE_MAIN_CLASS); |
|
508 this.mainClass = mainClass; |
|
509 } |
|
510 |
|
511 public ModuleMainClassAttribute() { |
|
512 this(null); |
|
513 } |
|
514 |
|
515 @Override |
|
516 protected Attribute read(ClassReader cr, |
|
517 int off, |
|
518 int len, |
|
519 char[] buf, |
|
520 int codeOff, |
|
521 Label[] labels) |
|
522 { |
|
523 String value = cr.readClass(off, buf).replace('/', '.'); |
|
524 return new ModuleMainClassAttribute(value); |
|
525 } |
|
526 |
|
527 @Override |
|
528 protected ByteVector write(ClassWriter cw, |
|
529 byte[] code, |
|
530 int len, |
|
531 int maxStack, |
|
532 int maxLocals) |
|
533 { |
|
534 ByteVector attr = new ByteVector(); |
|
535 int index = cw.newClass(mainClass.replace('.', '/')); |
|
536 attr.putShort(index); |
|
537 return attr; |
|
538 } |
|
539 } |
|
540 |
|
541 /** |
|
542 * ModuleTarget attribute. |
|
543 * |
|
544 * <pre> {@code |
|
545 * |
|
546 * TargetPlatform_attribute { |
|
547 * // index to CONSTANT_utf8_info structure in constant pool representing |
|
548 * // the string "ModuleTarget" |
|
549 * u2 attribute_name_index; |
|
550 * u4 attribute_length; |
|
551 * |
|
552 * // index to CONSTANT_utf8_info structure with the target platform |
|
553 * u2 target_platform_index; |
|
554 * } |
|
555 * |
|
556 * } </pre> |
|
557 */ |
|
558 public static class ModuleTargetAttribute extends Attribute { |
|
559 private final String targetPlatform; |
|
560 |
|
561 public ModuleTargetAttribute(String targetPlatform) { |
|
562 super(MODULE_TARGET); |
|
563 this.targetPlatform = targetPlatform; |
|
564 } |
|
565 |
|
566 public ModuleTargetAttribute() { |
|
567 this(null); |
|
568 } |
|
569 |
|
570 public String targetPlatform() { |
|
571 return targetPlatform; |
|
572 } |
|
573 |
|
574 @Override |
|
575 protected Attribute read(ClassReader cr, |
|
576 int off, |
|
577 int len, |
|
578 char[] buf, |
|
579 int codeOff, |
|
580 Label[] labels) |
|
581 { |
|
582 |
|
583 String targetPlatform = null; |
|
584 |
|
585 int target_platform_index = cr.readUnsignedShort(off); |
|
586 if (target_platform_index != 0) |
|
587 targetPlatform = cr.readUTF8(off, buf); |
|
588 off += 2; |
|
589 |
|
590 return new ModuleTargetAttribute(targetPlatform); |
|
591 } |
|
592 |
|
593 @Override |
|
594 protected ByteVector write(ClassWriter cw, |
|
595 byte[] code, |
|
596 int len, |
|
597 int maxStack, |
|
598 int maxLocals) |
|
599 { |
|
600 ByteVector attr = new ByteVector(); |
|
601 |
|
602 int target_platform_index = 0; |
|
603 if (targetPlatform != null && targetPlatform.length() > 0) |
|
604 target_platform_index = cw.newUTF8(targetPlatform); |
|
605 attr.putShort(target_platform_index); |
|
606 |
|
607 return attr; |
|
608 } |
|
609 } |
|
610 |
|
611 /** |
|
612 * ModuleHashes attribute. |
|
613 * |
|
614 * <pre> {@code |
|
615 * |
|
616 * ModuleHashes_attribute { |
|
617 * // index to CONSTANT_utf8_info structure in constant pool representing |
|
618 * // the string "ModuleHashes" |
|
619 * u2 attribute_name_index; |
|
620 * u4 attribute_length; |
|
621 * |
|
622 * // index to CONSTANT_utf8_info structure with algorithm name |
|
623 * u2 algorithm_index; |
|
624 * |
|
625 * // the number of entries in the hashes table |
|
626 * u2 hashes_count; |
|
627 * { u2 module_name_index (index to CONSTANT_Module_info structure) |
|
628 * u2 hash_length; |
|
629 * u1 hash[hash_length]; |
|
630 * } hashes[hashes_count]; |
|
631 * |
|
632 * } </pre> |
|
633 */ |
|
634 static class ModuleHashesAttribute extends Attribute { |
|
635 private final ModuleHashes hashes; |
|
636 |
|
637 ModuleHashesAttribute(ModuleHashes hashes) { |
|
638 super(MODULE_HASHES); |
|
639 this.hashes = hashes; |
|
640 } |
|
641 |
|
642 ModuleHashesAttribute() { |
|
643 this(null); |
|
644 } |
|
645 |
|
646 @Override |
|
647 protected Attribute read(ClassReader cr, |
|
648 int off, |
|
649 int len, |
|
650 char[] buf, |
|
651 int codeOff, |
|
652 Label[] labels) |
|
653 { |
|
654 String algorithm = cr.readUTF8(off, buf); |
|
655 off += 2; |
|
656 |
|
657 int hashes_count = cr.readUnsignedShort(off); |
|
658 off += 2; |
|
659 |
|
660 Map<String, byte[]> map = new HashMap<>(); |
|
661 for (int i=0; i<hashes_count; i++) { |
|
662 String mn = cr.readModule(off, buf); |
|
663 off += 2; |
|
664 |
|
665 int hash_length = cr.readUnsignedShort(off); |
|
666 off += 2; |
|
667 byte[] hash = new byte[hash_length]; |
|
668 for (int j=0; j<hash_length; j++) { |
|
669 hash[j] = (byte) (0xff & cr.readByte(off+j)); |
|
670 } |
|
671 off += hash_length; |
|
672 |
|
673 map.put(mn, hash); |
|
674 } |
|
675 |
|
676 ModuleHashes hashes = new ModuleHashes(algorithm, map); |
|
677 |
|
678 return new ModuleHashesAttribute(hashes); |
|
679 } |
|
680 |
|
681 @Override |
|
682 protected ByteVector write(ClassWriter cw, |
|
683 byte[] code, |
|
684 int len, |
|
685 int maxStack, |
|
686 int maxLocals) |
|
687 { |
|
688 ByteVector attr = new ByteVector(); |
|
689 |
|
690 int index = cw.newUTF8(hashes.algorithm()); |
|
691 attr.putShort(index); |
|
692 |
|
693 Set<String> names = hashes.names(); |
|
694 attr.putShort(names.size()); |
|
695 |
|
696 for (String mn : names) { |
|
697 byte[] hash = hashes.hashFor(mn); |
|
698 assert hash != null; |
|
699 attr.putShort(cw.newModule(mn)); |
|
700 |
|
701 attr.putShort(hash.length); |
|
702 for (byte b: hash) { |
|
703 attr.putByte(b); |
|
704 } |
|
705 } |
|
706 |
|
707 return attr; |
|
708 } |
|
709 } |
|
710 |
|
711 /** |
|
712 * ModuleResolution_attribute { |
|
713 * u2 attribute_name_index; // "ModuleResolution" |
|
714 * u4 attribute_length; // 2 |
|
715 * u2 resolution_flags; |
|
716 * |
|
717 * The value of the resolution_flags item is a mask of flags used to denote |
|
718 * properties of module resolution. The flags are as follows: |
|
719 * |
|
720 * // Optional |
|
721 * 0x0001 (DO_NOT_RESOLVE_BY_DEFAULT) |
|
722 * |
|
723 * // At most one of: |
|
724 * 0x0002 (WARN_DEPRECATED) |
|
725 * 0x0004 (WARN_DEPRECATED_FOR_REMOVAL) |
|
726 * 0x0008 (WARN_INCUBATING) |
|
727 */ |
|
728 static class ModuleResolutionAttribute extends Attribute { |
|
729 private final int value; |
|
730 |
|
731 ModuleResolutionAttribute() { |
|
732 super(MODULE_RESOLUTION); |
|
733 value = 0; |
|
734 } |
|
735 |
|
736 ModuleResolutionAttribute(int value) { |
|
737 super(MODULE_RESOLUTION); |
|
738 this.value = value; |
|
739 } |
|
740 |
|
741 @Override |
|
742 protected Attribute read(ClassReader cr, |
|
743 int off, |
|
744 int len, |
|
745 char[] buf, |
|
746 int codeOff, |
|
747 Label[] labels) |
|
748 { |
|
749 int flags = cr.readUnsignedShort(off); |
|
750 return new ModuleResolutionAttribute(flags); |
|
751 } |
|
752 |
|
753 @Override |
|
754 protected ByteVector write(ClassWriter cw, |
|
755 byte[] code, |
|
756 int len, |
|
757 int maxStack, |
|
758 int maxLocals) |
|
759 { |
|
760 ByteVector attr = new ByteVector(); |
|
761 attr.putShort(value); |
|
762 return attr; |
|
763 } |
|
764 } |
|
765 } |
|