Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java
41159 views
1
/*
2
* Copyright (c) 2014, 2020, 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.io.DataInput;
29
import java.io.DataInputStream;
30
import java.io.EOFException;
31
import java.io.IOException;
32
import java.io.InputStream;
33
import java.io.UncheckedIOException;
34
import java.lang.module.InvalidModuleDescriptorException;
35
import java.lang.module.ModuleDescriptor;
36
import java.lang.module.ModuleDescriptor.Builder;
37
import java.lang.module.ModuleDescriptor.Requires;
38
import java.lang.module.ModuleDescriptor.Exports;
39
import java.lang.module.ModuleDescriptor.Opens;
40
import java.nio.ByteBuffer;
41
import java.nio.BufferUnderflowException;
42
import java.util.ArrayList;
43
import java.util.HashMap;
44
import java.util.HashSet;
45
import java.util.List;
46
import java.util.Map;
47
import java.util.Set;
48
import java.util.function.Supplier;
49
50
import jdk.internal.access.JavaLangModuleAccess;
51
import jdk.internal.access.SharedSecrets;
52
import jdk.internal.misc.VM;
53
54
import static jdk.internal.module.ClassFileConstants.*;
55
56
57
/**
58
* Read module information from a {@code module-info} class file.
59
*
60
* @implNote The rationale for the hand-coded reader is startup performance
61
* and fine control over the throwing of InvalidModuleDescriptorException.
62
*/
63
64
public final class ModuleInfo {
65
66
private static final JavaLangModuleAccess JLMA
67
= SharedSecrets.getJavaLangModuleAccess();
68
69
// supplies the set of packages when ModulePackages attribute not present
70
private final Supplier<Set<String>> packageFinder;
71
72
// indicates if the ModuleHashes attribute should be parsed
73
private final boolean parseHashes;
74
75
private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
76
packageFinder = pf;
77
parseHashes = ph;
78
}
79
80
private ModuleInfo(Supplier<Set<String>> pf) {
81
this(pf, true);
82
}
83
84
/**
85
* A holder class for the ModuleDescriptor that is created by reading the
86
* Module and other standard class file attributes. It also holds the objects
87
* that represent the non-standard class file attributes that are read from
88
* the class file.
89
*/
90
public static final class Attributes {
91
private final ModuleDescriptor descriptor;
92
private final ModuleTarget target;
93
private final ModuleHashes recordedHashes;
94
private final ModuleResolution moduleResolution;
95
Attributes(ModuleDescriptor descriptor,
96
ModuleTarget target,
97
ModuleHashes recordedHashes,
98
ModuleResolution moduleResolution) {
99
this.descriptor = descriptor;
100
this.target = target;
101
this.recordedHashes = recordedHashes;
102
this.moduleResolution = moduleResolution;
103
}
104
public ModuleDescriptor descriptor() {
105
return descriptor;
106
}
107
public ModuleTarget target() {
108
return target;
109
}
110
public ModuleHashes recordedHashes() {
111
return recordedHashes;
112
}
113
public ModuleResolution moduleResolution() {
114
return moduleResolution;
115
}
116
}
117
118
119
/**
120
* Reads a {@code module-info.class} from the given input stream.
121
*
122
* @throws InvalidModuleDescriptorException
123
* @throws IOException
124
*/
125
public static Attributes read(InputStream in, Supplier<Set<String>> pf)
126
throws IOException
127
{
128
try {
129
return new ModuleInfo(pf).doRead(new DataInputStream(in));
130
} catch (IllegalArgumentException | IllegalStateException e) {
131
throw invalidModuleDescriptor(e.getMessage());
132
} catch (EOFException x) {
133
throw truncatedModuleDescriptor();
134
}
135
}
136
137
/**
138
* Reads a {@code module-info.class} from the given byte buffer.
139
*
140
* @throws InvalidModuleDescriptorException
141
* @throws UncheckedIOException
142
*/
143
public static Attributes read(ByteBuffer bb, Supplier<Set<String>> pf) {
144
try {
145
return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
146
} catch (IllegalArgumentException | IllegalStateException e) {
147
throw invalidModuleDescriptor(e.getMessage());
148
} catch (EOFException x) {
149
throw truncatedModuleDescriptor();
150
} catch (IOException ioe) {
151
throw new UncheckedIOException(ioe);
152
}
153
}
154
155
/**
156
* Reads a {@code module-info.class} from the given byte buffer
157
* but ignore the {@code ModuleHashes} attribute.
158
*
159
* @throws InvalidModuleDescriptorException
160
* @throws UncheckedIOException
161
*/
162
public static Attributes readIgnoringHashes(ByteBuffer bb, Supplier<Set<String>> pf) {
163
try {
164
return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
165
} catch (IllegalArgumentException | IllegalStateException e) {
166
throw invalidModuleDescriptor(e.getMessage());
167
} catch (EOFException x) {
168
throw truncatedModuleDescriptor();
169
} catch (IOException ioe) {
170
throw new UncheckedIOException(ioe);
171
}
172
}
173
174
/**
175
* Reads the input as a module-info class file.
176
*
177
* @throws IOException
178
* @throws InvalidModuleDescriptorException
179
* @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
180
* because an identifier is not a legal Java identifier, duplicate
181
* exports, and many other reasons
182
*/
183
private Attributes doRead(DataInput input) throws IOException {
184
var in = new CountingDataInput(input);
185
186
int magic = in.readInt();
187
if (magic != 0xCAFEBABE)
188
throw invalidModuleDescriptor("Bad magic number");
189
190
int minor_version = in.readUnsignedShort();
191
int major_version = in.readUnsignedShort();
192
if (!VM.isSupportedModuleDescriptorVersion(major_version, minor_version)) {
193
throw invalidModuleDescriptor("Unsupported major.minor version "
194
+ major_version + "." + minor_version);
195
}
196
197
ConstantPool cpool = new ConstantPool(in);
198
199
int access_flags = in.readUnsignedShort();
200
if (access_flags != ACC_MODULE)
201
throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
202
203
int this_class = in.readUnsignedShort();
204
String mn = cpool.getClassName(this_class);
205
if (!"module-info".equals(mn))
206
throw invalidModuleDescriptor("this_class should be module-info");
207
208
int super_class = in.readUnsignedShort();
209
if (super_class > 0)
210
throw invalidModuleDescriptor("bad #super_class");
211
212
int interfaces_count = in.readUnsignedShort();
213
if (interfaces_count > 0)
214
throw invalidModuleDescriptor("Bad #interfaces");
215
216
int fields_count = in.readUnsignedShort();
217
if (fields_count > 0)
218
throw invalidModuleDescriptor("Bad #fields");
219
220
int methods_count = in.readUnsignedShort();
221
if (methods_count > 0)
222
throw invalidModuleDescriptor("Bad #methods");
223
224
int attributes_count = in.readUnsignedShort();
225
226
// the names of the attributes found in the class file
227
Set<String> attributes = new HashSet<>();
228
229
Builder builder = null;
230
Set<String> allPackages = null;
231
String mainClass = null;
232
ModuleTarget moduleTarget = null;
233
ModuleHashes moduleHashes = null;
234
ModuleResolution moduleResolution = null;
235
236
for (int i = 0; i < attributes_count ; i++) {
237
int name_index = in.readUnsignedShort();
238
String attribute_name = cpool.getUtf8(name_index);
239
int length = in.readInt();
240
241
boolean added = attributes.add(attribute_name);
242
if (!added && isAttributeAtMostOnce(attribute_name)) {
243
throw invalidModuleDescriptor("More than one "
244
+ attribute_name + " attribute");
245
}
246
247
long initialPosition = in.count();
248
249
switch (attribute_name) {
250
case MODULE :
251
builder = readModuleAttribute(in, cpool, major_version);
252
break;
253
254
case MODULE_PACKAGES :
255
allPackages = readModulePackagesAttribute(in, cpool);
256
break;
257
258
case MODULE_MAIN_CLASS :
259
mainClass = readModuleMainClassAttribute(in, cpool);
260
break;
261
262
case MODULE_TARGET :
263
moduleTarget = readModuleTargetAttribute(in, cpool);
264
break;
265
266
case MODULE_HASHES :
267
if (parseHashes) {
268
moduleHashes = readModuleHashesAttribute(in, cpool);
269
} else {
270
in.skipBytes(length);
271
}
272
break;
273
274
case MODULE_RESOLUTION :
275
moduleResolution = readModuleResolution(in, cpool);
276
break;
277
278
default:
279
if (isAttributeDisallowed(attribute_name)) {
280
throw invalidModuleDescriptor(attribute_name
281
+ " attribute not allowed");
282
} else {
283
in.skipBytes(length);
284
}
285
}
286
287
long newPosition = in.count();
288
if ((newPosition - initialPosition) != length) {
289
// attribute length does not match actual attribute size
290
throw invalidModuleDescriptor("Attribute " + attribute_name
291
+ " does not match its expected length");
292
}
293
294
}
295
296
// the Module attribute is required
297
if (builder == null) {
298
throw invalidModuleDescriptor(MODULE + " attribute not found");
299
}
300
301
// ModuleMainClass attribute
302
if (mainClass != null) {
303
builder.mainClass(mainClass);
304
}
305
306
// If the ModulePackages attribute is not present then the packageFinder
307
// is used to find the set of packages
308
boolean usedPackageFinder = false;
309
if (allPackages == null && packageFinder != null) {
310
try {
311
allPackages = packageFinder.get();
312
} catch (UncheckedIOException x) {
313
throw x.getCause();
314
}
315
usedPackageFinder = true;
316
}
317
if (allPackages != null) {
318
Set<String> knownPackages = JLMA.packages(builder);
319
if (!allPackages.containsAll(knownPackages)) {
320
Set<String> missingPackages = new HashSet<>(knownPackages);
321
missingPackages.removeAll(allPackages);
322
assert !missingPackages.isEmpty();
323
String missingPackage = missingPackages.iterator().next();
324
String tail;
325
if (usedPackageFinder) {
326
tail = " not found in module";
327
} else {
328
tail = " missing from ModulePackages class file attribute";
329
}
330
throw invalidModuleDescriptor("Package " + missingPackage + tail);
331
332
}
333
builder.packages(allPackages);
334
}
335
336
ModuleDescriptor descriptor = builder.build();
337
return new Attributes(descriptor,
338
moduleTarget,
339
moduleHashes,
340
moduleResolution);
341
}
342
343
/**
344
* Reads the Module attribute, returning the ModuleDescriptor.Builder to
345
* build the corresponding ModuleDescriptor.
346
*/
347
private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major)
348
throws IOException
349
{
350
// module_name
351
int module_name_index = in.readUnsignedShort();
352
String mn = cpool.getModuleName(module_name_index);
353
354
int module_flags = in.readUnsignedShort();
355
356
Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>();
357
boolean open = ((module_flags & ACC_OPEN) != 0);
358
if (open)
359
modifiers.add(ModuleDescriptor.Modifier.OPEN);
360
if ((module_flags & ACC_SYNTHETIC) != 0)
361
modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
362
if ((module_flags & ACC_MANDATED) != 0)
363
modifiers.add(ModuleDescriptor.Modifier.MANDATED);
364
365
Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
366
367
int module_version_index = in.readUnsignedShort();
368
if (module_version_index != 0) {
369
String vs = cpool.getUtf8(module_version_index);
370
builder.version(vs);
371
}
372
373
int requires_count = in.readUnsignedShort();
374
boolean requiresJavaBase = false;
375
for (int i=0; i<requires_count; i++) {
376
int requires_index = in.readUnsignedShort();
377
String dn = cpool.getModuleName(requires_index);
378
379
int requires_flags = in.readUnsignedShort();
380
Set<Requires.Modifier> mods;
381
if (requires_flags == 0) {
382
mods = Set.of();
383
} else {
384
mods = new HashSet<>();
385
if ((requires_flags & ACC_TRANSITIVE) != 0)
386
mods.add(Requires.Modifier.TRANSITIVE);
387
if ((requires_flags & ACC_STATIC_PHASE) != 0)
388
mods.add(Requires.Modifier.STATIC);
389
if ((requires_flags & ACC_SYNTHETIC) != 0)
390
mods.add(Requires.Modifier.SYNTHETIC);
391
if ((requires_flags & ACC_MANDATED) != 0)
392
mods.add(Requires.Modifier.MANDATED);
393
}
394
395
int requires_version_index = in.readUnsignedShort();
396
if (requires_version_index == 0) {
397
builder.requires(mods, dn);
398
} else {
399
String vs = cpool.getUtf8(requires_version_index);
400
JLMA.requires(builder, mods, dn, vs);
401
}
402
403
if (dn.equals("java.base")) {
404
if (major >= 54
405
&& (mods.contains(Requires.Modifier.TRANSITIVE)
406
|| mods.contains(Requires.Modifier.STATIC))) {
407
String flagName;
408
if (mods.contains(Requires.Modifier.TRANSITIVE)) {
409
flagName = "ACC_TRANSITIVE";
410
} else {
411
flagName = "ACC_STATIC_PHASE";
412
}
413
throw invalidModuleDescriptor("The requires entry for java.base"
414
+ " has " + flagName + " set");
415
}
416
requiresJavaBase = true;
417
}
418
}
419
if (mn.equals("java.base")) {
420
if (requires_count > 0) {
421
throw invalidModuleDescriptor("The requires table for java.base"
422
+ " must be 0 length");
423
}
424
} else if (!requiresJavaBase) {
425
throw invalidModuleDescriptor("The requires table must have"
426
+ " an entry for java.base");
427
}
428
429
int exports_count = in.readUnsignedShort();
430
if (exports_count > 0) {
431
for (int i=0; i<exports_count; i++) {
432
int exports_index = in.readUnsignedShort();
433
String pkg = cpool.getPackageName(exports_index);
434
435
Set<Exports.Modifier> mods;
436
int exports_flags = in.readUnsignedShort();
437
if (exports_flags == 0) {
438
mods = Set.of();
439
} else {
440
mods = new HashSet<>();
441
if ((exports_flags & ACC_SYNTHETIC) != 0)
442
mods.add(Exports.Modifier.SYNTHETIC);
443
if ((exports_flags & ACC_MANDATED) != 0)
444
mods.add(Exports.Modifier.MANDATED);
445
}
446
447
int exports_to_count = in.readUnsignedShort();
448
if (exports_to_count > 0) {
449
Set<String> targets = new HashSet<>(exports_to_count);
450
for (int j=0; j<exports_to_count; j++) {
451
int exports_to_index = in.readUnsignedShort();
452
String target = cpool.getModuleName(exports_to_index);
453
if (!targets.add(target)) {
454
throw invalidModuleDescriptor(pkg + " exported to "
455
+ target + " more than once");
456
}
457
}
458
builder.exports(mods, pkg, targets);
459
} else {
460
builder.exports(mods, pkg);
461
}
462
}
463
}
464
465
int opens_count = in.readUnsignedShort();
466
if (opens_count > 0) {
467
if (open) {
468
throw invalidModuleDescriptor("The opens table for an open"
469
+ " module must be 0 length");
470
}
471
for (int i=0; i<opens_count; i++) {
472
int opens_index = in.readUnsignedShort();
473
String pkg = cpool.getPackageName(opens_index);
474
475
Set<Opens.Modifier> mods;
476
int opens_flags = in.readUnsignedShort();
477
if (opens_flags == 0) {
478
mods = Set.of();
479
} else {
480
mods = new HashSet<>();
481
if ((opens_flags & ACC_SYNTHETIC) != 0)
482
mods.add(Opens.Modifier.SYNTHETIC);
483
if ((opens_flags & ACC_MANDATED) != 0)
484
mods.add(Opens.Modifier.MANDATED);
485
}
486
487
int open_to_count = in.readUnsignedShort();
488
if (open_to_count > 0) {
489
Set<String> targets = new HashSet<>(open_to_count);
490
for (int j=0; j<open_to_count; j++) {
491
int opens_to_index = in.readUnsignedShort();
492
String target = cpool.getModuleName(opens_to_index);
493
if (!targets.add(target)) {
494
throw invalidModuleDescriptor(pkg + " opened to "
495
+ target + " more than once");
496
}
497
}
498
builder.opens(mods, pkg, targets);
499
} else {
500
builder.opens(mods, pkg);
501
}
502
}
503
}
504
505
int uses_count = in.readUnsignedShort();
506
if (uses_count > 0) {
507
for (int i=0; i<uses_count; i++) {
508
int index = in.readUnsignedShort();
509
String sn = cpool.getClassName(index);
510
builder.uses(sn);
511
}
512
}
513
514
int provides_count = in.readUnsignedShort();
515
if (provides_count > 0) {
516
for (int i=0; i<provides_count; i++) {
517
int index = in.readUnsignedShort();
518
String sn = cpool.getClassName(index);
519
int with_count = in.readUnsignedShort();
520
List<String> providers = new ArrayList<>(with_count);
521
for (int j=0; j<with_count; j++) {
522
index = in.readUnsignedShort();
523
String pn = cpool.getClassName(index);
524
if (!providers.add(pn)) {
525
throw invalidModuleDescriptor(sn + " provides " + pn
526
+ " more than once");
527
}
528
}
529
builder.provides(sn, providers);
530
}
531
}
532
533
return builder;
534
}
535
536
/**
537
* Reads the ModulePackages attribute
538
*/
539
private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool)
540
throws IOException
541
{
542
int package_count = in.readUnsignedShort();
543
Set<String> packages = new HashSet<>(package_count);
544
for (int i=0; i<package_count; i++) {
545
int index = in.readUnsignedShort();
546
String pn = cpool.getPackageName(index);
547
boolean added = packages.add(pn);
548
if (!added) {
549
throw invalidModuleDescriptor("Package " + pn + " in ModulePackages"
550
+ "attribute more than once");
551
}
552
}
553
return packages;
554
}
555
556
/**
557
* Reads the ModuleMainClass attribute
558
*/
559
private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
560
throws IOException
561
{
562
int index = in.readUnsignedShort();
563
return cpool.getClassName(index);
564
}
565
566
/**
567
* Reads the ModuleTarget attribute
568
*/
569
private ModuleTarget readModuleTargetAttribute(DataInput in, ConstantPool cpool)
570
throws IOException
571
{
572
String targetPlatform = null;
573
574
int index = in.readUnsignedShort();
575
if (index != 0)
576
targetPlatform = cpool.getUtf8(index);
577
578
return new ModuleTarget(targetPlatform);
579
}
580
581
/**
582
* Reads the ModuleHashes attribute
583
*/
584
private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
585
throws IOException
586
{
587
int algorithm_index = in.readUnsignedShort();
588
String algorithm = cpool.getUtf8(algorithm_index);
589
590
int hash_count = in.readUnsignedShort();
591
Map<String, byte[]> map = new HashMap<>(hash_count);
592
for (int i=0; i<hash_count; i++) {
593
int module_name_index = in.readUnsignedShort();
594
String mn = cpool.getModuleName(module_name_index);
595
int hash_length = in.readUnsignedShort();
596
if (hash_length == 0) {
597
throw invalidModuleDescriptor("hash_length == 0");
598
}
599
byte[] hash = new byte[hash_length];
600
in.readFully(hash);
601
map.put(mn, hash);
602
}
603
604
return new ModuleHashes(algorithm, map);
605
}
606
607
/**
608
* Reads the ModuleResolution attribute.
609
*/
610
private ModuleResolution readModuleResolution(DataInput in,
611
ConstantPool cpool)
612
throws IOException
613
{
614
int flags = in.readUnsignedShort();
615
616
int reason = 0;
617
if ((flags & WARN_DEPRECATED) != 0)
618
reason = WARN_DEPRECATED;
619
if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0) {
620
if (reason != 0)
621
throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
622
reason = WARN_DEPRECATED_FOR_REMOVAL;
623
}
624
if ((flags & WARN_INCUBATING) != 0) {
625
if (reason != 0)
626
throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
627
}
628
629
return new ModuleResolution(flags);
630
}
631
632
/**
633
* Returns true if the given attribute can be present at most once
634
* in the class file. Returns false otherwise.
635
*/
636
private static boolean isAttributeAtMostOnce(String name) {
637
638
if (name.equals(MODULE) ||
639
name.equals(SOURCE_FILE) ||
640
name.equals(SDE) ||
641
name.equals(MODULE_PACKAGES) ||
642
name.equals(MODULE_MAIN_CLASS) ||
643
name.equals(MODULE_TARGET) ||
644
name.equals(MODULE_HASHES) ||
645
name.equals(MODULE_RESOLUTION))
646
return true;
647
648
return false;
649
}
650
651
/**
652
* Return true if the given attribute name is the name of a pre-defined
653
* attribute in JVMS 4.7 that is not allowed in a module-info class.
654
*/
655
private static boolean isAttributeDisallowed(String name) {
656
Set<String> notAllowed = predefinedNotAllowed;
657
if (notAllowed == null) {
658
notAllowed = Set.of(
659
"ConstantValue",
660
"Code",
661
"Deprecated",
662
"StackMapTable",
663
"Exceptions",
664
"EnclosingMethod",
665
"Signature",
666
"LineNumberTable",
667
"LocalVariableTable",
668
"LocalVariableTypeTable",
669
"RuntimeVisibleParameterAnnotations",
670
"RuntimeInvisibleParameterAnnotations",
671
"RuntimeVisibleTypeAnnotations",
672
"RuntimeInvisibleTypeAnnotations",
673
"Synthetic",
674
"AnnotationDefault",
675
"BootstrapMethods",
676
"MethodParameters");
677
predefinedNotAllowed = notAllowed;
678
}
679
return notAllowed.contains(name);
680
}
681
682
// lazily created set the pre-defined attributes that are not allowed
683
private static volatile Set<String> predefinedNotAllowed;
684
685
686
/**
687
* The constant pool in a class file.
688
*/
689
private static class ConstantPool {
690
static final int CONSTANT_Utf8 = 1;
691
static final int CONSTANT_Integer = 3;
692
static final int CONSTANT_Float = 4;
693
static final int CONSTANT_Long = 5;
694
static final int CONSTANT_Double = 6;
695
static final int CONSTANT_Class = 7;
696
static final int CONSTANT_String = 8;
697
static final int CONSTANT_Fieldref = 9;
698
static final int CONSTANT_Methodref = 10;
699
static final int CONSTANT_InterfaceMethodref = 11;
700
static final int CONSTANT_NameAndType = 12;
701
static final int CONSTANT_MethodHandle = 15;
702
static final int CONSTANT_MethodType = 16;
703
static final int CONSTANT_InvokeDynamic = 18;
704
static final int CONSTANT_Module = 19;
705
static final int CONSTANT_Package = 20;
706
707
private static class Entry {
708
protected Entry(int tag) {
709
this.tag = tag;
710
}
711
final int tag;
712
}
713
714
private static class IndexEntry extends Entry {
715
IndexEntry(int tag, int index) {
716
super(tag);
717
this.index = index;
718
}
719
final int index;
720
}
721
722
private static class Index2Entry extends Entry {
723
Index2Entry(int tag, int index1, int index2) {
724
super(tag);
725
this.index1 = index1;
726
this.index2 = index2;
727
}
728
final int index1, index2;
729
}
730
731
private static class ValueEntry extends Entry {
732
ValueEntry(int tag, Object value) {
733
super(tag);
734
this.value = value;
735
}
736
final Object value;
737
}
738
739
final Entry[] pool;
740
741
ConstantPool(DataInput in) throws IOException {
742
int count = in.readUnsignedShort();
743
pool = new Entry[count];
744
745
for (int i = 1; i < count; i++) {
746
int tag = in.readUnsignedByte();
747
switch (tag) {
748
749
case CONSTANT_Utf8:
750
String svalue = in.readUTF();
751
pool[i] = new ValueEntry(tag, svalue);
752
break;
753
754
case CONSTANT_Class:
755
case CONSTANT_Package:
756
case CONSTANT_Module:
757
case CONSTANT_String:
758
int index = in.readUnsignedShort();
759
pool[i] = new IndexEntry(tag, index);
760
break;
761
762
case CONSTANT_Double:
763
double dvalue = in.readDouble();
764
pool[i] = new ValueEntry(tag, dvalue);
765
i++;
766
break;
767
768
case CONSTANT_Fieldref:
769
case CONSTANT_InterfaceMethodref:
770
case CONSTANT_Methodref:
771
case CONSTANT_InvokeDynamic:
772
case CONSTANT_NameAndType:
773
int index1 = in.readUnsignedShort();
774
int index2 = in.readUnsignedShort();
775
pool[i] = new Index2Entry(tag, index1, index2);
776
break;
777
778
case CONSTANT_MethodHandle:
779
int refKind = in.readUnsignedByte();
780
index = in.readUnsignedShort();
781
pool[i] = new Index2Entry(tag, refKind, index);
782
break;
783
784
case CONSTANT_MethodType:
785
index = in.readUnsignedShort();
786
pool[i] = new IndexEntry(tag, index);
787
break;
788
789
case CONSTANT_Float:
790
float fvalue = in.readFloat();
791
pool[i] = new ValueEntry(tag, fvalue);
792
break;
793
794
case CONSTANT_Integer:
795
int ivalue = in.readInt();
796
pool[i] = new ValueEntry(tag, ivalue);
797
break;
798
799
case CONSTANT_Long:
800
long lvalue = in.readLong();
801
pool[i] = new ValueEntry(tag, lvalue);
802
i++;
803
break;
804
805
default:
806
throw invalidModuleDescriptor("Bad constant pool entry: "
807
+ i);
808
}
809
}
810
}
811
812
String getClassName(int index) {
813
checkIndex(index);
814
Entry e = pool[index];
815
if (e.tag != CONSTANT_Class) {
816
throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
817
+ index);
818
}
819
String value = getUtf8(((IndexEntry) e).index);
820
checkUnqualifiedName("CONSTANT_Class", index, value);
821
return value.replace('/', '.'); // internal form -> binary name
822
}
823
824
String getPackageName(int index) {
825
checkIndex(index);
826
Entry e = pool[index];
827
if (e.tag != CONSTANT_Package) {
828
throw invalidModuleDescriptor("CONSTANT_Package expected at entry: "
829
+ index);
830
}
831
String value = getUtf8(((IndexEntry) e).index);
832
checkUnqualifiedName("CONSTANT_Package", index, value);
833
return value.replace('/', '.'); // internal form -> binary name
834
}
835
836
String getModuleName(int index) {
837
checkIndex(index);
838
Entry e = pool[index];
839
if (e.tag != CONSTANT_Module) {
840
throw invalidModuleDescriptor("CONSTANT_Module expected at entry: "
841
+ index);
842
}
843
String value = getUtf8(((IndexEntry) e).index);
844
return decodeModuleName(index, value);
845
}
846
847
String getUtf8(int index) {
848
checkIndex(index);
849
Entry e = pool[index];
850
if (e.tag != CONSTANT_Utf8) {
851
throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
852
+ index);
853
}
854
return (String) (((ValueEntry) e).value);
855
}
856
857
void checkIndex(int index) {
858
if (index < 1 || index >= pool.length)
859
throw invalidModuleDescriptor("Index into constant pool out of range");
860
}
861
862
void checkUnqualifiedName(String what, int index, String value) {
863
int len = value.length();
864
if (len == 0) {
865
throw invalidModuleDescriptor(what + " at entry " + index
866
+ " has zero length");
867
}
868
for (int i=0; i<len; i++) {
869
char c = value.charAt(i);
870
if (c == '.' || c == ';' || c == '[') {
871
throw invalidModuleDescriptor(what + " at entry " + index
872
+ " has illegal character: '"
873
+ c + "'");
874
}
875
}
876
}
877
878
/**
879
* "Decode" a module name that has been read from the constant pool.
880
*/
881
String decodeModuleName(int index, String value) {
882
int len = value.length();
883
if (len == 0) {
884
throw invalidModuleDescriptor("CONSTANT_Module at entry "
885
+ index + " is zero length");
886
}
887
int i = 0;
888
while (i < len) {
889
int cp = value.codePointAt(i);
890
if (cp == ':' || cp == '@' || cp < 0x20) {
891
throw invalidModuleDescriptor("CONSTANT_Module at entry "
892
+ index + " has illegal character: "
893
+ Character.getName(cp));
894
}
895
896
// blackslash is the escape character
897
if (cp == '\\')
898
return decodeModuleName(index, i, value);
899
900
i += Character.charCount(cp);
901
}
902
return value;
903
}
904
905
/**
906
* "Decode" a module name that has been read from the constant pool and
907
* partly checked for illegal characters (up to position {@code i}).
908
*/
909
String decodeModuleName(int index, int i, String value) {
910
StringBuilder sb = new StringBuilder();
911
912
// copy the code points that have been checked
913
int j = 0;
914
while (j < i) {
915
int cp = value.codePointAt(j);
916
sb.appendCodePoint(cp);
917
j += Character.charCount(cp);
918
}
919
920
// decode from position {@code i} to end
921
int len = value.length();
922
while (i < len) {
923
int cp = value.codePointAt(i);
924
if (cp == ':' || cp == '@' || cp < 0x20) {
925
throw invalidModuleDescriptor("CONSTANT_Module at entry "
926
+ index + " has illegal character: "
927
+ Character.getName(cp));
928
}
929
930
// blackslash is the escape character
931
if (cp == '\\') {
932
j = i + Character.charCount(cp);
933
if (j >= len) {
934
throw invalidModuleDescriptor("CONSTANT_Module at entry "
935
+ index + " has illegal "
936
+ "escape sequence");
937
}
938
int next = value.codePointAt(j);
939
if (next != '\\' && next != ':' && next != '@') {
940
throw invalidModuleDescriptor("CONSTANT_Module at entry "
941
+ index + " has illegal "
942
+ "escape sequence");
943
}
944
sb.appendCodePoint(next);
945
i += Character.charCount(next);
946
} else {
947
sb.appendCodePoint(cp);
948
}
949
950
i += Character.charCount(cp);
951
}
952
return sb.toString();
953
}
954
}
955
956
/**
957
* A DataInput implementation that reads from a ByteBuffer.
958
*/
959
private static class DataInputWrapper implements DataInput {
960
private final ByteBuffer bb;
961
962
DataInputWrapper(ByteBuffer bb) {
963
this.bb = bb;
964
}
965
966
@Override
967
public void readFully(byte b[]) throws IOException {
968
readFully(b, 0, b.length);
969
}
970
971
@Override
972
public void readFully(byte b[], int off, int len) throws IOException {
973
try {
974
bb.get(b, off, len);
975
} catch (BufferUnderflowException e) {
976
throw new EOFException(e.getMessage());
977
}
978
}
979
980
@Override
981
public int skipBytes(int n) {
982
int skip = Math.min(n, bb.remaining());
983
bb.position(bb.position() + skip);
984
return skip;
985
}
986
987
@Override
988
public boolean readBoolean() throws IOException {
989
try {
990
int ch = bb.get();
991
return (ch != 0);
992
} catch (BufferUnderflowException e) {
993
throw new EOFException(e.getMessage());
994
}
995
}
996
997
@Override
998
public byte readByte() throws IOException {
999
try {
1000
return bb.get();
1001
} catch (BufferUnderflowException e) {
1002
throw new EOFException(e.getMessage());
1003
}
1004
}
1005
1006
@Override
1007
public int readUnsignedByte() throws IOException {
1008
try {
1009
return ((int) bb.get()) & 0xff;
1010
} catch (BufferUnderflowException e) {
1011
throw new EOFException(e.getMessage());
1012
}
1013
}
1014
1015
@Override
1016
public short readShort() throws IOException {
1017
try {
1018
return bb.getShort();
1019
} catch (BufferUnderflowException e) {
1020
throw new EOFException(e.getMessage());
1021
}
1022
}
1023
1024
@Override
1025
public int readUnsignedShort() throws IOException {
1026
try {
1027
return ((int) bb.getShort()) & 0xffff;
1028
} catch (BufferUnderflowException e) {
1029
throw new EOFException(e.getMessage());
1030
}
1031
}
1032
1033
@Override
1034
public char readChar() throws IOException {
1035
try {
1036
return bb.getChar();
1037
} catch (BufferUnderflowException e) {
1038
throw new EOFException(e.getMessage());
1039
}
1040
}
1041
1042
@Override
1043
public int readInt() throws IOException {
1044
try {
1045
return bb.getInt();
1046
} catch (BufferUnderflowException e) {
1047
throw new EOFException(e.getMessage());
1048
}
1049
}
1050
1051
@Override
1052
public long readLong() throws IOException {
1053
try {
1054
return bb.getLong();
1055
} catch (BufferUnderflowException e) {
1056
throw new EOFException(e.getMessage());
1057
}
1058
}
1059
1060
@Override
1061
public float readFloat() throws IOException {
1062
try {
1063
return bb.getFloat();
1064
} catch (BufferUnderflowException e) {
1065
throw new EOFException(e.getMessage());
1066
}
1067
}
1068
1069
@Override
1070
public double readDouble() throws IOException {
1071
try {
1072
return bb.getDouble();
1073
} catch (BufferUnderflowException e) {
1074
throw new EOFException(e.getMessage());
1075
}
1076
}
1077
1078
@Override
1079
public String readLine() {
1080
throw new RuntimeException("not implemented");
1081
}
1082
1083
@Override
1084
public String readUTF() throws IOException {
1085
// ### Need to measure the performance and feasibility of using
1086
// the UTF-8 decoder instead.
1087
return DataInputStream.readUTF(this);
1088
}
1089
}
1090
1091
/**
1092
* A DataInput implementation that reads from another DataInput and counts
1093
* the number of bytes read.
1094
*/
1095
private static class CountingDataInput implements DataInput {
1096
private final DataInput delegate;
1097
private long count;
1098
1099
CountingDataInput(DataInput delegate) {
1100
this.delegate = delegate;
1101
}
1102
1103
long count() {
1104
return count;
1105
}
1106
1107
@Override
1108
public void readFully(byte b[]) throws IOException {
1109
delegate.readFully(b, 0, b.length);
1110
count += b.length;
1111
}
1112
1113
@Override
1114
public void readFully(byte b[], int off, int len) throws IOException {
1115
delegate.readFully(b, off, len);
1116
count += len;
1117
}
1118
1119
@Override
1120
public int skipBytes(int n) throws IOException {
1121
int skip = delegate.skipBytes(n);
1122
count += skip;
1123
return skip;
1124
}
1125
1126
@Override
1127
public boolean readBoolean() throws IOException {
1128
boolean b = delegate.readBoolean();
1129
count++;
1130
return b;
1131
}
1132
1133
@Override
1134
public byte readByte() throws IOException {
1135
byte b = delegate.readByte();
1136
count++;
1137
return b;
1138
}
1139
1140
@Override
1141
public int readUnsignedByte() throws IOException {
1142
int i = delegate.readUnsignedByte();
1143
count++;
1144
return i;
1145
}
1146
1147
@Override
1148
public short readShort() throws IOException {
1149
short s = delegate.readShort();
1150
count += 2;
1151
return s;
1152
}
1153
1154
@Override
1155
public int readUnsignedShort() throws IOException {
1156
int s = delegate.readUnsignedShort();
1157
count += 2;
1158
return s;
1159
}
1160
1161
@Override
1162
public char readChar() throws IOException {
1163
char c = delegate.readChar();
1164
count += 2;
1165
return c;
1166
}
1167
1168
@Override
1169
public int readInt() throws IOException {
1170
int i = delegate.readInt();
1171
count += 4;
1172
return i;
1173
}
1174
1175
@Override
1176
public long readLong() throws IOException {
1177
long l = delegate.readLong();
1178
count += 8;
1179
return l;
1180
}
1181
1182
@Override
1183
public float readFloat() throws IOException {
1184
float f = delegate.readFloat();
1185
count += 4;
1186
return f;
1187
}
1188
1189
@Override
1190
public double readDouble() throws IOException {
1191
double d = delegate.readDouble();
1192
count += 8;
1193
return d;
1194
}
1195
1196
@Override
1197
public String readLine() {
1198
throw new RuntimeException("not implemented");
1199
}
1200
1201
@Override
1202
public String readUTF() throws IOException {
1203
return DataInputStream.readUTF(this);
1204
}
1205
}
1206
1207
/**
1208
* Returns an InvalidModuleDescriptorException with the given detail
1209
* message
1210
*/
1211
private static InvalidModuleDescriptorException invalidModuleDescriptor(String msg) {
1212
return new InvalidModuleDescriptorException(msg);
1213
}
1214
1215
/**
1216
* Returns an InvalidModuleDescriptorException with a detail message to
1217
* indicate that the class file is truncated.
1218
*/
1219
private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
1220
return invalidModuleDescriptor("Truncated module-info.class");
1221
}
1222
1223
}
1224
1225