1 /* 2 * Copyright (c) 2010, 2013, 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.nashorn.internal.codegen; 27 28 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; 29 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; 30 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 31 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 32 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; 33 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; 34 import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEINTERFACE; 35 import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESPECIAL; 36 import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; 37 import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKEVIRTUAL; 38 import static jdk.internal.org.objectweb.asm.Opcodes.H_NEWINVOKESPECIAL; 39 import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; 40 import static jdk.nashorn.internal.codegen.CompilerConstants.CLINIT; 41 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; 42 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_ARRAY_PREFIX; 43 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_ARRAY_SUFFIX; 44 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; 45 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; 46 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT; 47 import static jdk.nashorn.internal.codegen.CompilerConstants.SET_MAP; 48 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; 49 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; 50 import static jdk.nashorn.internal.codegen.CompilerConstants.className; 51 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; 52 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; 53 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; 54 55 import java.io.ByteArrayOutputStream; 56 import java.io.PrintWriter; 57 import java.security.AccessController; 58 import java.security.PrivilegedAction; 59 import java.util.Collections; 60 import java.util.EnumSet; 61 import java.util.HashSet; 62 import java.util.Set; 63 import jdk.internal.org.objectweb.asm.ClassWriter; 64 import jdk.internal.org.objectweb.asm.MethodVisitor; 65 import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; 66 import jdk.nashorn.internal.codegen.types.Type; 67 import jdk.nashorn.internal.ir.FunctionNode; 68 import jdk.nashorn.internal.ir.debug.NashornClassReader; 69 import jdk.nashorn.internal.ir.debug.NashornTextifier; 70 import jdk.nashorn.internal.runtime.Context; 71 import jdk.nashorn.internal.runtime.PropertyMap; 72 import jdk.nashorn.internal.runtime.RewriteException; 73 import jdk.nashorn.internal.runtime.ScriptObject; 74 import jdk.nashorn.internal.runtime.Source; 75 76 /** 77 * The interface responsible for speaking to ASM, emitting classes, 78 * fields and methods. 79 * <p> 80 * This file contains the ClassEmitter, which is the master object 81 * responsible for writing byte codes. It utilizes a MethodEmitter 82 * for method generation, which also the NodeVisitors own, to keep 83 * track of the current code generator and what it is doing. 84 * <p> 85 * There is, however, nothing stopping you from using this in a 86 * completely self contained environment, for example in ObjectGenerator 87 * where there are no visitors or external hooks. 88 * <p> 89 * MethodEmitter makes it simple to generate code for methods without 90 * having to do arduous type checking. It maintains a type stack 91 * and will pick the appropriate operation for all operations sent to it 92 * We also allow chained called to a MethodEmitter for brevity, e.g. 93 * it is legal to write _new(className).dup() or 94 * load(slot).load(slot2).xor().store(slot3); 95 * <p> 96 * If running with assertions enabled, any type conflict, such as different 97 * bytecode stack sizes or operating on the wrong type will be detected 98 * and an error thrown. 99 * <p> 100 * There is also a very nice debug interface that can emit formatted 101 * bytecodes that have been written. This is enabled by setting the 102 * environment "nashorn.codegen.debug" to true, or --log=codegen:{@literal <level>} 103 * <p> 104 * 105 * @see Compiler 106 */ 107 public class ClassEmitter { 108 /** Default flags for class generation - public class */ 109 private static final EnumSet<Flag> DEFAULT_METHOD_FLAGS = EnumSet.of(Flag.PUBLIC); 110 111 /** Sanity check flag - have we started on a class? */ 112 private boolean classStarted; 113 114 /** Sanity check flag - have we ended this emission? */ 115 private boolean classEnded; 116 117 /** 118 * Sanity checks - which methods have we currently 119 * started for generation in this class? 120 */ 121 private final HashSet<MethodEmitter> methodsStarted; 122 123 /** The ASM classwriter that we use for all bytecode operations */ 124 protected final ClassWriter cw; 125 126 /** The script environment */ 127 protected final Context context; 128 129 /** Compile unit class name. */ 130 private String unitClassName; 131 132 /** Set of constants access methods required. */ 133 private Set<Class<?>> constantMethodNeeded; 134 135 private int methodCount; 136 137 private int initCount; 138 139 private int clinitCount; 140 141 private int fieldCount; 142 143 private final Set<String> methodNames; 144 145 /** 146 * Constructor - only used internally in this class as it breaks 147 * abstraction towards ASM or other code generator below 148 * 149 * @param env script environment 150 * @param cw ASM classwriter 151 */ 152 private ClassEmitter(final Context context, final ClassWriter cw) { 153 this.context = context; 154 this.cw = cw; 155 this.methodsStarted = new HashSet<>(); 156 this.methodNames = new HashSet<>(); 157 } 158 159 /** 160 * Return the method names encountered 161 * @return method names 162 */ 163 public Set<String> getMethodNames() { 164 return Collections.unmodifiableSet(methodNames); 165 } 166 167 /** 168 * Constructor 169 * 170 * @param env script environment 171 * @param className name of class to weave 172 * @param superClassName super class name for class 173 * @param interfaceNames names of interfaces implemented by this class, or null if none 174 */ 175 ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) { 176 this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS)); 177 cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, className, null, superClassName, interfaceNames); 178 } 179 180 /** 181 * Constructor from the compiler 182 * 183 * @param env Script environment 184 * @param sourceName Source name 185 * @param unitClassName Compile unit class name. 186 * @param strictMode Should we generate this method in strict mode 187 */ 188 ClassEmitter(final Context context, final String sourceName, final String unitClassName, final boolean strictMode) { 189 this(context, 190 new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { 191 private static final String OBJECT_CLASS = "java/lang/Object"; 192 193 @Override 194 protected String getCommonSuperClass(final String type1, final String type2) { 195 try { 196 return super.getCommonSuperClass(type1, type2); 197 } catch (final RuntimeException e) { 198 if (isScriptObject(Compiler.SCRIPTS_PACKAGE, type1) && isScriptObject(Compiler.SCRIPTS_PACKAGE, type2)) { 199 return className(ScriptObject.class); 200 } 201 return OBJECT_CLASS; 202 } 203 } 204 }); 205 206 this.unitClassName = unitClassName; 207 this.constantMethodNeeded = new HashSet<>(); 208 209 cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, unitClassName, null, pathName(jdk.nashorn.internal.scripts.JS.class.getName()), null); 210 cw.visitSource(sourceName, null); 211 212 defineCommonStatics(strictMode); 213 } 214 215 Context getContext() { 216 return context; 217 } 218 219 /** 220 * Returns the name of the compile unit class name. 221 * @return the name of the compile unit class name. 222 */ 223 String getUnitClassName() { 224 return unitClassName; 225 } 226 227 /** 228 * Get the method count, including init and clinit methods 229 * @return method count 230 */ 231 public int getMethodCount() { 232 return methodCount; 233 } 234 235 /** 236 * Get the clinit count 237 * @return clinit count 238 */ 239 public int getClinitCount() { 240 return clinitCount; 241 } 242 243 /** 244 * Get the init count 245 * @return init count 246 */ 247 public int getInitCount() { 248 return initCount; 249 } 250 251 /** 252 * Get the field count 253 * @return field count 254 */ 255 public int getFieldCount() { 256 return fieldCount; 257 } 258 259 /** 260 * Convert a binary name to a package/class name. 261 * 262 * @param name Binary name. 263 * @return Package/class name. 264 */ 265 private static String pathName(final String name) { 266 return name.replace('.', '/'); 267 } 268 269 /** 270 * Define the static fields common in all scripts. 271 * @param strictMode Should we generate this method in strict mode 272 */ 273 private void defineCommonStatics(final boolean strictMode) { 274 // source - used to store the source data (text) for this script. Shared across 275 // compile units. Set externally by the compiler. 276 field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), SOURCE.symbolName(), Source.class); 277 278 // constants - used to the constants array for this script. Shared across 279 // compile units. Set externally by the compiler. 280 field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), CONSTANTS.symbolName(), Object[].class); 281 282 // strictMode - was this script compiled in strict mode. Set externally by the compiler. 283 field(EnumSet.of(Flag.PUBLIC, Flag.STATIC, Flag.FINAL), STRICT_MODE.symbolName(), boolean.class, strictMode); 284 } 285 286 /** 287 * Define static utilities common needed in scripts. These are per compile unit 288 * and therefore have to be defined here and not in code gen. 289 */ 290 private void defineCommonUtilities() { 291 assert unitClassName != null; 292 293 if (constantMethodNeeded.contains(String.class)) { 294 // $getString - get the ith entry from the constants table and cast to String. 295 final MethodEmitter getStringMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), GET_STRING.symbolName(), String.class, int.class); 296 getStringMethod.begin(); 297 getStringMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor()) 298 .load(Type.INT, 0) 299 .arrayload() 300 .checkcast(String.class) 301 ._return(); 302 getStringMethod.end(); 303 } 304 305 if (constantMethodNeeded.contains(PropertyMap.class)) { 306 // $getMap - get the ith entry from the constants table and cast to PropertyMap. 307 final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.symbolName(), PropertyMap.class, int.class); 308 getMapMethod.begin(); 309 getMapMethod.loadConstants() 310 .load(Type.INT, 0) 311 .arrayload() 312 .checkcast(PropertyMap.class) 313 ._return(); 314 getMapMethod.end(); 315 316 // $setMap - overwrite an existing map. 317 final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.symbolName(), void.class, int.class, PropertyMap.class); 318 setMapMethod.begin(); 319 setMapMethod.loadConstants() 320 .load(Type.INT, 0) 321 .load(Type.OBJECT, 1) 322 .arraystore(); 323 setMapMethod.returnVoid(); 324 setMapMethod.end(); 325 } 326 327 // $getXXXX$array - get the ith entry from the constants table and cast to XXXX[]. 328 for (final Class<?> clazz : constantMethodNeeded) { 329 if (clazz.isArray()) { 330 defineGetArrayMethod(clazz); 331 } 332 } 333 } 334 335 /** 336 * Constructs a primitive specific method for getting the ith entry from the constants table as an array. 337 * @param clazz Array class. 338 */ 339 private void defineGetArrayMethod(final Class<?> clazz) { 340 assert unitClassName != null; 341 342 final String methodName = getArrayMethodName(clazz); 343 final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, clazz, int.class); 344 345 getArrayMethod.begin(); 346 getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor()) 347 .load(Type.INT, 0) 348 .arrayload() 349 .checkcast(clazz) 350 .invoke(virtualCallNoLookup(clazz, "clone", Object.class)) 351 .checkcast(clazz) 352 ._return(); 353 getArrayMethod.end(); 354 } 355 356 357 /** 358 * Generate the name of a get array from constant pool method. 359 * @param clazz Name of array class. 360 * @return Method name. 361 */ 362 static String getArrayMethodName(final Class<?> clazz) { 363 assert clazz.isArray(); 364 return GET_ARRAY_PREFIX.symbolName() + clazz.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName(); 365 } 366 367 /** 368 * Ensure a get constant method is issued for the class. 369 * @param clazz Class of constant. 370 */ 371 void needGetConstantMethod(final Class<?> clazz) { 372 constantMethodNeeded.add(clazz); 373 } 374 375 /** 376 * Inspect class name and decide whether we are generating a ScriptObject class 377 * 378 * @param scriptPrefix the script class prefix for the current script 379 * @param type the type to check 380 * 381 * @return true if type is ScriptObject 382 */ 383 private static boolean isScriptObject(final String scriptPrefix, final String type) { 384 if (type.startsWith(scriptPrefix)) { 385 return true; 386 } else if (type.equals(CompilerConstants.className(ScriptObject.class))) { 387 return true; 388 } else if (type.startsWith(Compiler.OBJECTS_PACKAGE)) { 389 return true; 390 } 391 392 return false; 393 } 394 395 /** 396 * Call at beginning of class emission 397 */ 398 public void begin() { 399 classStarted = true; 400 } 401 402 /** 403 * Call at end of class emission 404 */ 405 public void end() { 406 assert classStarted : "class not started for " + unitClassName; 407 408 if (unitClassName != null) { 409 final MethodEmitter initMethod = init(EnumSet.of(Flag.PRIVATE)); 410 initMethod.begin(); 411 initMethod.load(Type.OBJECT, 0); 412 initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class); 413 initMethod.returnVoid(); 414 initMethod.end(); 415 416 defineCommonUtilities(); 417 } 418 419 cw.visitEnd(); 420 classStarted = false; 421 classEnded = true; 422 assert methodsStarted.isEmpty() : "methodsStarted not empty " + methodsStarted; 423 } 424 425 /** 426 * Disassemble an array of byte code. 427 * @param bytecode byte array representing bytecode 428 * @return disassembly as human readable string 429 */ 430 static String disassemble(final byte[] bytecode) { 431 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 432 try (final PrintWriter pw = new PrintWriter(baos)) { 433 final NashornClassReader cr = new NashornClassReader(bytecode); 434 final Context ctx = AccessController.doPrivileged(new PrivilegedAction<Context>() { 435 @Override 436 public Context run() { 437 return Context.getContext(); 438 } 439 }); 440 final TraceClassVisitor tcv = new TraceClassVisitor(null, new NashornTextifier(ctx.getEnv(), cr), pw); 441 cr.accept(tcv, 0); 442 } 443 444 final String str = new String(baos.toByteArray()); 445 return str; 446 } 447 448 /** 449 * Call back from MethodEmitter for method start 450 * 451 * @see MethodEmitter 452 * 453 * @param method method emitter. 454 */ 455 void beginMethod(final MethodEmitter method) { 456 assert !methodsStarted.contains(method); 457 methodsStarted.add(method); 458 } 459 460 /** 461 * Call back from MethodEmitter for method end 462 * 463 * @see MethodEmitter 464 * 465 * @param method 466 */ 467 void endMethod(final MethodEmitter method) { 468 assert methodsStarted.contains(method); 469 methodsStarted.remove(method); 470 } 471 472 /** 473 * Add a new method to the class - defaults to public method 474 * 475 * @param methodName name of method 476 * @param rtype return type of the method 477 * @param ptypes parameter types the method 478 * 479 * @return method emitter to use for weaving this method 480 */ 481 MethodEmitter method(final String methodName, final Class<?> rtype, final Class<?>... ptypes) { 482 return method(DEFAULT_METHOD_FLAGS, methodName, rtype, ptypes); //TODO why public default ? 483 } 484 485 /** 486 * Add a new method to the class - defaults to public method 487 * 488 * @param methodFlags access flags for the method 489 * @param methodName name of method 490 * @param rtype return type of the method 491 * @param ptypes parameter types the method 492 * 493 * @return method emitter to use for weaving this method 494 */ 495 MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { 496 methodCount++; 497 methodNames.add(methodName); 498 return new MethodEmitter(this, methodVisitor(methodFlags, methodName, rtype, ptypes)); 499 } 500 501 /** 502 * Add a new method to the class - defaults to public method 503 * 504 * @param methodName name of method 505 * @param descriptor descriptor of method 506 * 507 * @return method emitter to use for weaving this method 508 */ 509 MethodEmitter method(final String methodName, final String descriptor) { 510 return method(DEFAULT_METHOD_FLAGS, methodName, descriptor); 511 } 512 513 /** 514 * Add a new method to the class - defaults to public method 515 * 516 * @param methodFlags access flags for the method 517 * @param methodName name of method 518 * @param descriptor descriptor of method 519 * 520 * @return method emitter to use for weaving this method 521 */ 522 MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final String descriptor) { 523 methodCount++; 524 methodNames.add(methodName); 525 return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null)); 526 } 527 528 /** 529 * Add a new method to the class, representing a function node 530 * 531 * @param functionNode the function node to generate a method for 532 * @return method emitter to use for weaving this method 533 */ 534 MethodEmitter method(final FunctionNode functionNode) { 535 methodCount++; 536 methodNames.add(functionNode.getName()); 537 final FunctionSignature signature = new FunctionSignature(functionNode); 538 final MethodVisitor mv = cw.visitMethod( 539 ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0), 540 functionNode.getName(), 541 signature.toString(), 542 null, 543 null); 544 545 return new MethodEmitter(this, mv, functionNode); 546 } 547 548 /** 549 * Add a new method to the class, representing a rest-of version of the function node 550 * 551 * @param functionNode the function node to generate a method for 552 * @return method emitter to use for weaving this method 553 */ 554 MethodEmitter restOfMethod(final FunctionNode functionNode) { 555 methodCount++; 556 methodNames.add(functionNode.getName()); 557 final MethodVisitor mv = cw.visitMethod( 558 ACC_PUBLIC | ACC_STATIC, 559 functionNode.getName(), 560 Type.getMethodDescriptor(functionNode.getReturnType().getTypeClass(), RewriteException.class), 561 null, 562 null); 563 564 return new MethodEmitter(this, mv, functionNode); 565 } 566 567 568 /** 569 * Start generating the <clinit> method in the class 570 * 571 * @return method emitter to use for weaving <clinit> 572 */ 573 MethodEmitter clinit() { 574 clinitCount++; 575 return method(EnumSet.of(Flag.STATIC), CLINIT.symbolName(), void.class); 576 } 577 578 /** 579 * Start generating an <init>()V method in the class 580 * 581 * @return method emitter to use for weaving <init>()V 582 */ 583 MethodEmitter init() { 584 initCount++; 585 return method(INIT.symbolName(), void.class); 586 } 587 588 /** 589 * Start generating an <init>()V method in the class 590 * 591 * @param ptypes parameter types for constructor 592 * @return method emitter to use for weaving <init>()V 593 */ 594 MethodEmitter init(final Class<?>... ptypes) { 595 initCount++; 596 return method(INIT.symbolName(), void.class, ptypes); 597 } 598 599 /** 600 * Start generating an <init>(...)V method in the class 601 * 602 * @param flags access flags for the constructor 603 * @param ptypes parameter types for the constructor 604 * 605 * @return method emitter to use for weaving <init>(...)V 606 */ 607 MethodEmitter init(final EnumSet<Flag> flags, final Class<?>... ptypes) { 608 initCount++; 609 return method(flags, INIT.symbolName(), void.class, ptypes); 610 } 611 612 /** 613 * Add a field to the class, initialized to a value 614 * 615 * @param fieldFlags flags, e.g. should it be static or public etc 616 * @param fieldName name of field 617 * @param fieldType the type of the field 618 * @param value the value 619 * 620 * @see ClassEmitter.Flag 621 */ 622 final void field(final EnumSet<Flag> fieldFlags, final String fieldName, final Class<?> fieldType, final Object value) { 623 fieldCount++; 624 cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd(); 625 } 626 627 /** 628 * Add a field to the class 629 * 630 * @param fieldFlags access flags for the field 631 * @param fieldName name of field 632 * @param fieldType type of the field 633 * 634 * @see ClassEmitter.Flag 635 */ 636 final void field(final EnumSet<Flag> fieldFlags, final String fieldName, final Class<?> fieldType) { 637 field(fieldFlags, fieldName, fieldType, null); 638 } 639 640 /** 641 * Add a field to the class - defaults to public 642 * 643 * @param fieldName name of field 644 * @param fieldType type of field 645 */ 646 final void field(final String fieldName, final Class<?> fieldType) { 647 field(EnumSet.of(Flag.PUBLIC), fieldName, fieldType, null); 648 } 649 650 /** 651 * Return a bytecode array from this ClassEmitter. The ClassEmitter must 652 * have been ended (having its end function called) for this to work. 653 * 654 * @return byte code array for generated class, null if class generation hasn't been ended with {@link ClassEmitter#end()} 655 */ 656 byte[] toByteArray() { 657 assert classEnded; 658 if (!classEnded) { 659 return null; 660 } 661 662 return cw.toByteArray(); 663 } 664 665 /** 666 * Abstraction for flags used in class emission 667 * 668 * We provide abstraction separating these from the underlying bytecode 669 * emitter. 670 * 671 * Flags are provided for method handles, protection levels, static/virtual 672 * fields/methods. 673 */ 674 static enum Flag { 675 /** method handle with static access */ 676 HANDLE_STATIC(H_INVOKESTATIC), 677 /** method handle with new invoke special access */ 678 HANDLE_NEWSPECIAL(H_NEWINVOKESPECIAL), 679 /** method handle with invoke special access */ 680 HANDLE_SPECIAL(H_INVOKESPECIAL), 681 /** method handle with invoke virtual access */ 682 HANDLE_VIRTUAL(H_INVOKEVIRTUAL), 683 /** method handle with invoke interface access */ 684 HANDLE_INTERFACE(H_INVOKEINTERFACE), 685 686 /** final access */ 687 FINAL(ACC_FINAL), 688 /** static access */ 689 STATIC(ACC_STATIC), 690 /** public access */ 691 PUBLIC(ACC_PUBLIC), 692 /** private access */ 693 PRIVATE(ACC_PRIVATE); 694 695 private int value; 696 697 private Flag(final int value) { 698 this.value = value; 699 } 700 701 /** 702 * Get the value of this flag 703 * @return the int value 704 */ 705 int getValue() { 706 return value; 707 } 708 709 /** 710 * Return the corresponding ASM flag value for an enum set of flags 711 * 712 * @param flags enum set of flags 713 * @return an integer value representing the flags intrinsic values or:ed together 714 */ 715 static int getValue(final EnumSet<Flag> flags) { 716 int v = 0; 717 for (final Flag flag : flags) { 718 v |= flag.getValue(); 719 } 720 return v; 721 } 722 } 723 724 private MethodVisitor methodVisitor(final EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { 725 return cw.visitMethod(Flag.getValue(flags), methodName, methodDescriptor(rtype, ptypes), null, null); 726 } 727 728 }