Search in sources :

Example 11 with ParameterElement

use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.

the class AopProxyWriter method visitBeanDefinitionEnd.

/**
 * Finalizes the proxy. This method should be called before writing the proxy to disk with {@link #writeTo(File)}
 */
@Override
public void visitBeanDefinitionEnd() {
    if (declaredConstructor == null) {
        throw new IllegalStateException("The method visitBeanDefinitionConstructor(..) should be called at least once");
    } else {
        initConstructor(declaredConstructor);
    }
    if (parentWriter != null && !isProxyTarget) {
        processAlreadyVisitedMethods(parentWriter);
    }
    interceptorParameter.annotate(AnnotationUtil.ANN_INTERCEPTOR_BINDING_QUALIFIER, builder -> {
        final AnnotationValue<?>[] interceptorBinding = this.interceptorBinding.toArray(new AnnotationValue[0]);
        builder.values(interceptorBinding);
    });
    qualifierParameter.annotate(AnnotationUtil.NULLABLE);
    String constructorDescriptor = getConstructorDescriptor(Arrays.asList(newConstructor.getParameters()));
    ClassWriter proxyClassWriter = this.classWriter;
    this.constructorWriter = proxyClassWriter.visitMethod(ACC_PUBLIC, CONSTRUCTOR_NAME, constructorDescriptor, null, null);
    this.constructorGenerator = new GeneratorAdapter(constructorWriter, Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, constructorDescriptor);
    GeneratorAdapter proxyConstructorGenerator = this.constructorGenerator;
    proxyConstructorGenerator.loadThis();
    if (isInterface) {
        proxyConstructorGenerator.invokeConstructor(TYPE_OBJECT, METHOD_DEFAULT_CONSTRUCTOR);
    } else {
        ParameterElement[] existingArguments = declaredConstructor.getParameters();
        for (int i = 0; i < existingArguments.length; i++) {
            proxyConstructorGenerator.loadArg(i);
        }
        String superConstructorDescriptor = getConstructorDescriptor(Arrays.asList(existingArguments));
        proxyConstructorGenerator.invokeConstructor(getTypeReferenceForName(targetClassFullName), new Method(CONSTRUCTOR_NAME, superConstructorDescriptor));
    }
    proxyBeanDefinitionWriter.visitBeanDefinitionConstructor(newConstructor, constructorRequiresReflection, visitorContext);
    GeneratorAdapter targetDefinitionGenerator = null;
    GeneratorAdapter targetTypeGenerator = null;
    if (parentWriter != null) {
        proxyBeanDefinitionWriter.visitBeanDefinitionInterface(ProxyBeanDefinition.class);
        ClassVisitor pcw = proxyBeanDefinitionWriter.getClassWriter();
        targetDefinitionGenerator = new GeneratorAdapter(pcw.visitMethod(ACC_PUBLIC, METHOD_PROXY_TARGET_TYPE.getName(), METHOD_PROXY_TARGET_TYPE.getDescriptor(), null, null), ACC_PUBLIC, METHOD_PROXY_TARGET_TYPE.getName(), METHOD_PROXY_TARGET_TYPE.getDescriptor());
        targetDefinitionGenerator.loadThis();
        targetDefinitionGenerator.push(getTypeReferenceForName(parentWriter.getBeanDefinitionName()));
        targetDefinitionGenerator.returnValue();
        targetTypeGenerator = new GeneratorAdapter(pcw.visitMethod(ACC_PUBLIC, METHOD_PROXY_TARGET_CLASS.getName(), METHOD_PROXY_TARGET_CLASS.getDescriptor(), null, null), ACC_PUBLIC, METHOD_PROXY_TARGET_CLASS.getName(), METHOD_PROXY_TARGET_CLASS.getDescriptor());
        targetTypeGenerator.loadThis();
        targetTypeGenerator.push(getTypeReferenceForName(parentWriter.getBeanTypeName()));
        targetTypeGenerator.returnValue();
    }
    Class<?> interceptedInterface = isIntroduction ? Introduced.class : Intercepted.class;
    Type targetType = getTypeReferenceForName(targetClassFullName);
    // add the $beanLocator field
    if (isProxyTarget) {
        proxyClassWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_BEAN_LOCATOR, TYPE_BEAN_LOCATOR.getDescriptor(), null, null);
        // add the $beanQualifier field
        proxyClassWriter.visitField(ACC_PRIVATE, FIELD_BEAN_QUALIFIER, Type.getType(Qualifier.class).getDescriptor(), null, null);
        writeWithQualifierMethod(proxyClassWriter);
        if (!lazy || cacheLazyTarget) {
            // add the $target field for the target bean
            int modifiers = hotswap ? ACC_PRIVATE : ACC_PRIVATE | ACC_FINAL;
            proxyClassWriter.visitField(modifiers, FIELD_TARGET, targetType.getDescriptor(), null, null);
        }
        if (lazy) {
            interceptedInterface = InterceptedProxy.class;
            proxyClassWriter.visitField(ACC_PRIVATE, FIELD_BEAN_RESOLUTION_CONTEXT, Type.getType(BeanResolutionContext.class).getDescriptor(), null, null);
        } else {
            interceptedInterface = hotswap ? HotSwappableInterceptedProxy.class : InterceptedProxy.class;
            if (hotswap) {
                // Add ReadWriteLock field
                // private final ReentrantReadWriteLock $target_rwl = new ReentrantReadWriteLock();
                proxyClassWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK.getDescriptor(), null, null);
                proxyConstructorGenerator.loadThis();
                pushNewInstance(proxyConstructorGenerator, TYPE_READ_WRITE_LOCK);
                proxyConstructorGenerator.putField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
                // Add Read Lock field
                // private final Lock $target_rl = $target_rwl.readLock();
                proxyClassWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_READ_LOCK, TYPE_LOCK.getDescriptor(), null, null);
                proxyConstructorGenerator.loadThis();
                proxyConstructorGenerator.loadThis();
                proxyConstructorGenerator.getField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
                proxyConstructorGenerator.invokeInterface(Type.getType(ReadWriteLock.class), Method.getMethod(Lock.class.getName() + " readLock()"));
                proxyConstructorGenerator.putField(proxyType, FIELD_READ_LOCK, TYPE_LOCK);
                // Add Write Lock field
                // private final Lock $target_wl = $target_rwl.writeLock();
                proxyClassWriter.visitField(ACC_PRIVATE | ACC_FINAL, FIELD_WRITE_LOCK, Type.getDescriptor(Lock.class), null, null);
                proxyConstructorGenerator.loadThis();
                proxyConstructorGenerator.loadThis();
                proxyConstructorGenerator.getField(proxyType, FIELD_READ_WRITE_LOCK, TYPE_READ_WRITE_LOCK);
                proxyConstructorGenerator.invokeInterface(Type.getType(ReadWriteLock.class), Method.getMethod(Lock.class.getName() + " writeLock()"));
                proxyConstructorGenerator.putField(proxyType, FIELD_WRITE_LOCK, TYPE_LOCK);
            }
        }
        // assign the bean locator
        proxyConstructorGenerator.loadThis();
        proxyConstructorGenerator.loadArg(beanContextArgumentIndex);
        proxyConstructorGenerator.putField(proxyType, FIELD_BEAN_LOCATOR, TYPE_BEAN_LOCATOR);
        proxyConstructorGenerator.loadThis();
        proxyConstructorGenerator.loadArg(qualifierIndex);
        proxyConstructorGenerator.putField(proxyType, FIELD_BEAN_QUALIFIER, Type.getType(Qualifier.class));
        if (!lazy) {
            proxyConstructorGenerator.loadThis();
            pushResolveProxyTargetBean(proxyConstructorGenerator, targetType);
            proxyConstructorGenerator.putField(proxyType, FIELD_TARGET, targetType);
        } else {
            proxyConstructorGenerator.loadThis();
            proxyConstructorGenerator.loadArg(beanResolutionContextArgumentIndex);
            proxyConstructorGenerator.invokeInterface(Type.getType(BeanResolutionContext.class), Method.getMethod(ReflectionUtils.getRequiredMethod(BeanResolutionContext.class, "copy")));
            proxyConstructorGenerator.putField(proxyType, FIELD_BEAN_RESOLUTION_CONTEXT, Type.getType(BeanResolutionContext.class));
        }
        // Write the Object interceptedTarget() method
        writeInterceptedTargetMethod(proxyClassWriter, targetType);
        // e. T swap(T newInstance);
        if (hotswap && !lazy) {
            writeSwapMethod(proxyClassWriter, targetType);
        }
    }
    String[] interfaces = getImplementedInterfaceInternalNames();
    if (isInterface && implementInterface) {
        String[] adviceInterfaces = { getInternalName(targetClassFullName), Type.getInternalName(interceptedInterface) };
        interfaces = ArrayUtils.concat(interfaces, adviceInterfaces);
    } else {
        String[] adviceInterfaces = { Type.getInternalName(interceptedInterface) };
        interfaces = ArrayUtils.concat(interfaces, adviceInterfaces);
    }
    proxyClassWriter.visit(V1_8, ACC_SYNTHETIC, proxyInternalName, null, isInterface ? TYPE_OBJECT.getInternalName() : getTypeReferenceForName(targetClassFullName).getInternalName(), interfaces);
    // set $proxyMethods field
    proxyConstructorGenerator.loadThis();
    proxyConstructorGenerator.push(proxyMethodCount);
    proxyConstructorGenerator.newArray(EXECUTABLE_METHOD_TYPE);
    proxyConstructorGenerator.putField(proxyType, FIELD_PROXY_METHODS, FIELD_TYPE_PROXY_METHODS);
    // set $interceptors field
    proxyConstructorGenerator.loadThis();
    proxyConstructorGenerator.push(proxyMethodCount);
    proxyConstructorGenerator.newArray(INTERCEPTOR_ARRAY_TYPE);
    proxyConstructorGenerator.putField(proxyType, FIELD_INTERCEPTORS, FIELD_TYPE_INTERCEPTORS);
    // now initialize the held values
    if (isProxyTarget) {
        if (proxiedMethods.size() == proxyMethodCount) {
            Iterator<MethodRef> iterator = proxyTargetMethods.iterator();
            for (int i = 0; i < proxyMethodCount; i++) {
                MethodRef methodRef = iterator.next();
                // The following will initialize the array of $proxyMethod instances
                // Eg. this.$proxyMethods[0] = $PARENT_BEAN.getRequiredMethod("test", new Class[]{String.class});
                proxyConstructorGenerator.loadThis();
                // Step 1: dereference the array - this.$proxyMethods[0]
                proxyConstructorGenerator.getField(proxyType, FIELD_PROXY_METHODS, FIELD_TYPE_PROXY_METHODS);
                proxyConstructorGenerator.push(i);
                // Step 2: lookup the Method instance from the declaring type
                // context.getProxyTargetMethod("test", new Class[]{String.class});
                proxyConstructorGenerator.loadArg(beanContextArgumentIndex);
                buildProxyLookupArgument(proxyConstructorGenerator, targetType);
                proxyConstructorGenerator.loadArg(qualifierIndex);
                pushMethodNameAndTypesArguments(proxyConstructorGenerator, methodRef.name, methodRef.argumentTypes);
                proxyConstructorGenerator.invokeInterface(Type.getType(ExecutionHandleLocator.class), METHOD_GET_PROXY_TARGET);
                // Step 3: store the result in the array
                proxyConstructorGenerator.visitInsn(AASTORE);
                // Step 4: Resolve the interceptors
                // this.$interceptors[0] = InterceptorChain.resolveAroundInterceptors(this.$proxyMethods[0], var2);
                pushResolveInterceptorsCall(proxyConstructorGenerator, i, isIntroduction);
            }
        }
    } else if (!proxiedMethods.isEmpty()) {
        BeanDefinitionWriter beanDefinitionWriter = parentWriter == null ? proxyBeanDefinitionWriter : parentWriter;
        ExecutableMethodsDefinitionWriter executableMethodsDefinitionWriter = beanDefinitionWriter.getExecutableMethodsWriter();
        Type executableMethodsDefinitionType = executableMethodsDefinitionWriter.getClassType();
        proxyConstructorGenerator.newInstance(executableMethodsDefinitionType);
        proxyConstructorGenerator.dup();
        if (executableMethodsDefinitionWriter.isSupportsInterceptedProxy()) {
            proxyConstructorGenerator.push(true);
            proxyConstructorGenerator.invokeConstructor(executableMethodsDefinitionType, new Method(CONSTRUCTOR_NAME, getConstructorDescriptor(boolean.class)));
        } else {
            proxyConstructorGenerator.invokeConstructor(executableMethodsDefinitionType, new Method(CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR));
        }
        int executableMethodsDefinitionIndex = proxyConstructorGenerator.newLocal(executableMethodsDefinitionType);
        proxyConstructorGenerator.storeLocal(executableMethodsDefinitionIndex, executableMethodsDefinitionType);
        for (int i = 0; i < proxyMethodCount; i++) {
            MethodRef methodRef = proxiedMethods.get(i);
            int methodIndex = methodRef.methodIndex;
            boolean introduction = isIntroduction && (executableMethodsDefinitionWriter.isAbstract(methodIndex) || (executableMethodsDefinitionWriter.isInterface(methodIndex) && !executableMethodsDefinitionWriter.isDefault(methodIndex)));
            // The following will initialize the array of $proxyMethod instances
            // Eg. this.proxyMethods[0] = new $blah0();
            proxyConstructorGenerator.loadThis();
            proxyConstructorGenerator.getField(proxyType, FIELD_PROXY_METHODS, FIELD_TYPE_PROXY_METHODS);
            proxyConstructorGenerator.push(i);
            // getExecutableMethodByIndex
            proxyConstructorGenerator.loadLocal(executableMethodsDefinitionIndex);
            proxyConstructorGenerator.push(methodIndex);
            proxyConstructorGenerator.invokeVirtual(executableMethodsDefinitionType, ExecutableMethodsDefinitionWriter.GET_EXECUTABLE_AT_INDEX_METHOD);
            proxyConstructorGenerator.visitInsn(AASTORE);
            pushResolveInterceptorsCall(proxyConstructorGenerator, i, introduction);
        }
    }
    for (Runnable fieldInjectionPoint : deferredInjectionPoints) {
        fieldInjectionPoint.run();
    }
    constructorWriter.visitInsn(RETURN);
    constructorWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
    this.constructorWriter.visitEnd();
    proxyBeanDefinitionWriter.visitBeanDefinitionEnd();
    if (targetDefinitionGenerator != null) {
        targetDefinitionGenerator.visitMaxs(1, 1);
        targetDefinitionGenerator.visitEnd();
    }
    if (targetTypeGenerator != null) {
        targetTypeGenerator.visitMaxs(1, 1);
        targetTypeGenerator.visitEnd();
    }
    proxyClassWriter.visitEnd();
}
Also used : ClassVisitor(org.objectweb.asm.ClassVisitor) InterceptedProxy(io.micronaut.aop.InterceptedProxy) HotSwappableInterceptedProxy(io.micronaut.aop.HotSwappableInterceptedProxy) BeanDefinitionWriter(io.micronaut.inject.writer.BeanDefinitionWriter) HotSwappableInterceptedProxy(io.micronaut.aop.HotSwappableInterceptedProxy) ReadWriteLock(java.util.concurrent.locks.ReadWriteLock) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) Qualifier(io.micronaut.context.Qualifier) ParameterElement(io.micronaut.inject.ast.ParameterElement) ExecutableMethodsDefinitionWriter(io.micronaut.inject.writer.ExecutableMethodsDefinitionWriter) ExecutionHandleLocator(io.micronaut.context.ExecutionHandleLocator) ExecutableMethod(io.micronaut.inject.ExecutableMethod) Method(org.objectweb.asm.commons.Method) ClassWriter(org.objectweb.asm.ClassWriter) ReadWriteLock(java.util.concurrent.locks.ReadWriteLock) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) Lock(java.util.concurrent.locks.Lock) Type(org.objectweb.asm.Type) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) BeanResolutionContext(io.micronaut.context.BeanResolutionContext)

