Search in sources :

Example 1 with Type

use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.

the class MethodInliner method putStackValuesIntoLocals.

private static void putStackValuesIntoLocals(@NotNull List<Type> directOrder, int shift, @NotNull InstructionAdapter iv, @NotNull String descriptor) {
    Type[] actualParams = Type.getArgumentTypes(descriptor);
    assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!";
    int size = 0;
    for (Type next : directOrder) {
        size += next.getSize();
    }
    shift += size;
    int index = directOrder.size();
    for (Type next : Lists.reverse(directOrder)) {
        shift -= next.getSize();
        Type typeOnStack = actualParams[--index];
        if (!typeOnStack.equals(next)) {
            StackValue.onStack(typeOnStack).put(next, iv);
        }
        iv.store(shift, next);
    }
}
Also used : Type(org.jetbrains.org.objectweb.asm.Type)

Example 2 with Type

use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.

the class MethodInliner method doInline.

@NotNull
private MethodNode doInline(@NotNull MethodNode node) {
    final Deque<InvokeCall> currentInvokes = new LinkedList<InvokeCall>(invokeCalls);
    final MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
    final Iterator<TransformationInfo> iterator = transformations.iterator();
    final TypeRemapper remapper = TypeRemapper.createFrom(currentTypeMapping);
    final RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode, new AsmTypeRemapper(remapper, inliningContext.getRoot().typeParameterMappings == null, result));
    final int markerShift = InlineCodegenUtil.calcMarkerShift(parameters, node);
    InlineAdapter lambdaInliner = new InlineAdapter(remappingMethodAdapter, parameters.getArgsSizeOnStack(), sourceMapper) {

        private TransformationInfo transformationInfo;

        private void handleAnonymousObjectRegeneration() {
            transformationInfo = iterator.next();
            String oldClassName = transformationInfo.getOldClassName();
            if (transformationInfo.shouldRegenerate(isSameModule)) {
                //TODO: need poping of type but what to do with local funs???
                String newClassName = transformationInfo.getNewClassName();
                remapper.addMapping(oldClassName, newClassName);
                InliningContext childInliningContext = inliningContext.subInlineWithClassRegeneration(inliningContext.nameGenerator, currentTypeMapping, inlineCallSiteInfo);
                ObjectTransformer transformer = transformationInfo.createTransformer(childInliningContext, isSameModule);
                InlineResult transformResult = transformer.doTransform(nodeRemapper);
                result.merge(transformResult);
                result.addChangedType(oldClassName, newClassName);
                if (inliningContext.isInliningLambda && transformationInfo.canRemoveAfterTransformation()) {
                    // this class is transformed and original not used so we should remove original one after inlining
                    result.addClassToRemove(oldClassName);
                }
                if (transformResult.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
                    ReifiedTypeInliner.putNeedClassReificationMarker(mv);
                    result.getReifiedTypeParametersUsages().mergeAll(transformResult.getReifiedTypeParametersUsages());
                }
            } else if (!transformationInfo.getWasAlreadyRegenerated()) {
                result.addNotChangedClass(oldClassName);
            }
        }

        @Override
        public void anew(@NotNull Type type) {
            if (isAnonymousClass(type.getInternalName())) {
                handleAnonymousObjectRegeneration();
            }
            //in case of regenerated transformationInfo type would be remapped to new one via remappingMethodAdapter
            super.anew(type);
        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
            if (/*INLINE_RUNTIME.equals(owner) &&*/
            isInvokeOnLambda(owner, name)) {
                //TODO add method
                assert !currentInvokes.isEmpty();
                InvokeCall invokeCall = currentInvokes.remove();
                LambdaInfo info = invokeCall.lambdaInfo;
                if (info == null) {
                    //noninlinable lambda
                    super.visitMethodInsn(opcode, owner, name, desc, itf);
                    return;
                }
                //NB: don't inline cause it changes
                int valueParamShift = Math.max(getNextLocalIndex(), markerShift);
                putStackValuesIntoLocals(info.getInvokeParamsWithoutCaptured(), valueParamShift, this, desc);
                if (invokeCall.lambdaInfo.getFunctionDescriptor().getValueParameters().isEmpty()) {
                    // There won't be no parameters processing and line call can be left without actual instructions.
                    // Note: if function is called on the line with other instructions like 1 + foo(), 'nop' will still be generated.
                    visitInsn(Opcodes.NOP);
                }
                addInlineMarker(this, true);
                Parameters lambdaParameters = info.addAllParameters(nodeRemapper);
                InlinedLambdaRemapper newCapturedRemapper = new InlinedLambdaRemapper(info.getLambdaClassType().getInternalName(), nodeRemapper, lambdaParameters);
                setLambdaInlining(true);
                SMAP lambdaSMAP = info.getNode().getClassSMAP();
                //noinspection ConstantConditions
                SourceMapper mapper = inliningContext.classRegeneration && !inliningContext.isInliningLambda ? new NestedSourceMapper(sourceMapper, lambdaSMAP.getIntervals(), lambdaSMAP.getSourceInfo()) : new InlineLambdaSourceMapper(sourceMapper.getParent(), info.getNode());
                MethodInliner inliner = new MethodInliner(info.getNode().getNode(), lambdaParameters, inliningContext.subInlineLambda(info), newCapturedRemapper, true, /*cause all calls in same module as lambda*/
                "Lambda inlining " + info.getLambdaClassType().getInternalName(), mapper, inlineCallSiteInfo, null);
                LocalVarRemapper remapper = new LocalVarRemapper(lambdaParameters, valueParamShift);
                //TODO add skipped this and receiver
                InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info, invokeCall.finallyDepthShift);
                result.mergeWithNotChangeInfo(lambdaResult);
                result.getReifiedTypeParametersUsages().mergeAll(lambdaResult.getReifiedTypeParametersUsages());
                //return value boxing/unboxing
                Method bridge = typeMapper.mapAsmMethod(ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor()));
                Method delegate = typeMapper.mapAsmMethod(info.getFunctionDescriptor());
                StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
                setLambdaInlining(false);
                addInlineMarker(this, false);
                mapper.endMapping();
                if (inlineOnlySmapSkipper != null) {
                    inlineOnlySmapSkipper.markCallSiteLineNumber(remappingMethodAdapter);
                }
            } else if (isAnonymousConstructorCall(owner, name)) {
                //TODO add proper message
                assert transformationInfo instanceof AnonymousObjectTransformationInfo : "<init> call doesn't correspond to object transformation info: " + owner + "." + name + ", info " + transformationInfo;
                InliningContext parent = inliningContext.getParent();
                boolean shouldRegenerate = transformationInfo.shouldRegenerate(isSameModule);
                boolean isContinuation = parent != null && parent.isContinuation();
                if (shouldRegenerate || isContinuation) {
                    assert shouldRegenerate || inlineCallSiteInfo.getOwnerClassName().equals(transformationInfo.getOldClassName()) : "Only coroutines can call their own constructors";
                    //put additional captured parameters on stack
                    AnonymousObjectTransformationInfo info = (AnonymousObjectTransformationInfo) transformationInfo;
                    AnonymousObjectTransformationInfo oldInfo = inliningContext.findAnonymousObjectTransformationInfo(owner);
                    if (oldInfo != null && isContinuation) {
                        info = oldInfo;
                    }
                    for (CapturedParamDesc capturedParamDesc : info.getAllRecapturedParameters()) {
                        visitFieldInsn(Opcodes.GETSTATIC, capturedParamDesc.getContainingLambdaName(), "$$$" + capturedParamDesc.getFieldName(), capturedParamDesc.getType().getDescriptor());
                    }
                    super.visitMethodInsn(opcode, info.getNewClassName(), name, info.getNewConstructorDescriptor(), itf);
                    //TODO: add new inner class also for other contexts
                    if (inliningContext.getParent() instanceof RegeneratedClassContext) {
                        inliningContext.getParent().typeRemapper.addAdditionalMappings(transformationInfo.getOldClassName(), transformationInfo.getNewClassName());
                    }
                    transformationInfo = null;
                } else {
                    super.visitMethodInsn(opcode, owner, name, desc, itf);
                }
            } else if (!inliningContext.isInliningLambda && ReifiedTypeInliner.isNeedClassReificationMarker(new MethodInsnNode(opcode, owner, name, desc, false))) {
            //we shouldn't process here content of inlining lambda it should be reified at external level
            } else {
                super.visitMethodInsn(opcode, owner, name, desc, itf);
            }
        }

        @Override
        public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
            if (opcode == Opcodes.GETSTATIC && (isAnonymousSingletonLoad(owner, name) || isWhenMappingAccess(owner, name))) {
                handleAnonymousObjectRegeneration();
            }
            super.visitFieldInsn(opcode, owner, name, desc);
        }

        @Override
        public void visitMaxs(int stack, int locals) {
            lambdasFinallyBlocks = resultNode.tryCatchBlocks.size();
            super.visitMaxs(stack, locals);
        }
    };
    node.accept(lambdaInliner);
    return resultNode;
}
Also used : RemappingMethodAdapter(org.jetbrains.org.objectweb.asm.commons.RemappingMethodAdapter) NotNull(org.jetbrains.annotations.NotNull) Method(org.jetbrains.org.objectweb.asm.commons.Method) Type(org.jetbrains.org.objectweb.asm.Type) NotNull(org.jetbrains.annotations.NotNull)

