Search in sources :

Example 1 with RemappingMethodAdapter

use of org.jetbrains.org.objectweb.asm.commons.RemappingMethodAdapter 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)

Aggregations

NotNull (org.jetbrains.annotations.NotNull)1 Type (org.jetbrains.org.objectweb.asm.Type)1 Method (org.jetbrains.org.objectweb.asm.commons.Method)1 RemappingMethodAdapter (org.jetbrains.org.objectweb.asm.commons.RemappingMethodAdapter)1