List of usage examples for org.objectweb.asm.commons InstructionAdapter visitCode
public void visitCode()
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
private void generateDelegatingConstructor(final Constructor<?> ctor) { final Type originalCtorType = Type.getType(ctor); final Type[] argTypes = originalCtorType.getArgumentTypes(); // All constructors must be public, even if in the superclass they were protected. final InstructionAdapter mv = new InstructionAdapter( cw.visitMethod(ACC_PUBLIC | (ctor.isVarArgs() ? ACC_VARARGS : 0), INIT, Type.getMethodDescriptor(originalCtorType.getReturnType(), argTypes), null, null)); mv.visitCode(); // Invoke super constructor with the same arguments. mv.visitVarInsn(ALOAD, 0);/* w ww . j a va 2s . com*/ int offset = 1; // First arg is at position 1, after this. for (final Type argType : argTypes) { mv.load(offset, argType); offset += argType.getSize(); } mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor(), false); endInitMethod(mv); }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
/** * Generates a constructor for the instance adapter class. This constructor will take the same arguments as the supertype * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize * all the method handle fields of the adapter instance with functions from the script object (or the script * function itself, if that's what's passed). There is one method handle field in the adapter class for every method * that can be implemented or overridden; the name of every field is same as the name of the method, with a number * suffix that makes it unique in case of overloaded methods. The generated constructor will invoke * {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType, * boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity * adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}. * The constructor that takes a script function will only initialize the methods with the same name as the single * abstract method. The constructor will also store the Nashorn global that was current at the constructor * invocation time in a field named "global". The generated constructor will be public, regardless of whether the * supertype constructor was public or protected. The generated constructor will not be variable arity, even if the * supertype constructor was./*w ww. j a v a2 s. c o m*/ * @param ctor the supertype constructor that is serving as the base for the generated constructor. * @param fromFunction true if we're generating a constructor that initializes SAM types from a single * ScriptFunction passed to it, false if we're generating a constructor that initializes an arbitrary type from a * ScriptObject passed to it. */ private void generateOverridingConstructor(final Constructor<?> ctor, final boolean fromFunction) { final Type originalCtorType = Type.getType(ctor); final Type[] originalArgTypes = originalCtorType.getArgumentTypes(); final int argLen = originalArgTypes.length; final Type[] newArgTypes = new Type[argLen + 1]; // Insert ScriptFunction|ScriptObject as the last argument to the constructor final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE; newArgTypes[argLen] = extraArgumentType; System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen); // All constructors must be public, even if in the superclass they were protected. // Existing super constructor <init>(this, args...) triggers generating <init>(this, args..., scriptObj). // Any variable arity constructors become fixed-arity with explicit array arguments. final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT, Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null)); mv.visitCode(); // First, invoke super constructor with original arguments. If the form of the constructor we're generating is // <init>(this, args..., scriptFn), then we're invoking super.<init>(this, args...). mv.visitVarInsn(ALOAD, 0); final Class<?>[] argTypes = ctor.getParameterTypes(); int offset = 1; // First arg is at position 1, after this. for (int i = 0; i < argLen; ++i) { final Type argType = Type.getType(argTypes[i]); mv.load(offset, argType); offset += argType.getSize(); } mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor(), false); // Get a descriptor to the appropriate "JavaAdapterFactory.getHandle" method. final String getHandleDescriptor = fromFunction ? GET_HANDLE_FUNCTION_DESCRIPTOR : GET_HANDLE_OBJECT_DESCRIPTOR; // Assign MethodHandle fields through invoking getHandle() for (final MethodInfo mi : methodInfos) { mv.visitVarInsn(ALOAD, 0); if (fromFunction && !mi.getName().equals(samName)) { // Constructors initializing from a ScriptFunction only initialize methods with the SAM name. // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overridden too. This // is a deliberate design choice. All other method handles are initialized to null. mv.visitInsn(ACONST_NULL); } else { mv.visitVarInsn(ALOAD, offset); if (!fromFunction) { mv.aconst(mi.getName()); } loadMethodTypeAndGetHandle(mv, mi, getHandleDescriptor); } mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); } // Assign "this.global = Context.getGlobal()" mv.visitVarInsn(ALOAD, 0); invokeGetGlobalWithNullCheck(mv); mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR); // Initialize converters generateConverterInit(mv, fromFunction); endInitMethod(mv); if (!fromFunction) { newArgTypes[argLen] = OBJECT_TYPE; final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT, Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null)); generateOverridingConstructorWithObjectParam(mv2, ctor, originalCtorType.getDescriptor()); } }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final Constructor<?> ctor, final String ctorDescriptor) { mv.visitCode(); mv.visitVarInsn(ALOAD, 0);/*from w w w. jav a 2s . c o m*/ final Class<?>[] argTypes = ctor.getParameterTypes(); int offset = 1; // First arg is at position 1, after this. for (int i = 0; i < argTypes.length; ++i) { final Type argType = Type.getType(argTypes[i]); mv.load(offset, argType); offset += argType.getSize(); } mv.invokespecial(superClassName, INIT, ctorDescriptor, false); mv.visitVarInsn(ALOAD, offset); mv.visitInsn(ACONST_NULL); mv.visitInsn(ACONST_NULL); mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false); endInitMethod(mv); }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
/** * Generates a method in the adapter class that adapts a method from the original class. The generated methods will * inspect the method handle field assigned to them. If it is null (the JS object doesn't provide an implementation * for the method) then it will either invoke its version in the supertype, or if it is abstract, throw an * {@link UnsupportedOperationException}. Otherwise, if the method handle field's value is not null, the handle is * invoked using invokeExact (signature polymorphic invocation as per JLS 15.12.3). Before the invocation, the * current Nashorn {@link Context} is checked, and if it is different than the global used to create the adapter * instance, the creating global is set to be the current global. In this case, the previously current global is * restored after the invocation. If invokeExact results in a Throwable that is not one of the method's declared * exceptions, and is not an unchecked throwable, then it is wrapped into a {@link RuntimeException} and the runtime * exception is thrown. The method handle retrieved from the field is guaranteed to exactly match the signature of * the method; this is guaranteed by the way constructors of the adapter class obtain them using * {@link #getHandle(Object, String, MethodType, boolean)}. * @param mi the method info describing the method to be generated. *//*from ww w .j av a 2s.c o m*/ private void generateMethod(final MethodInfo mi) { final Method method = mi.method; final Class<?>[] exceptions = method.getExceptionTypes(); final String[] exceptionNames = getExceptionNames(exceptions); final MethodType type = mi.type; final String methodDesc = type.toMethodDescriptorString(); final String name = mi.getName(); final Type asmType = Type.getMethodType(methodDesc); final Type[] asmArgTypes = asmType.getArgumentTypes(); final InstructionAdapter mv = new InstructionAdapter( cw.visitMethod(getAccessModifiers(method), name, methodDesc, null, exceptionNames)); mv.visitCode(); final Label handleDefined = new Label(); final Class<?> returnType = type.returnType(); final Type asmReturnType = Type.getType(returnType); // See if we have overriding method handle defined if (classOverride) { mv.getstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); } else { mv.visitVarInsn(ALOAD, 0); mv.getfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); } // stack: [handle] mv.visitInsn(DUP); mv.visitJumpInsn(IFNONNULL, handleDefined); // No handle is available, fall back to default behavior if (Modifier.isAbstract(method.getModifiers())) { // If the super method is abstract, throw an exception mv.anew(UNSUPPORTED_OPERATION_TYPE); mv.dup(); mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR, false); mv.athrow(); } else { mv.visitInsn(POP); // If the super method is not abstract, delegate to it. emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); } mv.visitLabel(handleDefined); // Load the creatingGlobal object if (classOverride) { // If class handle is defined, load the static defining global mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR); } else { mv.visitVarInsn(ALOAD, 0); mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR); } // stack: [creatingGlobal, handle] final Label setupGlobal = new Label(); mv.visitLabel(setupGlobal); // Determine the first index for a local variable int nextLocalVar = 1; // "this" is at 0 for (final Type t : asmArgTypes) { nextLocalVar += t.getSize(); } // Set our local variable indices final int currentGlobalVar = nextLocalVar++; final int globalsDifferVar = nextLocalVar++; mv.dup(); // stack: [creatingGlobal, creatingGlobal, handle] // Emit code for switching to the creating global // Global currentGlobal = Context.getGlobal(); invokeGetGlobal(mv); mv.dup(); mv.visitVarInsn(ASTORE, currentGlobalVar); // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle] // if(definingGlobal == currentGlobal) { final Label globalsDiffer = new Label(); mv.ifacmpne(globalsDiffer); // stack: [creatingGlobal, handle] // globalsDiffer = false mv.pop(); // stack: [handle] mv.iconst(0); // false // stack: [false, handle] final Label invokeHandle = new Label(); mv.goTo(invokeHandle); mv.visitLabel(globalsDiffer); // } else { // Context.setGlobal(definingGlobal); // stack: [creatingGlobal, handle] invokeSetGlobal(mv); // stack: [handle] // globalsDiffer = true mv.iconst(1); // stack: [true, handle] mv.visitLabel(invokeHandle); mv.visitVarInsn(ISTORE, globalsDifferVar); // stack: [handle] // Load all parameters back on stack for dynamic invocation. NOTE: since we're using a generic // Object(Object, Object, ...) type signature for the method, we must box all arguments here. int varOffset = 1; for (final Type t : asmArgTypes) { mv.load(varOffset, t); boxStackTop(mv, t); varOffset += t.getSize(); } // Invoke the target method handle final Label tryBlockStart = new Label(); mv.visitLabel(tryBlockStart); emitInvokeExact(mv, type.generic()); convertReturnValue(mv, returnType, asmReturnType); final Label tryBlockEnd = new Label(); mv.visitLabel(tryBlockEnd); emitFinally(mv, currentGlobalVar, globalsDifferVar); mv.areturn(asmReturnType); // If Throwable is not declared, we need an adapter from Throwable to RuntimeException final boolean throwableDeclared = isThrowableDeclared(exceptions); final Label throwableHandler; if (!throwableDeclared) { // Add "throw new RuntimeException(Throwable)" handler for Throwable throwableHandler = new Label(); mv.visitLabel(throwableHandler); mv.anew(RUNTIME_EXCEPTION_TYPE); mv.dupX1(); mv.swap(); mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE), false); // Fall through to rethrow handler } else { throwableHandler = null; } final Label rethrowHandler = new Label(); mv.visitLabel(rethrowHandler); // Rethrow handler for RuntimeException, Error, and all declared exception types emitFinally(mv, currentGlobalVar, globalsDifferVar); mv.athrow(); final Label methodEnd = new Label(); mv.visitLabel(methodEnd); mv.visitLocalVariable("currentGlobal", GLOBAL_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar); mv.visitLocalVariable("globalsDiffer", Type.BOOLEAN_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar); if (throwableDeclared) { mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME); assert throwableHandler == null; } else { mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME); mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME); for (final String excName : exceptionNames) { mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName); } mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME); } endMethod(mv); }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
private void generateSuperMethod(final MethodInfo mi) { final Method method = mi.method; final String methodDesc = mi.type.toMethodDescriptorString(); final String name = mi.getName(); final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes()))); mv.visitCode(); emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); endMethod(mv);/* w w w . j av a2s. c o m*/ }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterServices.java
License:Open Source License
private static MethodHandle createNoPermissionsInvoker() { final String className = "NoPermissionsInvoker"; final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER | ACC_FINAL, className, null, "java/lang/Object", null); final Type objectType = Type.getType(Object.class); final Type methodHandleType = Type.getType(MethodHandle.class); final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "invoke", Type.getMethodDescriptor(Type.VOID_TYPE, methodHandleType, objectType), null, null)); mv.visitCode(); mv.visitVarInsn(ALOAD, 0);/*from w w w . ja va 2 s. c o m*/ mv.visitVarInsn(ALOAD, 1); mv.invokevirtual(methodHandleType.getInternalName(), "invokeExact", Type.getMethodDescriptor(Type.VOID_TYPE, objectType), false); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); cw.visitEnd(); final byte[] bytes = cw.toByteArray(); final ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { @Override public ClassLoader run() { return new SecureClassLoader(null) { @Override protected Class<?> findClass(final String name) throws ClassNotFoundException { if (name.equals(className)) { return defineClass(name, bytes, 0, bytes.length, new ProtectionDomain( new CodeSource(null, (CodeSigner[]) null), new Permissions())); } throw new ClassNotFoundException(name); } }; } }); try { return MethodHandles.lookup().findStatic(Class.forName(className, true, loader), "invoke", MethodType.methodType(void.class, MethodHandle.class, Object.class)); } catch (final ReflectiveOperationException e) { throw new AssertionError(e.getMessage(), e); } }
From source file:edu.ubc.mirrors.holograms.HologramClassGenerator.java
License:Open Source License
@Override public void visitEnd() { // Generate the static field used to store the corresponding ClassMirror int staticAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC; super.visitField(staticAccess, "classMirror", classMirrorType.getDescriptor(), null, null); // Generate the constructor that takes a mirror instance as an Object parameter String constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class)); if (name.equals(getHologramType(Type.getType(Throwable.class), true).getInternalName())) { // This doesn't extend ObjectHologram so we have to set the field directly super.visitField(Opcodes.ACC_PUBLIC, "mirror", objectMirrorType.getDescriptor(), null, null); MethodVisitor methodVisitor = super.visitMethod(Opcodes.ACC_PUBLIC, "<init>", constructorDesc, null, null);/* w w w . j a v a 2s .c o m*/ methodVisitor.visitCode(); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superName, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE)); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, objectMirrorType.getInternalName()); methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, name, "mirror", Type.getDescriptor(ObjectMirror.class)); methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitMaxs(2, 2); methodVisitor.visitEnd(); methodVisitor = super.visitMethod(Opcodes.ACC_PUBLIC, "getMirror", Type.getMethodDescriptor(objectMirrorType), null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitFieldInsn(Opcodes.GETFIELD, name, "mirror", Type.getDescriptor(ObjectMirror.class)); methodVisitor.visitInsn(Opcodes.ARETURN); methodVisitor.visitMaxs(1, 1); methodVisitor.visitEnd(); } else if (!isInterface) { MethodVisitor methodVisitor = super.visitMethod(Opcodes.ACC_PUBLIC, "<init>", constructorDesc, null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superName, "<init>", constructorDesc); methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitMaxs(2, 2); methodVisitor.visitEnd(); } // Add a class initialization method to initialize the static fields, // if one doesn't exist already. if (!hasClinit) { InstructionAdapter mv = new InstructionAdapter( super.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "<clinit>", "()V", null, null)); mv.visitCode(); HologramMethodGenerator.initializeStaticFields(Type.getObjectType(this.name), mv); mv.areturn(Type.VOID_TYPE); mv.visitMaxs(2, 2); mv.visitEnd(); } super.visitEnd(); }