Example 3 with Type

use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.

the class MethodInliner method prepareNode.

@NotNull
private MethodNode prepareNode(@NotNull MethodNode node, int finallyDeepShift) {
    final int capturedParamsSize = parameters.getCapturedParametersSizeOnStack();
    final int realParametersSize = parameters.getRealParametersSizeOnStack();
    Type[] types = Type.getArgumentTypes(node.desc);
    Type returnType = Type.getReturnType(node.desc);
    List<Type> capturedTypes = parameters.getCapturedTypes();
    Type[] allTypes = ArrayUtil.mergeArrays(types, capturedTypes.toArray(new Type[capturedTypes.size()]));
    node.instructions.resetLabels();
    MethodNode transformedNode = new MethodNode(InlineCodegenUtil.API, node.access, node.name, Type.getMethodDescriptor(returnType, allTypes), node.signature, null) {

        @SuppressWarnings("ConstantConditions")
        private final boolean GENERATE_DEBUG_INFO = InlineCodegenUtil.GENERATE_SMAP && inlineOnlySmapSkipper == null;

        private final boolean isInliningLambda = nodeRemapper.isInsideInliningLambda();

        private int getNewIndex(int var) {
            return var + (var < realParametersSize ? 0 : capturedParamsSize);
        }

        @Override
        public void visitVarInsn(int opcode, int var) {
            super.visitVarInsn(opcode, getNewIndex(var));
        }

        @Override
        public void visitIincInsn(int var, int increment) {
            super.visitIincInsn(getNewIndex(var), increment);
        }

        @Override
        public void visitMaxs(int maxStack, int maxLocals) {
            super.visitMaxs(maxStack, maxLocals + capturedParamsSize);
        }

        @Override
        public void visitLineNumber(int line, @NotNull Label start) {
            if (isInliningLambda || GENERATE_DEBUG_INFO) {
                super.visitLineNumber(line, start);
            }
        }

        @Override
        public void visitLocalVariable(@NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index) {
            if (isInliningLambda || GENERATE_DEBUG_INFO) {
                String varSuffix = inliningContext.isRoot() && !InlineCodegenUtil.isFakeLocalVariableForInline(name) ? INLINE_FUN_VAR_SUFFIX : "";
                String varName = !varSuffix.isEmpty() && name.equals("this") ? name + "_" : name;
                super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index));
            }
        }
    };
    node.accept(transformedNode);
    transformCaptured(transformedNode);
    transformFinallyDeepIndex(transformedNode, finallyDeepShift);
    return transformedNode;
}
Also used : Type(org.jetbrains.org.objectweb.asm.Type) Label(org.jetbrains.org.objectweb.asm.Label) NotNull(org.jetbrains.annotations.NotNull) NotNull(org.jetbrains.annotations.NotNull)

