List of usage examples for org.objectweb.asm.commons InstructionAdapter visitVarInsn
@Override
public void visitVarInsn(final int opcode, final int var)
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
private void generateConverterInit(final InstructionAdapter mv, final boolean samOnly) { assert !samOnly || !classOverride; for (final Map.Entry<Class<?>, String> converterField : converterFields.entrySet()) { final Class<?> returnType = converterField.getKey(); if (!classOverride) { mv.visitVarInsn(ALOAD, 0); }/*from w w w . j a va2 s . c o m*/ if (samOnly && !samReturnTypes.contains(returnType)) { mv.visitInsn(ACONST_NULL); } else { mv.aconst(Type.getType(converterField.getKey())); mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getObjectConverter", GET_CONVERTER_METHOD_DESCRIPTOR, false); } if (classOverride) { mv.putstatic(generatedClassName, converterField.getValue(), METHOD_HANDLE_TYPE_DESCRIPTOR); } else { mv.putfield(generatedClassName, converterField.getValue(), METHOD_HANDLE_TYPE_DESCRIPTOR); } } }
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();//from w w w . j av a 2 s . co m // Invoke super constructor with the same arguments. mv.visitVarInsn(ALOAD, 0); 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.// www . j av 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();/*from w w w . j av a 2 s . c o m*/ 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 < 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 .java 2 s . c om 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 convertReturnValue(final InstructionAdapter mv, final Class<?> returnType, final Type asmReturnType) { switch (asmReturnType.getSort()) { case Type.VOID: mv.pop();//from ww w .j a v a 2 s. com break; case Type.BOOLEAN: JSType.TO_BOOLEAN.invoke(mv); break; case Type.BYTE: JSType.TO_INT32.invoke(mv); mv.visitInsn(Opcodes.I2B); break; case Type.SHORT: JSType.TO_INT32.invoke(mv); mv.visitInsn(Opcodes.I2S); break; case Type.CHAR: // JSType doesn't have a TO_CHAR, so we have services supply us one. mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "toCharPrimitive", TO_CHAR_PRIMITIVE_METHOD_DESCRIPTOR, false); break; case Type.INT: JSType.TO_INT32.invoke(mv); break; case Type.LONG: JSType.TO_LONG.invoke(mv); break; case Type.FLOAT: JSType.TO_NUMBER.invoke(mv); mv.visitInsn(Opcodes.D2F); break; case Type.DOUBLE: JSType.TO_NUMBER.invoke(mv); break; default: if (asmReturnType.equals(OBJECT_TYPE)) { // Must hide ConsString (and potentially other internal Nashorn types) from callers mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "exportReturnValue", EXPORT_RETURN_VALUE_METHOD_DESCRIPTOR, false); } else if (asmReturnType.equals(STRING_TYPE)) { // Well-known conversion to String. Not using the JSType one as we want to preserve null as null instead // of the string "n,u,l,l". mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "toString", TO_STRING_METHOD_DESCRIPTOR, false); } else { // Invoke converter method handle for everything else. Note that we could have just added an asType or // filterReturnValue to the invoked handle instead, but then every instance would have the function // method handle wrapped in a separate converter method handle, making handle.invokeExact() megamorphic. if (classOverride) { mv.getstatic(generatedClassName, converterFields.get(returnType), METHOD_HANDLE_TYPE_DESCRIPTOR); } else { mv.visitVarInsn(ALOAD, 0); mv.getfield(generatedClassName, converterFields.get(returnType), METHOD_HANDLE_TYPE_DESCRIPTOR); } mv.swap(); emitInvokeExact(mv, MethodType.methodType(returnType, Object.class)); } } }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
/** * Emit code to restore the previous Nashorn Context when needed. * @param mv the instruction adapter/*from w ww . j a v a2 s . c o m*/ * @param currentGlobalVar index of the local variable holding the reference to the current global at method * entry. * @param globalsDifferVar index of the boolean local variable that is true if the global needs to be restored. */ private static void emitFinally(final InstructionAdapter mv, final int currentGlobalVar, final int globalsDifferVar) { // Emit code to restore the previous Nashorn global if needed mv.visitVarInsn(ILOAD, globalsDifferVar); final Label skip = new Label(); mv.ifeq(skip); mv.visitVarInsn(ALOAD, currentGlobalVar); invokeSetGlobal(mv); mv.visitLabel(skip); }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
private void emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc) { mv.visitVarInsn(ALOAD, 0); int nextParam = 1; final Type methodType = Type.getMethodType(methodDesc); for (final Type t : methodType.getArgumentTypes()) { mv.load(nextParam, t);//from ww w .j ava 2s . co m nextParam += t.getSize(); } // default method - non-abstract, interface method if (Modifier.isInterface(owner.getModifiers())) { // we should call default method on the immediate "super" type - not on (possibly) // the indirectly inherited interface class! mv.invokespecial(Type.getInternalName(findInvokespecialOwnerFor(owner)), name, methodDesc, false); } else { mv.invokespecial(superClassName, name, methodDesc, false); } mv.areturn(methodType.getReturnType()); }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
private void generateFinalizerDelegate(final String finalizerDelegateName) { // Generate a delegate that will be invoked from the no-permission trampoline. Note it can be private, as we'll // refer to it with a MethodHandle constant pool entry in the overridden finalize() method (see // generateFinalizerOverride()). final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PRIVATE | ACC_STATIC, finalizerDelegateName, Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE), null, null)); // Simply invoke super.finalize() mv.visitVarInsn(ALOAD, 0); mv.checkcast(Type.getType(generatedClassName)); mv.invokespecial(superClassName, "finalize", Type.getMethodDescriptor(Type.VOID_TYPE), false); mv.visitInsn(RETURN);/*w w w . j av a 2 s.c om*/ endMethod(mv); }
From source file:com.gargoylesoftware.js.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.java
License:Open Source License
private void generateFinalizerOverride(final String finalizerDelegateName) { final InstructionAdapter mv = new InstructionAdapter( cw.visitMethod(ACC_PUBLIC, "finalize", VOID_NOARG_METHOD_DESCRIPTOR, null, null)); // Overridden finalizer will take a MethodHandle to the finalizer delegating method, ... mv.aconst(new Handle(Opcodes.H_INVOKESTATIC, generatedClassName, finalizerDelegateName, Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE))); mv.visitVarInsn(ALOAD, 0); // ...and invoke it through JavaAdapterServices.invokeNoPermissions mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "invokeNoPermissions", Type.getMethodDescriptor(METHOD_HANDLE_TYPE, OBJECT_TYPE), false); mv.visitInsn(RETURN);//from w ww. ja v a 2s .com endMethod(mv); }