Search in sources :

Example 11 with Handle

use of org.objectweb.asm.Handle in project es6draft by anba.

the class SimpleTypeTextifier method visitLdcInsn.

@Override
public void visitLdcInsn(Object cst) {
    if (cst instanceof Handle) {
        Handle handle = (Handle) cst;
        handle = new Handle(handle.getTag(), handle.getOwner(), handle.getName(), getMethodDescriptor(handle.getDesc()));
        buf.setLength(0);
        buf.append(tab2).append("LDC ");
        buf.append(handle.getOwner()).append('.').append(handle.getName()).append(handle.getDesc());
        buf.append('\n');
        text.add(buf.toString());
        return;
    }
    super.visitLdcInsn(cst);
}
Also used : Handle(org.objectweb.asm.Handle)

Example 12 with Handle

use of org.objectweb.asm.Handle in project seph by seph-lang.

the class AbstractionCompiler method activationForMethod.

private void activationForMethod() {
    MethodAdapter ma = new MethodAdapter(cw.visitMethod(ACC_PUBLIC, "activationFor", sig(MethodHandle.class, int.class, boolean.class), null, null));
    Handle specific = new Handle(H_INVOKEVIRTUAL, className, encode(abstractionName), sig(SephObject.class, argumentClassesFor(argNames.size(), false)));
    Handle generic = new Handle(H_INVOKEVIRTUAL, className, encode(abstractionName), sig(SephObject.class, argumentClassesFor(-1, false)));
    ma.loadThis();
    ma.loadLocalInt(1);
    ma.loadLocalInt(2);
    ma.dynamicCall("seph:activationFor:" + encode(abstractionName) + ":" + argNames.size() + ":false", sig(MethodHandle.class, Object.class, int.class, boolean.class), BOOTSTRAP_METHOD, specific, generic);
    ma.retValue();
    ma.end();
}
Also used : MethodHandle(java.lang.invoke.MethodHandle) Handle(org.objectweb.asm.Handle) MethodHandle(java.lang.invoke.MethodHandle)

Example 13 with Handle

use of org.objectweb.asm.Handle in project seph by seph-lang.

the class AbstractionCompiler method compileRegularMessageSend.

private void compileRegularMessageSend(MethodAdapter ma, Message current, int[] layout, boolean first, Message last, Arity arity, String name) {
    ScopeEntry se = null;
    Label noActivate = null;
    String messageType = "message";
    String possibleAdditional = "";
    if (first && (se = scope.find(name)) != null) {
        ma.loadLocal(layout[METHOD_SCOPE_IDX]);
        if (runtime.configuration().doLexicalMethodHandleLookup()) {
            ma.dynamicCall("seph:lookup:" + encode(name) + ":lexical:" + se.depth + ":" + se.index, sig(SephObject.class, LexicalScope.class), BOOTSTRAP_METHOD);
        } else {
            loadFromDepth(se.depth, se.index, ma);
        }
        if (!runtime.configuration().doLexicalMethodHandleInvoke()) {
            noActivate = new Label();
            ma.dup();
            ma.interfaceCall(SephObject.class, "isActivatable", boolean.class);
            ma.zero();
            ma.ifEqual(noActivate);
            ma.load(arity.positional);
            ma.load(arity.keyword == 0 ? 0 : 1);
            ma.interfaceCall(SephObject.class, "activationFor", MethodHandle.class, int.class, boolean.class);
            if (runtime.configuration().doTailCallOptimization() && current == last) {
                ma.swap();
                ma.load(0);
            }
        }
        ma.swap();
    }
    ma.loadLocal(layout[THREAD_IDX]);
    ma.loadLocal(layout[METHOD_SCOPE_IDX]);
    Handle[] argMHrefs = compileArguments(ma, current.arguments(), layout, last);
    if (first && se != null) {
        if (runtime.configuration().doLexicalMethodHandleInvoke()) {
            boolean fullPumping = false;
            messageType = "invoke";
            if (runtime.configuration().doTailCallOptimization() && current == last) {
                messageType = "tailInvoke";
                fullPumping = true;
            }
            ma.dynamicCall("seph:" + messageType + ":" + encode(name), sigFor2(arity), BOOTSTRAP_METHOD, argMHrefs);
            if (runtime.configuration().doTailCallOptimization()) {
                if (fullPumping) {
                    if (layout[SHOULD_EVALUATE_FULLY_IDX] != 0) {
                        Label noPump = new Label();
                        ma.loadLocalInt(layout[SHOULD_EVALUATE_FULLY_IDX]);
                        ma.zero();
                        ma.ifEqual(noPump);
                        pumpTailCall(ma, layout);
                        ma.label(noPump);
                    }
                } else {
                    pumpTailCall(ma, layout);
                }
            }
        } else {
            if (runtime.configuration().doTailCallOptimization() && current == last) {
                Label activate = new Label();
                int len = argumentArrayFor(arity).length;
                ma.load(len);
                ma.newArray(Object.class);
                for (int i = len - 1; i >= 0; i--) {
                    ma.dup_x1();
                    ma.swap();
                    ma.load(i);
                    ma.swap();
                    ma.storeArray();
                }
                ma.staticCall(MethodHandles.class, "insertArguments", MethodHandle.class, MethodHandle.class, int.class, Object[].class);
                ma.loadLocal(layout[THREAD_IDX]);
                ma.swap();
                ma.putField(SThread.class, "tail", MethodHandle.class);
                ma.getStatic(SThread.class, "TAIL_MARKER", SephObject.class);
                if (layout[SHOULD_EVALUATE_FULLY_IDX] != 0) {
                    Label noPump = new Label();
                    ma.loadLocalInt(layout[SHOULD_EVALUATE_FULLY_IDX]);
                    ma.zero();
                    ma.ifEqual(noPump);
                    pumpTailCall(ma, layout);
                    ma.label(noPump);
                }
                ma.jump(activate);
                ma.label(noActivate);
                ma.swap();
                ma.pop();
                ma.label(activate);
            } else {
                Label activate = new Label();
                ma.virtualCall(MethodHandle.class, "invokeExact", sigFor(arity));
                pumpTailCall(ma, layout);
                ma.jump(activate);
                ma.label(noActivate);
                ma.swap();
                ma.pop();
                ma.label(activate);
            }
        }
    } else {
        boolean fullPumping = false;
        if (runtime.configuration().doTailCallOptimization() && current == last) {
            messageType = "tailMessage";
            fullPumping = true;
        }
        ma.dynamicCall("seph:" + messageType + ":" + encode(name) + possibleAdditional, sigFor(arity), BOOTSTRAP_METHOD, argMHrefs);
        if (runtime.configuration().doTailCallOptimization()) {
            if (fullPumping) {
                if (layout[SHOULD_EVALUATE_FULLY_IDX] != 0) {
                    Label noPump = new Label();
                    ma.loadLocalInt(layout[SHOULD_EVALUATE_FULLY_IDX]);
                    ma.zero();
                    ma.ifEqual(noPump);
                    pumpTailCall(ma, layout);
                    ma.label(noPump);
                }
            } else {
                pumpTailCall(ma, layout);
            }
        }
    }
}
Also used : Label(org.objectweb.asm.Label) MethodHandle(java.lang.invoke.MethodHandle) Handle(org.objectweb.asm.Handle)