Example 4 with Type

use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.

the class KotlinTypeMapper method mapToCallableMethod.

@NotNull
public CallableMethod mapToCallableMethod(@NotNull FunctionDescriptor descriptor, boolean superCall) {
    if (descriptor instanceof ConstructorDescriptor) {
        JvmMethodSignature method = mapSignatureSkipGeneric(descriptor.getOriginal());
        Type owner = mapOwner(descriptor);
        String defaultImplDesc = mapDefaultMethod(descriptor.getOriginal(), OwnerKind.IMPLEMENTATION).getDescriptor();
        return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null, false);
    }
    if (descriptor instanceof LocalVariableAccessorDescriptor) {
        ResolvedCall<FunctionDescriptor> delegateAccessorResolvedCall = bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, (VariableAccessorDescriptor) descriptor);
        //noinspection ConstantConditions
        return mapToCallableMethod(delegateAccessorResolvedCall.getResultingDescriptor(), false);
    }
    DeclarationDescriptor functionParent = descriptor.getOriginal().getContainingDeclaration();
    FunctionDescriptor functionDescriptor = findSuperDeclaration(descriptor.getOriginal(), superCall);
    JvmMethodSignature signature;
    Type owner;
    Type ownerForDefaultImpl;
    FunctionDescriptor baseMethodDescriptor;
    int invokeOpcode;
    Type thisClass;
    boolean isInterfaceMember = false;
    if (functionParent instanceof ClassDescriptor) {
        FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
        ClassDescriptor currentOwner = (ClassDescriptor) functionParent;
        ClassDescriptor declarationOwner = (ClassDescriptor) declarationFunctionDescriptor.getContainingDeclaration();
        boolean originalIsInterface = isJvmInterface(declarationOwner);
        boolean currentIsInterface = isJvmInterface(currentOwner);
        boolean isInterface = currentIsInterface && originalIsInterface;
        baseMethodDescriptor = findBaseDeclaration(functionDescriptor).getOriginal();
        ClassDescriptor ownerForDefault = (ClassDescriptor) baseMethodDescriptor.getContainingDeclaration();
        ownerForDefaultImpl = isJvmInterface(ownerForDefault) && !isJvm8InterfaceWithDefaults(ownerForDefault) ? mapDefaultImpls(ownerForDefault) : mapClass(ownerForDefault);
        if (isInterface && (superCall || descriptor.getVisibility() == Visibilities.PRIVATE || isAccessor(descriptor))) {
            thisClass = mapClass(currentOwner);
            if (declarationOwner instanceof JavaClassDescriptor || isJvm8InterfaceWithDefaults(declarationOwner)) {
                invokeOpcode = INVOKESPECIAL;
                signature = mapSignatureSkipGeneric(functionDescriptor);
                owner = thisClass;
                isInterfaceMember = true;
            } else {
                invokeOpcode = INVOKESTATIC;
                signature = mapSignatureSkipGeneric(descriptor.getOriginal(), OwnerKind.DEFAULT_IMPLS);
                owner = mapDefaultImpls(currentOwner);
            }
        } else {
            boolean isStaticInvocation = (isStaticDeclaration(functionDescriptor) && !(functionDescriptor instanceof ImportedFromObjectCallableDescriptor)) || isStaticAccessor(functionDescriptor) || CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor);
            if (isStaticInvocation) {
                invokeOpcode = INVOKESTATIC;
                isInterfaceMember = currentIsInterface && currentOwner instanceof JavaClassDescriptor;
            } else if (isInterface) {
                invokeOpcode = INVOKEINTERFACE;
                isInterfaceMember = true;
            } else {
                boolean isPrivateFunInvocation = Visibilities.isPrivate(functionDescriptor.getVisibility());
                invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
                isInterfaceMember = superCall && currentIsInterface;
            }
            FunctionDescriptor overriddenSpecialBuiltinFunction = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(functionDescriptor.getOriginal());
            FunctionDescriptor functionToCall = overriddenSpecialBuiltinFunction != null && !superCall ? overriddenSpecialBuiltinFunction.getOriginal() : functionDescriptor.getOriginal();
            signature = mapSignatureSkipGeneric(functionToCall);
            ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor ? declarationOwner : currentOwner;
            owner = mapClass(receiver);
            thisClass = owner;
        }
    } else {
        signature = mapSignatureSkipGeneric(functionDescriptor.getOriginal());
        owner = mapOwner(functionDescriptor);
        ownerForDefaultImpl = owner;
        baseMethodDescriptor = functionDescriptor;
        if (functionParent instanceof PackageFragmentDescriptor) {
            invokeOpcode = INVOKESTATIC;
            thisClass = null;
        } else if (functionDescriptor instanceof ConstructorDescriptor) {
            invokeOpcode = INVOKESPECIAL;
            thisClass = null;
        } else {
            invokeOpcode = INVOKEVIRTUAL;
            thisClass = owner;
        }
    }
    Type calleeType = isLocalFunction(functionDescriptor) ? owner : null;
    Type receiverParameterType;
    ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getExtensionReceiverParameter();
    if (receiverParameter != null) {
        receiverParameterType = mapType(receiverParameter.getType());
    } else {
        receiverParameterType = null;
    }
    String defaultImplDesc = mapDefaultMethod(baseMethodDescriptor, getKindForDefaultImplCall(baseMethodDescriptor)).getDescriptor();
    return new CallableMethod(owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode, thisClass, receiverParameterType, calleeType, isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE);
}
Also used : LocalVariableAccessorDescriptor(org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor) DeserializedClassDescriptor(org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor) FunctionClassDescriptor(org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor) JavaClassDescriptor(org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor) TypeAliasConstructorDescriptor(org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor) IrBuiltinsPackageFragmentDescriptor(org.jetbrains.kotlin.ir.descriptors.IrBuiltinsPackageFragmentDescriptor) JvmMethodSignature(org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature) FunctionClassDescriptor(org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor) Type(org.jetbrains.org.objectweb.asm.Type) JavaClassDescriptor(org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with Type

use of org.jetbrains.org.objectweb.asm.Type in project kotlin by JetBrains.

the class KotlinTypeMapper method mapDefaultMethod.

@NotNull
public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind) {
    Method jvmSignature = mapAsmMethod(functionDescriptor, kind);
    Type ownerType = mapOwner(functionDescriptor);
    boolean isConstructor = isConstructor(jvmSignature);
    String descriptor = getDefaultDescriptor(jvmSignature, isStaticMethod(kind, functionDescriptor) || isConstructor ? null : ownerType.getDescriptor(), CodegenUtilKt.unwrapFrontendVersion(functionDescriptor));
    return new Method(isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor);
}
Also used : Type(org.jetbrains.org.objectweb.asm.Type) AsmUtil.isStaticMethod(org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod) Method(org.jetbrains.org.objectweb.asm.commons.Method) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