Example 12 with ParameterElement

use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.

the class BeanDefinitionWriter method createParameterArray.

private int createParameterArray(List<ParameterElement> parameters, GeneratorAdapter buildMethodVisitor) {
    final int pLen = parameters.size();
    pushNewArray(buildMethodVisitor, Object.class, pLen);
    for (int i = 0; i < pLen; i++) {
        final ParameterElement parameter = parameters.get(i);
        int parameterIndex = i;
        pushStoreInArray(buildMethodVisitor, i, pLen, () -> pushConstructorArgument(buildMethodVisitor, parameter.getName(), parameter, parameter.getAnnotationMetadata(), parameterIndex));
    }
    int local = buildMethodVisitor.newLocal(Type.getType(Object[].class));
    buildMethodVisitor.storeLocal(local);
    return local;
}
Also used : ParameterElement(io.micronaut.inject.ast.ParameterElement) AbstractConstructorInjectionPoint(io.micronaut.context.AbstractConstructorInjectionPoint) ConstructorInjectionPoint(io.micronaut.inject.ConstructorInjectionPoint)

Example 13 with ParameterElement

use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.

the class DispatchWriter method buildGetTargetMethodByIndex.

/**
 * Build get target method by index method if needed.
 *
 * @param classWriter The classwriter
 */