Example 14 with Handle

use of org.objectweb.asm.Handle in project spring-loaded by spring-projects.

the class Java8 method callLambdaMetaFactory.

// TODO [perf] How about a table of CallSites indexed by invokedynamic number through the class file. Computed on first reference but cleared on reload. Possibly extend this to all invoke types!
// TODO [lambda] Need to handle altMetaFactory which is used when the lambdas are more 'complex' (e.g. Serializable)
public static CallSite callLambdaMetaFactory(ReloadableType rtype, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor, Class<?> executorClass) throws Exception {
    MethodHandles.Lookup caller = (MethodHandles.Lookup) lookup;
    ClassLoader callerLoader = caller.lookupClass().getClassLoader();
    int descriptorStart = indyNameAndDescriptor.indexOf('(');
    String invokedName = indyNameAndDescriptor.substring(0, descriptorStart);
    MethodType invokedType = MethodType.fromMethodDescriptorString(indyNameAndDescriptor.substring(descriptorStart), callerLoader);
    // Use bsmArgs to build the parameters
    MethodType samMethodType = MethodType.fromMethodDescriptorString((((Type) bsmArgs[0]).getDescriptor()), callerLoader);
    Handle bsmArgsHandle = (Handle) bsmArgs[1];
    String owner = bsmArgsHandle.getOwner();
    String name = bsmArgsHandle.getName();
    String descriptor = bsmArgsHandle.getDesc();
    MethodType implMethodType = MethodType.fromMethodDescriptorString(descriptor, callerLoader);
    // Looking up the lambda$run method in the caller class (note the caller class is the executor, which gets us around the
    // problem of having to hack into LambdaMetafactory to intercept reflection)
    MethodHandle implMethod = null;
    switch(bsmArgsHandle.getTag()) {
        case Opcodes.H_INVOKESTATIC:
            implMethod = caller.findStatic(caller.lookupClass(), name, implMethodType);
            break;
        case Opcodes.H_INVOKESPECIAL:
            // will be static with a new leading parameter.
            if (executorClass == null) {
                // TODO is final parameter here correct?
                implMethod = caller.findSpecial(caller.lookupClass(), name, implMethodType, caller.lookupClass());
            } else {
                implMethod = caller.findStatic(caller.lookupClass(), name, MethodType.fromMethodDescriptorString("(L" + owner + ";" + descriptor.substring(1), callerLoader));
            }
            break;
        case Opcodes.H_INVOKEVIRTUAL:
            // There is a possibility to 'shortcut' here. Basically we are trying to resolve a callsite reference
            // to the method that satisfies it. The easiest option is to just find the method on the originally
            // loaded version of the target class and return that. A more optimal shortcut could return the
            // method on the executor class if the target has been reloaded (effectively bypassing the method
            // on the originally loaded version since we know that it will be acting as a pass through). But this
            // opens up a can of worms related to visibility. The executor is loaded into the child classloader,
            // and if the caller has not been reloaded it will not be able to 'see' the executor (since it is in
            // a child classloader). So, basically keep this dumb (but reliable) for now.
            TypeRegistry typeRegistry = rtype.getTypeRegistry();
            ReloadableType ownerRType = typeRegistry.getReloadableType(owner);
            if (null == ownerRType || !ownerRType.hasBeenReloaded()) {
                // target containing the reference/lambdaMethod has not been reloaded, no need to get over
                // complicated.
                Class<?> clazz = callerLoader.loadClass(owner.replace("/", "."));
                implMethod = caller.findVirtual(clazz, name, implMethodType);
            } else {
                MethodMember targetReferenceMethodMember = ownerRType.getCurrentMethod(name, descriptor);
                String targetReferenceDescriptor = targetReferenceMethodMember.getDescriptor();
                MethodType targetReferenceMethodType = MethodType.fromMethodDescriptorString(targetReferenceDescriptor, callerLoader);
                Class<?> targetReferenceClass = ownerRType.getClazz();
                MethodMember currentMethod = ownerRType.getCurrentMethod(name, descriptor);
                if (currentMethod.original == null) {
                    // caller and reloaded target are in the same child classloader (no visibility problem).
                    if (!rtype.hasBeenReloaded()) {
                        throw new IllegalStateException("Assertion violated: When a method added on reload is being referenced" + "in target type '" + ownerRType.getName() + "', expected the caller to also have been reloaded: '" + rtype.getName() + "'");
                    }
                    CurrentLiveVersion ownerLiveVersion = ownerRType.getLiveVersion();
                    Class<?> ownerExecutorClass = ownerLiveVersion.getExecutorClass();
                    Method executorMethod = ownerLiveVersion.getExecutorMethod(currentMethod);
                    String methodDescriptor = Type.getType(executorMethod).getDescriptor();
                    MethodType type = MethodType.fromMethodDescriptorString(methodDescriptor, callerLoader);
                    implMethod = caller.findStatic(ownerExecutorClass, name, type);
                } else {
                    // This finds the reference method on the originally loaded class. It will pass through
                    // to the actual code on the reloaded version.
                    implMethod = caller.findVirtual(targetReferenceClass, name, targetReferenceMethodType);
                }
            }
            break;
        case Opcodes.H_NEWINVOKESPECIAL:
            Class<?> clazz = callerLoader.loadClass(owner.replace("/", "."));
            implMethod = caller.findConstructor(clazz, implMethodType);
            break;
        case Opcodes.H_INVOKEINTERFACE:
            Handle h = (Handle) bsmArgs[1];
            String interfaceOwner = h.getOwner();
            // TODO Should there not be a more direct way to this than classloading?
            // TODO What about when this is a method added to the interface on a reload? It won't really exist, should we point
            // to the executor? or something else? (maybe just directly the real method that will satisfy the interface - if it can be worked out)
            // interface type, eg StreamB$Foo
            Class<?> interfaceClass = callerLoader.loadClass(interfaceOwner.replace('/', '.'));
            implMethod = caller.findVirtual(interfaceClass, name, implMethodType);
            break;
        default:
            throw new IllegalStateException("nyi " + bsmArgsHandle.getTag());
    }
    MethodType instantiatedMethodType = MethodType.fromMethodDescriptorString((((Type) bsmArgs[2]).getDescriptor()), callerLoader);
    return LambdaMetafactory.metafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType);
}
Also used : MethodType(java.lang.invoke.MethodType) CurrentLiveVersion(org.springsource.loaded.CurrentLiveVersion) Method(java.lang.reflect.Method) TypeRegistry(org.springsource.loaded.TypeRegistry) MethodMember(org.springsource.loaded.MethodMember) MethodHandle(java.lang.invoke.MethodHandle) Handle(org.objectweb.asm.Handle) MethodHandles(java.lang.invoke.MethodHandles) Type(org.objectweb.asm.Type) MethodType(java.lang.invoke.MethodType) ReloadableType(org.springsource.loaded.ReloadableType) ReloadableType(org.springsource.loaded.ReloadableType) MethodHandle(java.lang.invoke.MethodHandle)

Aggregations

Handle (org.objectweb.asm.Handle)14 MethodHandle (java.lang.invoke.MethodHandle)6 Type (org.objectweb.asm.Type)4 Label (org.objectweb.asm.Label)3 MethodType (java.lang.invoke.MethodType)2 StackManipulation (net.bytebuddy.implementation.bytecode.StackManipulation)2 Test (org.junit.Test)2 ClassReader (org.objectweb.asm.ClassReader)2 ClassWriter (org.objectweb.asm.ClassWriter)2 MethodVisitor (org.objectweb.asm.MethodVisitor)2 Local (com.googlecode.dex2jar.ir.expr.Local)1 MethodHandles (java.lang.invoke.MethodHandles)1 Executable (java.lang.reflect.Executable)1 Method (java.lang.reflect.Method)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 ClassVisitor (org.objectweb.asm.ClassVisitor)1 ClassNode (org.objectweb.asm.tree.ClassNode)1 FieldNode (org.objectweb.asm.tree.FieldNode)1