Type (org.jetbrains.org.objectweb.asm.Type)104 KotlinType (org.jetbrains.kotlin.types.KotlinType)66 IElementType (com.intellij.psi.tree.IElementType)45 NotNull (org.jetbrains.annotations.NotNull)23 InstructionAdapter (org.jetbrains.org.objectweb.asm.commons.InstructionAdapter)16 Label (org.jetbrains.org.objectweb.asm.Label)12 Type.getObjectType (org.jetbrains.org.objectweb.asm.Type.getObjectType)10 Method (org.jetbrains.org.objectweb.asm.commons.Method)9 Unit (kotlin.Unit)8 LocalVariableDescriptor (org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor)7 ArrayList (java.util.ArrayList)5 JavaClassDescriptor (org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor)5 MethodVisitor (org.jetbrains.org.objectweb.asm.MethodVisitor)5 PrimitiveType (org.jetbrains.kotlin.builtins.PrimitiveType)4 ValueParameterDescriptor (org.jetbrains.kotlin.descriptors.ValueParameterDescriptor)4 List (java.util.List)3 Nullable (org.jetbrains.annotations.Nullable)3 ScriptDescriptor (org.jetbrains.kotlin.descriptors.ScriptDescriptor)3 InOut (com.intellij.codeInspection.bytecodeAnalysis.Direction.InOut)2 FunctionClassDescriptor (org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor)2