public void buildGetTargetMethodByIndex(ClassWriter classWriter) {
    GeneratorAdapter getTargetMethodByIndex = new GeneratorAdapter(classWriter.visitMethod(Opcodes.ACC_PROTECTED | Opcodes.ACC_FINAL, GET_TARGET_METHOD.getName(), GET_TARGET_METHOD.getDescriptor(), null, null), ACC_PROTECTED | Opcodes.ACC_FINAL, GET_TARGET_METHOD.getName(), GET_TARGET_METHOD.getDescriptor());
    getTargetMethodByIndex.loadArg(0);
    int[] cases = dispatchTargets.stream().filter(dispatchTarget -> dispatchTarget instanceof MethodDispatchTarget).mapToInt(dispatchTargets::indexOf).toArray();
    getTargetMethodByIndex.tableSwitch(cases, new TableSwitchGenerator() {

        @Override
        public void generateCase(int key, Label end) {
            MethodDispatchTarget method = (MethodDispatchTarget) dispatchTargets.get(key);
            Type declaringTypeObject = JavaModelUtils.getTypeReference(method.declaringType);
            List<ParameterElement> argumentTypes = Arrays.asList(method.methodElement.getSuspendParameters());
            getTargetMethodByIndex.push(declaringTypeObject);
            getTargetMethodByIndex.push(method.methodElement.getName());
            if (!argumentTypes.isEmpty()) {
                int len = argumentTypes.size();
                Iterator<ParameterElement> iter = argumentTypes.iterator();
                pushNewArray(getTargetMethodByIndex, Class.class, len);
                for (int i = 0; i < len; i++) {
                    ParameterElement type = iter.next();
                    pushStoreInArray(getTargetMethodByIndex, i, len, () -> getTargetMethodByIndex.push(JavaModelUtils.getTypeReference(type)));
                }
            } else {
                getTargetMethodByIndex.getStatic(TYPE_REFLECTION_UTILS, "EMPTY_CLASS_ARRAY", Type.getType(Class[].class));
            }
            getTargetMethodByIndex.invokeStatic(TYPE_REFLECTION_UTILS, METHOD_GET_REQUIRED_METHOD);
            getTargetMethodByIndex.returnValue();
        }

        @Override
        public void generateDefault() {
            getTargetMethodByIndex.loadThis();
            getTargetMethodByIndex.loadArg(0);
            getTargetMethodByIndex.invokeVirtual(thisType, UNKNOWN_DISPATCH_AT_INDEX);
            getTargetMethodByIndex.throwException();
        }
    }, true);
    getTargetMethodByIndex.visitMaxs(DEFAULT_MAX_STACK, 1);
    getTargetMethodByIndex.visitEnd();
}
Also used : Type(org.objectweb.asm.Type) TableSwitchGenerator(org.objectweb.asm.commons.TableSwitchGenerator) Label(org.objectweb.asm.Label) Iterator(java.util.Iterator) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ArrayList(java.util.ArrayList) List(java.util.List) ParameterElement(io.micronaut.inject.ast.ParameterElement)

