1 /* 2 * Copyright (c) 2015, 2016, 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 package jdk.tools.jlink.internal.plugins; 26 27 import java.io.ByteArrayInputStream; 28 import java.io.ByteArrayOutputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.lang.module.ModuleDescriptor; 32 import java.lang.module.ModuleDescriptor.*; 33 import java.util.ArrayList; 34 import java.util.Collection; 35 import java.util.EnumSet; 36 import java.util.HashMap; 37 import java.util.HashSet; 38 import java.util.List; 39 import java.util.Map; 40 import java.util.Set; 41 import java.util.TreeSet; 42 import java.util.function.IntSupplier; 43 44 import jdk.internal.misc.JavaLangModuleAccess; 45 import jdk.internal.misc.SharedSecrets; 46 import jdk.internal.module.Checks; 47 import jdk.internal.module.ModuleHashes; 48 import jdk.internal.module.ModuleInfo.Attributes; 49 import jdk.internal.module.ModuleInfoExtender; 50 import jdk.internal.module.ModuleResolution; 51 import jdk.internal.module.SystemModules; 52 import jdk.internal.org.objectweb.asm.ClassWriter; 53 import jdk.internal.org.objectweb.asm.MethodVisitor; 54 import jdk.internal.org.objectweb.asm.Opcodes; 55 56 import static jdk.internal.org.objectweb.asm.Opcodes.*; 57 58 import jdk.tools.jlink.plugin.PluginException; 59 import jdk.tools.jlink.plugin.ResourcePool; 60 import jdk.tools.jlink.plugin.Plugin; 61 import jdk.tools.jlink.plugin.ResourcePoolBuilder; 62 import jdk.tools.jlink.plugin.ResourcePoolEntry; 63 64 /** 65 * Jlink plugin to reconstitute module descriptors for system modules. 66 * It will extend module-info.class with Packages attribute, 67 * if not present. It also determines the number of packages of 68 * the boot layer at link time. 69 * 70 * This plugin will override jdk.internal.module.SystemModules class 71 * 72 * @see jdk.internal.module.SystemModuleFinder 73 * @see SystemModules 74 */ 75 public final class SystemModulesPlugin implements Plugin { 76 private static final JavaLangModuleAccess JLMA = 77 SharedSecrets.getJavaLangModuleAccess(); 78 79 private static final String NAME = "system-modules"; 80 private static final String DESCRIPTION = 81 PluginsResourceBundle.getDescription(NAME); 82 83 private boolean enabled; 84 public SystemModulesPlugin() { 85 this.enabled = true; 86 } 87 88 @Override 89 public String getName() { 90 return NAME; 91 } 92 93 @Override 94 public String getDescription() { 95 return DESCRIPTION; 96 } 97 98 @Override 99 public Set<State> getState() { 100 return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL) 101 : EnumSet.of(State.DISABLED); 102 } 103 104 @Override 105 public void configure(Map<String, String> config) { 106 if (config.containsKey(NAME)) { 107 enabled = false; 108 } 109 } 110 111 @Override 112 public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { 113 if (!enabled) { 114 throw new PluginException(NAME + " was set"); 115 } 116 117 SystemModulesClassGenerator generator = new SystemModulesClassGenerator(); 118 119 // generate the byte code to create ModuleDescriptors 120 // skip parsing module-info.class and skip name check 121 in.moduleView().modules().forEach(module -> { 122 123 ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow( 124 // automatic module not supported yet 125 () -> new PluginException("module-info.class not found for " + 126 module.name() + " module") 127 ); 128 129 assert module.name().equals(data.moduleName()); 130 try { 131 ModuleInfo moduleInfo = new ModuleInfo(data.contentBytes(), module.packages()); 132 generator.addModule(moduleInfo); 133 134 // link-time validation 135 moduleInfo.validateNames(); 136 // check if any exported or open package is not present 137 moduleInfo.validatePackages(); 138 139 // Packages attribute needs update 140 if (moduleInfo.shouldAddPackagesAttribute()) { 141 // replace with the overridden version 142 data = data.copyWithContent(moduleInfo.getBytes()); 143 } 144 out.add(data); 145 } catch (IOException e) { 146 throw new PluginException(e); 147 } 148 }); 149 150 // Generate the new class 151 ClassWriter cwriter = generator.getClassWriter(); 152 in.entries().forEach(data -> { 153 if (data.path().endsWith("module-info.class")) 154 return; 155 if (generator.isOverriddenClass(data.path())) { 156 byte[] bytes = cwriter.toByteArray(); 157 ResourcePoolEntry ndata = data.copyWithContent(bytes); 158 out.add(ndata); 159 } else { 160 out.add(data); 161 } 162 }); 163 164 return out.build(); 165 } 166 167 class ModuleInfo { 168 final ModuleDescriptor descriptor; 169 final ModuleHashes recordedHashes; 170 final ModuleResolution moduleResolution; 171 final Set<String> packages; 172 final ByteArrayInputStream bain; 173 174 ModuleInfo(byte[] bytes, Set<String> packages) throws IOException { 175 this.bain = new ByteArrayInputStream(bytes); 176 this.packages = packages; 177 178 Attributes attrs = jdk.internal.module.ModuleInfo.read(bain, null); 179 this.descriptor = attrs.descriptor(); 180 this.recordedHashes = attrs.recordedHashes(); 181 this.moduleResolution = attrs.moduleResolution(); 182 183 if (descriptor.isAutomatic()) { 184 throw new InternalError("linking automatic module is not supported"); 185 } 186 } 187 188 String moduleName() { 189 return descriptor.name(); 190 } 191 192 /** 193 * Validates names in ModuleDescriptor 194 */ 195 void validateNames() { 196 Checks.requireModuleName(descriptor.name()); 197 for (Requires req : descriptor.requires()) { 198 Checks.requireModuleName(req.name()); 199 } 200 for (Exports e : descriptor.exports()) { 201 Checks.requirePackageName(e.source()); 202 if (e.isQualified()) 203 e.targets().forEach(Checks::requireModuleName); 204 } 205 for (Opens opens : descriptor.opens()) { 206 Checks.requirePackageName(opens.source()); 207 if (opens.isQualified()) 208 opens.targets().forEach(Checks::requireModuleName); 209 } 210 for (Provides provides : descriptor.provides()) { 211 Checks.requireServiceTypeName(provides.service()); 212 provides.providers().forEach(Checks::requireServiceProviderName); 213 } 214 for (String service : descriptor.uses()) { 215 Checks.requireServiceTypeName(service); 216 } 217 for (String pn : descriptor.packages()) { 218 Checks.requirePackageName(pn); 219 } 220 } 221 222 223 /** 224 * Validates if exported and open packages are present 225 */ 226 void validatePackages() { 227 Set<String> nonExistPackages = new TreeSet<>(); 228 descriptor.exports().stream() 229 .map(Exports::source) 230 .filter(pn -> !packages.contains(pn)) 231 .forEach(nonExistPackages::add); 232 233 descriptor.opens().stream() 234 .map(Opens::source) 235 .filter(pn -> !packages.contains(pn)) 236 .forEach(nonExistPackages::add); 237 238 if (!nonExistPackages.isEmpty()) { 239 throw new PluginException("Packages that are exported or open in " 240 + descriptor.name() + " are not present: " + nonExistPackages); 241 } 242 } 243 244 /** 245 * Returns true if the PackagesAttribute should be written 246 */ 247 boolean shouldAddPackagesAttribute() { 248 return descriptor.packages().isEmpty() && packages.size() > 0; 249 } 250 251 /** 252 * Returns the bytes for the module-info.class with PackagesAttribute 253 * if it contains at least one package 254 */ 255 byte[] getBytes() throws IOException { 256 bain.reset(); 257 258 // add Packages attribute if not exist 259 if (shouldAddPackagesAttribute()) { 260 return new ModuleInfoRewriter(bain, packages).getBytes(); 261 } else { 262 return bain.readAllBytes(); 263 } 264 } 265 266 class ModuleInfoRewriter extends ByteArrayOutputStream { 267 final ModuleInfoExtender extender; 268 ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException { 269 this.extender = ModuleInfoExtender.newExtender(in); 270 // Add Packages attribute 271 if (packages.size() > 0) { 272 this.extender.packages(packages); 273 } 274 this.extender.write(this); 275 } 276 277 byte[] getBytes() { 278 return buf; 279 } 280 } 281 } 282 283 /** 284 * ClassWriter of a new jdk.internal.module.SystemModules class 285 * to reconstitute ModuleDescriptor of the system modules. 286 */ 287 static class SystemModulesClassGenerator { 288 private static final String CLASSNAME = 289 "jdk/internal/module/SystemModules"; 290 private static final String MODULE_DESCRIPTOR_BUILDER = 291 "jdk/internal/module/Builder"; 292 private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE = 293 "[Ljava/lang/module/ModuleDescriptor;"; 294 private static final String REQUIRES_MODIFIER_CLASSNAME = 295 "java/lang/module/ModuleDescriptor$Requires$Modifier"; 296 private static final String EXPORTS_MODIFIER_CLASSNAME = 297 "java/lang/module/ModuleDescriptor$Exports$Modifier"; 298 private static final String OPENS_MODIFIER_CLASSNAME = 299 "java/lang/module/ModuleDescriptor$Opens$Modifier"; 300 private static final String MODULE_HASHES_ARRAY_SIGNATURE = 301 "[Ljdk/internal/module/ModuleHashes;"; 302 private static final String MODULE_RESOLUTION_CLASSNAME = 303 "jdk/internal/module/ModuleResolution"; 304 private static final String MODULE_RESOLUTIONS_ARRAY_SIGNATURE = 305 "[Ljdk/internal/module/ModuleResolution;"; 306 307 // static variables in SystemModules class 308 private static final String MODULE_NAMES = "MODULE_NAMES"; 309 private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER"; 310 311 private static final int MAX_LOCAL_VARS = 256; 312 313 private final int BUILDER_VAR = 0; 314 private final int MD_VAR = 1; // variable for ModuleDescriptor 315 private final int MH_VAR = 1; // variable for ModuleHashes 316 private int nextLocalVar = 2; // index to next local variable 317 318 private final ClassWriter cw; 319 320 // Method visitor for generating the SystemModules::modules() method 321 private MethodVisitor mv; 322 323 // list of all ModuleDescriptorBuilders, invoked in turn when building. 324 private final List<ModuleInfo> moduleInfos = new ArrayList<>(); 325 326 // A builder to create one single Set instance for a given set of 327 // names or modifiers to reduce the footprint 328 // e.g. target modules of qualified exports 329 private final DedupSetBuilder dedupSetBuilder 330 = new DedupSetBuilder(this::getNextLocalVar); 331 332 public SystemModulesClassGenerator() { 333 this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + 334 ClassWriter.COMPUTE_FRAMES); 335 } 336 337 private int getNextLocalVar() { 338 return nextLocalVar++; 339 } 340 341 /* 342 * static initializer initializing the static fields 343 * 344 * static Map<String, ModuleDescriptor> map = new HashMap<>(); 345 */ 346 private void clinit(int numModules, int numPackages, 347 boolean hasSplitPackages) { 348 cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME, 349 null, "java/lang/Object", null); 350 351 // public static String[] MODULE_NAMES = new String[] {....}; 352 cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES, 353 "[Ljava/lang/String;", null, null) 354 .visitEnd(); 355 356 // public static int PACKAGES_IN_BOOT_LAYER; 357 cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT, 358 "I", null, numPackages) 359 .visitEnd(); 360 361 MethodVisitor clinit = 362 cw.visitMethod(ACC_STATIC, "<clinit>", "()V", 363 null, null); 364 clinit.visitCode(); 365 366 // create the MODULE_NAMES array 367 pushInt(clinit, numModules); 368 clinit.visitTypeInsn(ANEWARRAY, "java/lang/String"); 369 370 int index = 0; 371 for (ModuleInfo minfo : moduleInfos) { 372 clinit.visitInsn(DUP); // arrayref 373 pushInt(clinit, index++); 374 clinit.visitLdcInsn(minfo.moduleName()); // value 375 clinit.visitInsn(AASTORE); 376 } 377 378 clinit.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES, 379 "[Ljava/lang/String;"); 380 381 clinit.visitInsn(RETURN); 382 clinit.visitMaxs(0, 0); 383 clinit.visitEnd(); 384 385 // public static boolean hasSplitPackages(); 386 MethodVisitor split = 387 cw.visitMethod(ACC_PUBLIC+ACC_STATIC, "hasSplitPackages", 388 "()Z", null, null); 389 split.visitCode(); 390 split.visitInsn(hasSplitPackages ? ICONST_1 : ICONST_0); 391 split.visitInsn(IRETURN); 392 split.visitMaxs(0, 0); 393 split.visitEnd(); 394 395 } 396 397 /* 398 * Adds the given ModuleDescriptor to the system module list, and 399 * prepares mapping from various Sets to SetBuilders to emit an 400 * optimized number of sets during build. 401 */ 402 public void addModule(ModuleInfo moduleInfo) { 403 ModuleDescriptor md = moduleInfo.descriptor; 404 moduleInfos.add(moduleInfo); 405 406 // exports 407 for (Exports e : md.exports()) { 408 dedupSetBuilder.stringSet(e.targets()); 409 dedupSetBuilder.exportsModifiers(e.modifiers()); 410 } 411 412 // opens 413 for (Opens opens : md.opens()) { 414 dedupSetBuilder.stringSet(opens.targets()); 415 dedupSetBuilder.opensModifiers(opens.modifiers()); 416 } 417 418 // requires 419 for (Requires r : md.requires()) { 420 dedupSetBuilder.requiresModifiers(r.modifiers()); 421 } 422 423 // uses 424 dedupSetBuilder.stringSet(md.uses()); 425 } 426 427 /* 428 * Generate bytecode for SystemModules 429 */ 430 public ClassWriter getClassWriter() { 431 int numModules = moduleInfos.size(); 432 Set<String> allPackages = new HashSet<>(); 433 int packageCount = 0; 434 for (ModuleInfo minfo : moduleInfos) { 435 allPackages.addAll(minfo.packages); 436 packageCount += minfo.packages.size(); 437 } 438 439 int numPackages = allPackages.size(); 440 boolean hasSplitPackages = (numPackages < packageCount); 441 clinit(numModules, numPackages, hasSplitPackages); 442 443 // generate SystemModules::descriptors 444 genDescriptorsMethod(); 445 // generate SystemModules::hashes 446 genHashesMethod(); 447 // generate SystemModules::moduleResolutions 448 genModuleResolutionsMethod(); 449 450 return cw; 451 } 452 453 /* 454 * Generate bytecode for SystemModules::descriptors method 455 */ 456 private void genDescriptorsMethod() { 457 this.mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, 458 "descriptors", 459 "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE, 460 "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE, 461 null); 462 mv.visitCode(); 463 pushInt(mv, moduleInfos.size()); 464 mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor"); 465 mv.visitVarInsn(ASTORE, MD_VAR); 466 467 for (int index = 0; index < moduleInfos.size(); index++) { 468 ModuleInfo minfo = moduleInfos.get(index); 469 new ModuleDescriptorBuilder(minfo.descriptor, 470 minfo.packages, 471 index).build(); 472 } 473 mv.visitVarInsn(ALOAD, MD_VAR); 474 mv.visitInsn(ARETURN); 475 mv.visitMaxs(0, 0); 476 mv.visitEnd(); 477 478 } 479 480 /* 481 * Generate bytecode for SystemModules::hashes method 482 */ 483 private void genHashesMethod() { 484 MethodVisitor hmv = 485 cw.visitMethod(ACC_PUBLIC + ACC_STATIC, 486 "hashes", 487 "()" + MODULE_HASHES_ARRAY_SIGNATURE, 488 "()" + MODULE_HASHES_ARRAY_SIGNATURE, 489 null); 490 hmv.visitCode(); 491 pushInt(hmv, moduleInfos.size()); 492 hmv.visitTypeInsn(ANEWARRAY, "jdk/internal/module/ModuleHashes"); 493 hmv.visitVarInsn(ASTORE, MH_VAR); 494 495 for (int index = 0; index < moduleInfos.size(); index++) { 496 ModuleInfo minfo = moduleInfos.get(index); 497 if (minfo.recordedHashes != null) { 498 new ModuleHashesBuilder(minfo.recordedHashes, 499 index, 500 hmv).build(); 501 } 502 } 503 504 hmv.visitVarInsn(ALOAD, MH_VAR); 505 hmv.visitInsn(ARETURN); 506 hmv.visitMaxs(0, 0); 507 hmv.visitEnd(); 508 509 } 510 511 /* 512 * Generate bytecode for SystemModules::methodResoultions method 513 */ 514 private void genModuleResolutionsMethod() { 515 MethodVisitor mresmv = 516 cw.visitMethod(ACC_PUBLIC+ACC_STATIC, 517 "moduleResolutions", 518 "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE, 519 "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE, 520 null); 521 mresmv.visitCode(); 522 pushInt(mresmv, moduleInfos.size()); 523 mresmv.visitTypeInsn(ANEWARRAY, MODULE_RESOLUTION_CLASSNAME); 524 mresmv.visitVarInsn(ASTORE, 0); 525 526 for (int index=0; index < moduleInfos.size(); index++) { 527 ModuleInfo minfo = moduleInfos.get(index); 528 if (minfo.moduleResolution != null) { 529 mresmv.visitVarInsn(ALOAD, 0); 530 pushInt(mresmv, index); 531 mresmv.visitTypeInsn(NEW, MODULE_RESOLUTION_CLASSNAME); 532 mresmv.visitInsn(DUP); 533 mresmv.visitLdcInsn(minfo.moduleResolution.value()); 534 mresmv.visitMethodInsn(INVOKESPECIAL, 535 MODULE_RESOLUTION_CLASSNAME, 536 "<init>", 537 "(I)V", false); 538 mresmv.visitInsn(AASTORE); 539 } 540 } 541 mresmv.visitVarInsn(ALOAD, 0); 542 mresmv.visitInsn(ARETURN); 543 mresmv.visitMaxs(0, 0); 544 mresmv.visitEnd(); 545 } 546 547 public boolean isOverriddenClass(String path) { 548 return path.equals("/java.base/" + CLASSNAME + ".class"); 549 } 550 551 void pushInt(MethodVisitor mv, int num) { 552 if (num <= 5) { 553 mv.visitInsn(ICONST_0 + num); 554 } else if (num < Byte.MAX_VALUE) { 555 mv.visitIntInsn(BIPUSH, num); 556 } else if (num < Short.MAX_VALUE) { 557 mv.visitIntInsn(SIPUSH, num); 558 } else { 559 throw new IllegalArgumentException("exceed limit: " + num); 560 } 561 } 562 563 class ModuleDescriptorBuilder { 564 static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;"; 565 static final String EXPORTS_TYPE = 566 "Ljava/lang/module/ModuleDescriptor$Exports;"; 567 static final String OPENS_TYPE = 568 "Ljava/lang/module/ModuleDescriptor$Opens;"; 569 static final String PROVIDES_TYPE = 570 "Ljava/lang/module/ModuleDescriptor$Provides;"; 571 static final String REQUIRES_TYPE = 572 "Ljava/lang/module/ModuleDescriptor$Requires;"; 573 574 // method signature for static Builder::newExports, newOpens, 575 // newProvides, newRequires methods 576 static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG = 577 "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)" 578 + EXPORTS_TYPE; 579 static final String EXPORTS_MODIFIER_SET_STRING_SIG = 580 "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE; 581 static final String OPENS_MODIFIER_SET_STRING_SET_SIG = 582 "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)" 583 + OPENS_TYPE; 584 static final String OPENS_MODIFIER_SET_STRING_SIG = 585 "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE; 586 static final String PROVIDES_STRING_LIST_SIG = 587 "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE; 588 static final String REQUIRES_SET_STRING_SIG = 589 "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE; 590 static final String REQUIRES_SET_STRING_STRING_SIG = 591 "(Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;)" + REQUIRES_TYPE; 592 593 // method signature for Builder instance methods that 594 // return this Builder instance 595 static final String EXPORTS_ARRAY_SIG = 596 "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE; 597 static final String OPENS_ARRAY_SIG = 598 "([" + OPENS_TYPE + ")" + BUILDER_TYPE; 599 static final String PROVIDES_ARRAY_SIG = 600 "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE; 601 static final String REQUIRES_ARRAY_SIG = 602 "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE; 603 static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE; 604 static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE; 605 static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE; 606 607 final ModuleDescriptor md; 608 final Set<String> packages; 609 final int index; 610 ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages, int index) { 611 if (md.isAutomatic()) { 612 throw new InternalError("linking automatic module is not supported"); 613 } 614 this.md = md; 615 this.packages = packages; 616 this.index = index; 617 } 618 619 void build() { 620 // new jdk.internal.module.Builder 621 newBuilder(); 622 623 // requires 624 requires(md.requires()); 625 626 // exports 627 exports(md.exports()); 628 629 // opens 630 opens(md.opens()); 631 632 // uses 633 uses(md.uses()); 634 635 // provides 636 provides(md.provides()); 637 638 // all packages 639 packages(packages); 640 641 // version 642 md.version().ifPresent(this::version); 643 644 // main class 645 md.mainClass().ifPresent(this::mainClass); 646 647 putModuleDescriptor(); 648 } 649 650 void newBuilder() { 651 mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER); 652 mv.visitInsn(DUP); 653 mv.visitLdcInsn(md.name()); 654 mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER, 655 "<init>", "(Ljava/lang/String;)V", false); 656 mv.visitVarInsn(ASTORE, BUILDER_VAR); 657 mv.visitVarInsn(ALOAD, BUILDER_VAR); 658 659 if (md.isOpen()) { 660 setModuleBit("open", true); 661 } 662 if (md.isSynthetic()) { 663 setModuleBit("synthetic", true); 664 } 665 } 666 667 /* 668 * Invoke Builder.<methodName>(boolean value) 669 */ 670 void setModuleBit(String methodName, boolean value) { 671 mv.visitVarInsn(ALOAD, BUILDER_VAR); 672 if (value) { 673 mv.visitInsn(ICONST_1); 674 } else { 675 mv.visitInsn(ICONST_0); 676 } 677 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 678 methodName, BOOLEAN_SIG, false); 679 mv.visitInsn(POP); 680 } 681 682 /* 683 * Put ModuleDescriptor into the modules array 684 */ 685 void putModuleDescriptor() { 686 mv.visitVarInsn(ALOAD, MD_VAR); 687 pushInt(mv, index); 688 mv.visitVarInsn(ALOAD, BUILDER_VAR); 689 mv.visitLdcInsn(md.hashCode()); 690 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 691 "build", "(I)Ljava/lang/module/ModuleDescriptor;", 692 false); 693 mv.visitInsn(AASTORE); 694 } 695 696 /* 697 * Call Builder::newRequires to create Requires instances and 698 * then pass it to the builder by calling: 699 * Builder.requires(Requires[]) 700 * 701 */ 702 void requires(Set<Requires> requires) { 703 mv.visitVarInsn(ALOAD, BUILDER_VAR); 704 pushInt(mv, requires.size()); 705 mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires"); 706 int arrayIndex = 0; 707 for (Requires require : requires) { 708 String compiledVersion = null; 709 if (require.compiledVersion().isPresent()) { 710 compiledVersion = require.compiledVersion().get().toString(); 711 } 712 713 mv.visitInsn(DUP); // arrayref 714 pushInt(mv, arrayIndex++); 715 newRequires(require.modifiers(), require.name(), compiledVersion); 716 mv.visitInsn(AASTORE); 717 } 718 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 719 "requires", REQUIRES_ARRAY_SIG, false); 720 } 721 722 /* 723 * Invoke Builder.newRequires(Set<Modifier> mods, String mn, String compiledVersion) 724 * 725 * Set<Modifier> mods = ... 726 * Builder.newRequires(mods, mn, compiledVersion); 727 */ 728 void newRequires(Set<Requires.Modifier> mods, String name, String compiledVersion) { 729 int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods); 730 mv.visitVarInsn(ALOAD, varIndex); 731 mv.visitLdcInsn(name); 732 if (compiledVersion != null) { 733 mv.visitLdcInsn(compiledVersion); 734 mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, 735 "newRequires", REQUIRES_SET_STRING_STRING_SIG, false); 736 } else { 737 mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, 738 "newRequires", REQUIRES_SET_STRING_SIG, false); 739 } 740 } 741 742 /* 743 * Call Builder::newExports to create Exports instances and 744 * then pass it to the builder by calling: 745 * Builder.exports(Exports[]) 746 * 747 */ 748 void exports(Set<Exports> exports) { 749 mv.visitVarInsn(ALOAD, BUILDER_VAR); 750 pushInt(mv, exports.size()); 751 mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports"); 752 int arrayIndex = 0; 753 for (Exports export : exports) { 754 mv.visitInsn(DUP); // arrayref 755 pushInt(mv, arrayIndex++); 756 newExports(export.modifiers(), export.source(), export.targets()); 757 mv.visitInsn(AASTORE); 758 } 759 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 760 "exports", EXPORTS_ARRAY_SIG, false); 761 } 762 763 /* 764 * Invoke 765 * Builder.newExports(Set<Exports.Modifier> ms, String pn, 766 * Set<String> targets) 767 * or 768 * Builder.newExports(Set<Exports.Modifier> ms, String pn) 769 * 770 * Set<String> targets = new HashSet<>(); 771 * targets.add(t); 772 * : 773 * : 774 * 775 * Set<Modifier> mods = ... 776 * Builder.newExports(mods, pn, targets); 777 */ 778 void newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets) { 779 int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms); 780 if (!targets.isEmpty()) { 781 int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets); 782 mv.visitVarInsn(ALOAD, modifiersSetIndex); 783 mv.visitLdcInsn(pn); 784 mv.visitVarInsn(ALOAD, stringSetIndex); 785 mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, 786 "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false); 787 } else { 788 mv.visitVarInsn(ALOAD, modifiersSetIndex); 789 mv.visitLdcInsn(pn); 790 mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, 791 "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false); 792 } 793 } 794 795 796 /** 797 * Call Builder::newOpens to create Opens instances and 798 * then pass it to the builder by calling: 799 * Builder.opens(Opens[]) 800 */ 801 void opens(Set<Opens> opens) { 802 mv.visitVarInsn(ALOAD, BUILDER_VAR); 803 pushInt(mv, opens.size()); 804 mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens"); 805 int arrayIndex = 0; 806 for (Opens open : opens) { 807 mv.visitInsn(DUP); // arrayref 808 pushInt(mv, arrayIndex++); 809 newOpens(open.modifiers(), open.source(), open.targets()); 810 mv.visitInsn(AASTORE); 811 } 812 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 813 "opens", OPENS_ARRAY_SIG, false); 814 } 815 816 /* 817 * Invoke 818 * Builder.newOpens(Set<Opens.Modifier> ms, String pn, 819 * Set<String> targets) 820 * or 821 * Builder.newOpens(Set<Opens.Modifier> ms, String pn) 822 * 823 * Set<String> targets = new HashSet<>(); 824 * targets.add(t); 825 * : 826 * : 827 * 828 * Set<Modifier> mods = ... 829 * Builder.newOpens(mods, pn, targets); 830 */ 831 void newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets) { 832 int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms); 833 if (!targets.isEmpty()) { 834 int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets); 835 mv.visitVarInsn(ALOAD, modifiersSetIndex); 836 mv.visitLdcInsn(pn); 837 mv.visitVarInsn(ALOAD, stringSetIndex); 838 mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, 839 "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false); 840 } else { 841 mv.visitVarInsn(ALOAD, modifiersSetIndex); 842 mv.visitLdcInsn(pn); 843 mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, 844 "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false); 845 } 846 } 847 848 /* 849 * Invoke Builder.uses(Set<String> uses) 850 */ 851 void uses(Set<String> uses) { 852 int varIndex = dedupSetBuilder.indexOfStringSet(uses); 853 mv.visitVarInsn(ALOAD, BUILDER_VAR); 854 mv.visitVarInsn(ALOAD, varIndex); 855 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 856 "uses", SET_SIG, false); 857 mv.visitInsn(POP); 858 } 859 860 /* 861 * Call Builder::newProvides to create Provides instances and 862 * then pass it to the builder by calling: 863 * Builder.provides(Provides[] provides) 864 * 865 */ 866 void provides(Collection<Provides> provides) { 867 mv.visitVarInsn(ALOAD, BUILDER_VAR); 868 pushInt(mv, provides.size()); 869 mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides"); 870 int arrayIndex = 0; 871 for (Provides provide : provides) { 872 mv.visitInsn(DUP); // arrayref 873 pushInt(mv, arrayIndex++); 874 newProvides(provide.service(), provide.providers()); 875 mv.visitInsn(AASTORE); 876 } 877 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 878 "provides", PROVIDES_ARRAY_SIG, false); 879 } 880 881 /* 882 * Invoke Builder.newProvides(String service, Set<String> providers) 883 * 884 * Set<String> providers = new HashSet<>(); 885 * providers.add(impl); 886 * : 887 * : 888 * Builder.newProvides(service, providers); 889 */ 890 void newProvides(String service, List<String> providers) { 891 mv.visitLdcInsn(service); 892 pushInt(mv, providers.size()); 893 mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); 894 int arrayIndex = 0; 895 for (String provider : providers) { 896 mv.visitInsn(DUP); // arrayref 897 pushInt(mv, arrayIndex++); 898 mv.visitLdcInsn(provider); 899 mv.visitInsn(AASTORE); 900 } 901 mv.visitMethodInsn(INVOKESTATIC, "java/util/List", 902 "of", "([Ljava/lang/Object;)Ljava/util/List;", true); 903 mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, 904 "newProvides", PROVIDES_STRING_LIST_SIG, false); 905 } 906 907 /* 908 * Invoke Builder.packages(String pn) 909 */ 910 void packages(Set<String> packages) { 911 int varIndex = dedupSetBuilder.newStringSet(packages); 912 mv.visitVarInsn(ALOAD, BUILDER_VAR); 913 mv.visitVarInsn(ALOAD, varIndex); 914 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 915 "packages", SET_SIG, false); 916 mv.visitInsn(POP); 917 } 918 919 /* 920 * Invoke Builder.mainClass(String cn) 921 */ 922 void mainClass(String cn) { 923 mv.visitVarInsn(ALOAD, BUILDER_VAR); 924 mv.visitLdcInsn(cn); 925 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 926 "mainClass", STRING_SIG, false); 927 mv.visitInsn(POP); 928 } 929 930 /* 931 * Invoke Builder.version(Version v); 932 */ 933 void version(Version v) { 934 mv.visitVarInsn(ALOAD, BUILDER_VAR); 935 mv.visitLdcInsn(v.toString()); 936 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, 937 "version", STRING_SIG, false); 938 mv.visitInsn(POP); 939 } 940 } 941 942 class ModuleHashesBuilder { 943 private static final String MODULE_HASHES_BUILDER = 944 "jdk/internal/module/ModuleHashes$Builder"; 945 private static final String MODULE_HASHES_BUILDER_TYPE = 946 "L" + MODULE_HASHES_BUILDER + ";"; 947 static final String STRING_BYTE_ARRAY_SIG = 948 "(Ljava/lang/String;[B)" + MODULE_HASHES_BUILDER_TYPE; 949 950 final ModuleHashes recordedHashes; 951 final MethodVisitor hmv; 952 final int index; 953 954 ModuleHashesBuilder(ModuleHashes hashes, int index, MethodVisitor hmv) { 955 this.recordedHashes = hashes; 956 this.hmv = hmv; 957 this.index = index; 958 } 959 960 /** 961 * Build ModuleHashes 962 */ 963 void build() { 964 if (recordedHashes == null) 965 return; 966 967 // new jdk.internal.module.ModuleHashes.Builder 968 newModuleHashesBuilder(); 969 970 // Invoke ModuleHashes.Builder::hashForModule 971 recordedHashes 972 .names() 973 .forEach(mn -> hashForModule(mn, recordedHashes.hashFor(mn))); 974 975 // Put ModuleHashes into the hashes array 976 pushModuleHashes(); 977 } 978 979 980 /* 981 * Create ModuleHashes.Builder instance 982 */ 983 void newModuleHashesBuilder() { 984 hmv.visitTypeInsn(NEW, MODULE_HASHES_BUILDER); 985 hmv.visitInsn(DUP); 986 hmv.visitLdcInsn(recordedHashes.algorithm()); 987 pushInt(hmv, ((4 * recordedHashes.names().size()) / 3) + 1); 988 hmv.visitMethodInsn(INVOKESPECIAL, MODULE_HASHES_BUILDER, 989 "<init>", "(Ljava/lang/String;I)V", false); 990 hmv.visitVarInsn(ASTORE, BUILDER_VAR); 991 hmv.visitVarInsn(ALOAD, BUILDER_VAR); 992 } 993 994 995 /* 996 * Invoke ModuleHashes.Builder::build and put the returned 997 * ModuleHashes to the hashes array 998 */ 999 void pushModuleHashes() { 1000 hmv.visitVarInsn(ALOAD, MH_VAR); 1001 pushInt(hmv, index); 1002 hmv.visitVarInsn(ALOAD, BUILDER_VAR); 1003 hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER, 1004 "build", "()Ljdk/internal/module/ModuleHashes;", 1005 false); 1006 hmv.visitInsn(AASTORE); 1007 } 1008 1009 /* 1010 * Invoke ModuleHashes.Builder.hashForModule(String name, byte[] hash); 1011 */ 1012 void hashForModule(String name, byte[] hash) { 1013 hmv.visitVarInsn(ALOAD, BUILDER_VAR); 1014 hmv.visitLdcInsn(name); 1015 1016 pushInt(hmv, hash.length); 1017 hmv.visitIntInsn(NEWARRAY, T_BYTE); 1018 for (int i = 0; i < hash.length; i++) { 1019 hmv.visitInsn(DUP); // arrayref 1020 pushInt(hmv, i); 1021 hmv.visitIntInsn(BIPUSH, hash[i]); 1022 hmv.visitInsn(BASTORE); 1023 } 1024 1025 hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER, 1026 "hashForModule", STRING_BYTE_ARRAY_SIG, false); 1027 hmv.visitInsn(POP); 1028 } 1029 } 1030 1031 /* 1032 * Wraps set creation, ensuring identical sets are properly deduplicated. 1033 */ 1034 class DedupSetBuilder { 1035 // map Set<String> to a specialized builder to allow them to be 1036 // deduplicated as they are requested 1037 final Map<Set<String>, SetBuilder<String>> stringSets = new HashMap<>(); 1038 1039 // map Set<Requires.Modifier> to a specialized builder to allow them to be 1040 // deduplicated as they are requested 1041 final Map<Set<Requires.Modifier>, EnumSetBuilder<Requires.Modifier>> 1042 requiresModifiersSets = new HashMap<>(); 1043 1044 // map Set<Exports.Modifier> to a specialized builder to allow them to be 1045 // deduplicated as they are requested 1046 final Map<Set<Exports.Modifier>, EnumSetBuilder<Exports.Modifier>> 1047 exportsModifiersSets = new HashMap<>(); 1048 1049 // map Set<Opens.Modifier> to a specialized builder to allow them to be 1050 // deduplicated as they are requested 1051 final Map<Set<Opens.Modifier>, EnumSetBuilder<Opens.Modifier>> 1052 opensModifiersSets = new HashMap<>(); 1053 1054 private final int stringSetVar; 1055 private final int enumSetVar; 1056 private final IntSupplier localVarSupplier; 1057 1058 DedupSetBuilder(IntSupplier localVarSupplier) { 1059 this.stringSetVar = localVarSupplier.getAsInt(); 1060 this.enumSetVar = localVarSupplier.getAsInt(); 1061 this.localVarSupplier = localVarSupplier; 1062 } 1063 1064 /* 1065 * Add the given set of strings to this builder. 1066 */ 1067 void stringSet(Set<String> strings) { 1068 stringSets.computeIfAbsent(strings, 1069 s -> new SetBuilder<>(s, stringSetVar, localVarSupplier) 1070 ).increment(); 1071 } 1072 1073 /* 1074 * Add the given set of Exports.Modifiers 1075 */ 1076 void exportsModifiers(Set<Exports.Modifier> mods) { 1077 exportsModifiersSets.computeIfAbsent(mods, s -> 1078 new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME, 1079 enumSetVar, localVarSupplier) 1080 ).increment(); 1081 } 1082 1083 /* 1084 * Add the given set of Opens.Modifiers 1085 */ 1086 void opensModifiers(Set<Opens.Modifier> mods) { 1087 opensModifiersSets.computeIfAbsent(mods, s -> 1088 new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME, 1089 enumSetVar, localVarSupplier) 1090 ).increment(); 1091 } 1092 1093 /* 1094 * Add the given set of Requires.Modifiers 1095 */ 1096 void requiresModifiers(Set<Requires.Modifier> mods) { 1097 requiresModifiersSets.computeIfAbsent(mods, s -> 1098 new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME, 1099 enumSetVar, localVarSupplier) 1100 ).increment(); 1101 } 1102 1103 /* 1104 * Retrieve the index to the given set of Strings. Emit code to 1105 * generate it when SetBuilder::build is called. 1106 */ 1107 int indexOfStringSet(Set<String> names) { 1108 return stringSets.get(names).build(); 1109 } 1110 1111 /* 1112 * Retrieve the index to the given set of Exports.Modifier. 1113 * Emit code to generate it when EnumSetBuilder::build is called. 1114 */ 1115 int indexOfExportsModifiers(Set<Exports.Modifier> mods) { 1116 return exportsModifiersSets.get(mods).build(); 1117 } 1118 1119 /** 1120 * Retrieve the index to the given set of Opens.Modifier. 1121 * Emit code to generate it when EnumSetBuilder::build is called. 1122 */ 1123 int indexOfOpensModifiers(Set<Opens.Modifier> mods) { 1124 return opensModifiersSets.get(mods).build(); 1125 } 1126 1127 1128 /* 1129 * Retrieve the index to the given set of Requires.Modifier. 1130 * Emit code to generate it when EnumSetBuilder::build is called. 1131 */ 1132 int indexOfRequiresModifiers(Set<Requires.Modifier> mods) { 1133 return requiresModifiersSets.get(mods).build(); 1134 } 1135 1136 /* 1137 * Build a new string set without any attempt to deduplicate it. 1138 */ 1139 int newStringSet(Set<String> names) { 1140 int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build(); 1141 assert index == stringSetVar; 1142 return index; 1143 } 1144 } 1145 1146 /* 1147 * SetBuilder generates bytecode to create one single instance of Set 1148 * for a given set of elements and assign to a local variable slot. 1149 * When there is only one single reference to a Set<T>, 1150 * it will reuse defaultVarIndex. For a Set with multiple references, 1151 * it will use a new local variable retrieved from the nextLocalVar 1152 */ 1153 class SetBuilder<T> { 1154 private final Set<T> elements; 1155 private final int defaultVarIndex; 1156 private final IntSupplier nextLocalVar; 1157 private int refCount; 1158 private int localVarIndex; 1159 1160 SetBuilder(Set<T> elements, 1161 int defaultVarIndex, 1162 IntSupplier nextLocalVar) { 1163 this.elements = elements; 1164 this.defaultVarIndex = defaultVarIndex; 1165 this.nextLocalVar = nextLocalVar; 1166 } 1167 1168 /* 1169 * Increments the number of references to this particular set. 1170 */ 1171 final void increment() { 1172 refCount++; 1173 } 1174 1175 /** 1176 * Generate the appropriate instructions to load an object reference 1177 * to the element onto the stack. 1178 */ 1179 void visitElement(T element, MethodVisitor mv) { 1180 mv.visitLdcInsn(element); 1181 } 1182 1183 /* 1184 * Build bytecode for the Set represented by this builder, 1185 * or get the local variable index of a previously generated set 1186 * (in the local scope). 1187 * 1188 * @return local variable index of the generated set. 1189 */ 1190 final int build() { 1191 int index = localVarIndex; 1192 if (localVarIndex == 0) { 1193 // if non-empty and more than one set reference this builder, 1194 // emit to a unique local 1195 index = refCount <= 1 ? defaultVarIndex 1196 : nextLocalVar.getAsInt(); 1197 if (index < MAX_LOCAL_VARS) { 1198 localVarIndex = index; 1199 } else { 1200 // overflow: disable optimization by using localVarIndex = 0 1201 index = defaultVarIndex; 1202 } 1203 1204 generateSetOf(index); 1205 } 1206 return index; 1207 } 1208 1209 private void generateSetOf(int index) { 1210 if (elements.size() <= 10) { 1211 // call Set.of(e1, e2, ...) 1212 StringBuilder sb = new StringBuilder("("); 1213 for (T t : elements) { 1214 sb.append("Ljava/lang/Object;"); 1215 visitElement(t, mv); 1216 } 1217 sb.append(")Ljava/util/Set;"); 1218 mv.visitMethodInsn(INVOKESTATIC, "java/util/Set", 1219 "of", sb.toString(), true); 1220 } else { 1221 // call Set.of(E... elements) 1222 pushInt(mv, elements.size()); 1223 mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); 1224 int arrayIndex = 0; 1225 for (T t : elements) { 1226 mv.visitInsn(DUP); // arrayref 1227 pushInt(mv, arrayIndex); 1228 visitElement(t, mv); // value 1229 mv.visitInsn(AASTORE); 1230 arrayIndex++; 1231 } 1232 mv.visitMethodInsn(INVOKESTATIC, "java/util/Set", 1233 "of", "([Ljava/lang/Object;)Ljava/util/Set;", true); 1234 } 1235 mv.visitVarInsn(ASTORE, index); 1236 } 1237 } 1238 1239 /* 1240 * Generates bytecode to create one single instance of EnumSet 1241 * for a given set of modifiers and assign to a local variable slot. 1242 */ 1243 class EnumSetBuilder<T> extends SetBuilder<T> { 1244 1245 private final String className; 1246 1247 EnumSetBuilder(Set<T> modifiers, String className, 1248 int defaultVarIndex, 1249 IntSupplier nextLocalVar) { 1250 super(modifiers, defaultVarIndex, nextLocalVar); 1251 this.className = className; 1252 } 1253 1254 /** 1255 * Loads an Enum field. 1256 */ 1257 void visitElement(T t, MethodVisitor mv) { 1258 mv.visitFieldInsn(GETSTATIC, className, t.toString(), 1259 "L" + className + ";"); 1260 } 1261 } 1262 } 1263 }