Example 14 with ParameterElement

use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.

the class ExecutableMethodWriter method buildInvokeMethod.

/**
 * @param declaringTypeObject The declaring object type
 * @param methodName          The method name
 * @param returnType          The return type
 * @param argumentTypes       The argument types
 * @param invokeMethodVisitor The invoke method visitor
 */
protected void buildInvokeMethod(Type declaringTypeObject, String methodName, ClassElement returnType, Collection<ParameterElement> argumentTypes, GeneratorAdapter invokeMethodVisitor) {
    Type returnTypeObject = JavaModelUtils.getTypeReference(returnType);
    // load this
    invokeMethodVisitor.visitVarInsn(ALOAD, 1);
    // duplicate target
    invokeMethodVisitor.dup();
    String methodDescriptor = getMethodDescriptor(returnType, argumentTypes);
    if (interceptedProxyClassName != null) {
        Label invokeTargetBlock = new Label();
        Type interceptedProxyType = getObjectType(interceptedProxyClassName);
        // load this.$interceptable field value
        invokeMethodVisitor.loadThis();
        invokeMethodVisitor.getField(Type.getObjectType(internalName), FIELD_INTERCEPTABLE, Type.getType(boolean.class));
        // check if it equals true
        invokeMethodVisitor.push(true);
        invokeMethodVisitor.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.NE, invokeTargetBlock);
        // target instanceOf intercepted proxy
        invokeMethodVisitor.loadArg(0);
        invokeMethodVisitor.instanceOf(interceptedProxyType);
        // check if instanceOf
        invokeMethodVisitor.push(true);
        invokeMethodVisitor.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.NE, invokeTargetBlock);
        pushCastToType(invokeMethodVisitor, interceptedProxyType);
        // load arguments
        Iterator<ParameterElement> iterator = argumentTypes.iterator();
        for (int i = 0; i < argumentTypes.size(); i++) {
            invokeMethodVisitor.loadArg(1);
            invokeMethodVisitor.push(i);
            invokeMethodVisitor.visitInsn(AALOAD);
            pushCastToType(invokeMethodVisitor, iterator.next());
        }
        invokeMethodVisitor.visitMethodInsn(INVOKEVIRTUAL, interceptedProxyType.getInternalName(), interceptedProxyBridgeMethodName, methodDescriptor, false);
        if (returnTypeObject.equals(Type.VOID_TYPE)) {
            invokeMethodVisitor.visitInsn(ACONST_NULL);
        } else {
            pushBoxPrimitiveIfNecessary(returnType, invokeMethodVisitor);
        }
        invokeMethodVisitor.visitInsn(ARETURN);
        invokeMethodVisitor.visitLabel(invokeTargetBlock);
        // remove parent
        invokeMethodVisitor.pop();
    }
    pushCastToType(invokeMethodVisitor, declaringTypeObject);
    boolean hasArgs = !argumentTypes.isEmpty();
    if (hasArgs) {
        int argCount = argumentTypes.size();
        Iterator<ParameterElement> argIterator = argumentTypes.iterator();
        for (int i = 0; i < argCount; i++) {
            invokeMethodVisitor.visitVarInsn(ALOAD, 2);
            invokeMethodVisitor.push(i);
            invokeMethodVisitor.visitInsn(AALOAD);
            // cast the return value to the correct type
            pushCastToType(invokeMethodVisitor, argIterator.next());
        }
    }
    invokeMethodVisitor.visitMethodInsn(isInterface ? INVOKEINTERFACE : INVOKEVIRTUAL, declaringTypeObject.getInternalName(), methodName, methodDescriptor, isInterface);
    if (returnTypeObject.equals(Type.VOID_TYPE)) {
        invokeMethodVisitor.visitInsn(ACONST_NULL);
    } else {
        pushBoxPrimitiveIfNecessary(returnType, invokeMethodVisitor);
    }
    invokeMethodVisitor.visitInsn(ARETURN);
    invokeMethodVisitor.visitMaxs(DEFAULT_MAX_STACK, 1);
    invokeMethodVisitor.visitEnd();
}
Also used : Type(org.objectweb.asm.Type) Label(org.objectweb.asm.Label) ParameterElement(io.micronaut.inject.ast.ParameterElement)

Example 15 with ParameterElement

use of io.micronaut.inject.ast.ParameterElement in project micronaut-core by micronaut-projects.

the class ExecutableMethodWriter method visitMethod.

/**
 * Write the method.
 *
 * @param declaringType              The declaring type
 * @param methodElement              The method element
 */
public void visitMethod(TypedElement declaringType, MethodElement methodElement) {
    String methodName = methodElement.getName();
    List<ParameterElement> argumentTypes = Arrays.asList(methodElement.getSuspendParameters());
    Type declaringTypeObject = JavaModelUtils.getTypeReference(declaringType);
    boolean hasArgs = !argumentTypes.isEmpty();
    classWriter.visit(V1_8, ACC_SYNTHETIC, internalName, null, Type.getInternalName(AbstractExecutableMethod.class), null);
    classWriter.visitAnnotation(TYPE_GENERATED.getDescriptor(), false);
    // initialize and write the annotation metadata
    if (!(annotationMetadata instanceof AnnotationMetadataReference)) {
        writeAnnotationMetadataStaticInitializer(classWriter);
    }
    writeGetAnnotationMetadataMethod(classWriter);
    MethodVisitor executorMethodConstructor;
    GeneratorAdapter constructorWriter;
    if (interceptedProxyBridgeMethodName != null) {
        // Create default constructor call other one with 'false'
        String descriptor = Type.getDescriptor(boolean.class);
        classWriter.visitField(ACC_FINAL | ACC_PRIVATE, FIELD_INTERCEPTABLE, descriptor, null, null);
        GeneratorAdapter defaultConstructorWriter = new GeneratorAdapter(startConstructor(classWriter), Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR);
        String executorMethodConstructorDescriptor = getConstructorDescriptor(boolean.class);
        executorMethodConstructor = startConstructor(classWriter, boolean.class);
        constructorWriter = new GeneratorAdapter(executorMethodConstructor, Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, executorMethodConstructorDescriptor);
        defaultConstructorWriter.loadThis();
        defaultConstructorWriter.push(false);
        defaultConstructorWriter.visitMethodInsn(INVOKESPECIAL, internalName, CONSTRUCTOR_NAME, executorMethodConstructorDescriptor, false);
        defaultConstructorWriter.visitInsn(RETURN);
        defaultConstructorWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
        constructorWriter.loadThis();
        constructorWriter.loadArg(0);
        constructorWriter.putField(Type.getObjectType(internalName), FIELD_INTERCEPTABLE, Type.getType(boolean.class));
    } else {
        executorMethodConstructor = startConstructor(classWriter);
        constructorWriter = new GeneratorAdapter(executorMethodConstructor, Opcodes.ACC_PUBLIC, CONSTRUCTOR_NAME, DESCRIPTOR_DEFAULT_CONSTRUCTOR);
    }
    // ALOAD 0
    constructorWriter.loadThis();
    // load 'this'
    constructorWriter.loadThis();
    // 1st argument: the declaring class
    constructorWriter.push(declaringTypeObject);
    // 2nd argument: the method name
    constructorWriter.push(methodName);
    // 3rd argument the generic return type
    ClassElement genericReturnType = methodElement.getGenericReturnType();
    if (genericReturnType.isPrimitive() && !genericReturnType.isArray()) {
        String constantName = genericReturnType.getName().toUpperCase(Locale.ENGLISH);
        // refer to constant for primitives
        Type type = Type.getType(Argument.class);
        constructorWriter.getStatic(type, constantName, type);
    } else {
        pushCreateArgument(declaringType.getName(), methodType, classWriter, constructorWriter, genericReturnType.getName(), genericReturnType, genericReturnType.getAnnotationMetadata(), genericReturnType.getTypeArguments(), new HashMap<>(), loadTypeMethods);
    }
    if (hasArgs) {
        // 4th argument: the generic types
        pushBuildArgumentsForMethod(methodType.getClassName(), methodType, classWriter, constructorWriter, argumentTypes, new HashMap<>(), loadTypeMethods);
        for (ParameterElement pe : argumentTypes) {
            DefaultAnnotationMetadata.contributeDefaults(this.annotationMetadata, pe.getAnnotationMetadata());
            DefaultAnnotationMetadata.contributeRepeatable(this.annotationMetadata, pe.getGenericType());
        }
        // now invoke super(..) if no arg constructor
        invokeConstructor(executorMethodConstructor, AbstractExecutableMethod.class, Class.class, String.class, Argument.class, Argument[].class);
    } else {
        invokeConstructor(executorMethodConstructor, AbstractExecutableMethod.class, Class.class, String.class, Argument.class);
    }
    constructorWriter.visitInsn(RETURN);
    constructorWriter.visitMaxs(DEFAULT_MAX_STACK, 1);
    // add isAbstract method
    GeneratorAdapter isAbstractMethod = new GeneratorAdapter(classWriter.visitMethod(ACC_PUBLIC | ACC_FINAL, METHOD_IS_ABSTRACT.getName(), METHOD_IS_ABSTRACT.getDescriptor(), null, null), ACC_PUBLIC, METHOD_IS_ABSTRACT.getName(), METHOD_IS_ABSTRACT.getDescriptor());
    isAbstractMethod.push(isAbstract());
    isAbstractMethod.returnValue();
    isAbstractMethod.visitMaxs(1, 1);
    isAbstractMethod.endMethod();
    // add isSuspend method
    GeneratorAdapter isSuspendMethod = new GeneratorAdapter(classWriter.visitMethod(ACC_PUBLIC | ACC_FINAL, METHOD_IS_SUSPEND.getName(), METHOD_IS_SUSPEND.getDescriptor(), null, null), ACC_PUBLIC, METHOD_IS_SUSPEND.getName(), METHOD_IS_SUSPEND.getDescriptor());
    isSuspendMethod.push(isSuspend());
    isSuspendMethod.returnValue();
    isSuspendMethod.visitMaxs(1, 1);
    isSuspendMethod.endMethod();
    // invoke the methods with the passed arguments
    String invokeDescriptor = METHOD_INVOKE_INTERNAL.getDescriptor();
    String invokeInternalName = METHOD_INVOKE_INTERNAL.getName();
    GeneratorAdapter invokeMethod = new GeneratorAdapter(classWriter.visitMethod(Opcodes.ACC_PUBLIC, invokeInternalName, invokeDescriptor, null, null), ACC_PUBLIC, invokeInternalName, invokeDescriptor);
    ClassElement returnType = methodElement.isSuspend() ? ClassElement.of(Object.class) : methodElement.getReturnType();
    buildInvokeMethod(declaringTypeObject, methodName, returnType, argumentTypes, invokeMethod);
    buildResolveTargetMethod(methodName, declaringTypeObject, hasArgs, argumentTypes);
    for (GeneratorAdapter method : loadTypeMethods.values()) {
        method.visitMaxs(3, 1);
        method.visitEnd();
    }
}
Also used : Argument(io.micronaut.core.type.Argument) AnnotationMetadataReference(io.micronaut.inject.annotation.AnnotationMetadataReference) ClassElement(io.micronaut.inject.ast.ClassElement) MethodVisitor(org.objectweb.asm.MethodVisitor) Type(org.objectweb.asm.Type) AbstractExecutableMethod(io.micronaut.context.AbstractExecutableMethod) GeneratorAdapter(org.objectweb.asm.commons.GeneratorAdapter) ParameterElement(io.micronaut.inject.ast.ParameterElement)

Aggregations

ParameterElement (io.micronaut.inject.ast.ParameterElement)32 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)13 ClassElement (io.micronaut.inject.ast.ClassElement)13 Type (org.objectweb.asm.Type)13 GeneratorAdapter (org.objectweb.asm.commons.GeneratorAdapter)13 DefaultAnnotationMetadata (io.micronaut.inject.annotation.DefaultAnnotationMetadata)12 MethodElement (io.micronaut.inject.ast.MethodElement)9 ArrayList (java.util.ArrayList)8 List (java.util.List)8 AbstractConstructorInjectionPoint (io.micronaut.context.AbstractConstructorInjectionPoint)7 Label (org.objectweb.asm.Label)7 Argument (io.micronaut.core.type.Argument)6 ConstructorInjectionPoint (io.micronaut.inject.ConstructorInjectionPoint)6 MutableAnnotationMetadata (io.micronaut.inject.annotation.MutableAnnotationMetadata)6 TypedElement (io.micronaut.inject.ast.TypedElement)6 Map (java.util.Map)6 AnnotationMetadataReference (io.micronaut.inject.annotation.AnnotationMetadataReference)5 FieldElement (io.micronaut.inject.ast.FieldElement)5 HashMap (java.util.HashMap)5 ClassWriter (org.objectweb.asm.ClassWriter)5