Search in sources :

Example 1 with StackValue

use of org.jetbrains.kotlin.codegen.StackValue in project kotlin by JetBrains.

the class RemapVisitor method visitFieldInsn.

@Override
public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
    if (name.startsWith("$$$") && (nodeRemapper instanceof RegeneratedLambdaFieldRemapper || nodeRemapper.isRoot())) {
        FieldInsnNode fin = new FieldInsnNode(opcode, owner, name, desc);
        StackValue inline = nodeRemapper.getFieldForInline(fin, null);
        assert inline != null : "Captured field should have not null stackValue " + fin;
        inline.put(inline.type, this);
        return;
    }
    super.visitFieldInsn(opcode, owner, name, desc);
}
Also used : StackValue(org.jetbrains.kotlin.codegen.StackValue) FieldInsnNode(org.jetbrains.org.objectweb.asm.tree.FieldInsnNode)

Example 2 with StackValue

use of org.jetbrains.kotlin.codegen.StackValue in project kotlin by JetBrains.

the class AnonymousObjectTransformer method generateConstructorAndFields.

private void generateConstructorAndFields(@NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder allCapturedBuilder, @NotNull ParametersBuilder constructorInlineBuilder, @NotNull FieldRemapper parentRemapper, @NotNull List<CapturedParamInfo> constructorAdditionalFakeParams) {
    List<Type> descTypes = new ArrayList<Type>();
    Parameters constructorParams = constructorInlineBuilder.buildParameters();
    int[] capturedIndexes = new int[constructorParams.getParameters().size()];
    int index = 0;
    int size = 0;
    //complex processing cause it could have super constructor call params
    for (ParameterInfo info : constructorParams) {
        if (!info.isSkipped) {
            //not inlined
            if (info.isCaptured() || info instanceof CapturedParamInfo) {
                capturedIndexes[index] = size;
                index++;
            }
            if (size != 0) {
                //skip this
                descTypes.add(info.getType());
            }
            size += info.getType().getSize();
        }
    }
    String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, descTypes.toArray(new Type[descTypes.size()]));
    //TODO for inline method make public class
    transformationInfo.setNewConstructorDescriptor(constructorDescriptor);
    MethodVisitor constructorVisitor = classBuilder.newMethod(NO_ORIGIN, constructor.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
    final Label newBodyStartLabel = new Label();
    constructorVisitor.visitLabel(newBodyStartLabel);
    //initialize captured fields
    List<NewJavaField> newFieldsWithSkipped = TransformationUtilsKt.getNewFieldsToGenerate(allCapturedBuilder.listCaptured());
    List<FieldInfo> fieldInfoWithSkipped = TransformationUtilsKt.transformToFieldInfo(Type.getObjectType(transformationInfo.getNewClassName()), newFieldsWithSkipped);
    int paramIndex = 0;
    InstructionAdapter capturedFieldInitializer = new InstructionAdapter(constructorVisitor);
    for (int i = 0; i < fieldInfoWithSkipped.size(); i++) {
        FieldInfo fieldInfo = fieldInfoWithSkipped.get(i);
        if (!newFieldsWithSkipped.get(i).getSkip()) {
            AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, capturedIndexes[paramIndex], capturedFieldInitializer);
        }
        paramIndex++;
    }
    //so we need to add them to captured params
    for (CapturedParamInfo info : constructorAdditionalFakeParams) {
        CapturedParamInfo fake = constructorInlineBuilder.addCapturedParamCopy(info);
        if (fake.getLambda() != null) {
            //set remap value to skip this fake (captured with lambda already skipped)
            StackValue composed = StackValue.field(fake.getType(), oldObjectType, fake.getNewFieldName(), false, StackValue.LOCAL_0);
            fake.setRemapValue(composed);
        }
    }
    MethodNode intermediateMethodNode = new MethodNode(constructor.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
    inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor, constructorInlineBuilder, true);
    InlineCodegenUtil.removeFinallyMarkers(intermediateMethodNode);
    AbstractInsnNode first = intermediateMethodNode.instructions.getFirst();
    final Label oldStartLabel = first instanceof LabelNode ? ((LabelNode) first).getLabel() : null;
    intermediateMethodNode.accept(new MethodBodyVisitor(capturedFieldInitializer) {

        @Override
        public void visitLocalVariable(@NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index) {
            if (oldStartLabel == start) {
                //patch for jack&jill
                start = newBodyStartLabel;
            }
            super.visitLocalVariable(name, desc, signature, start, end, index);
        }
    });
    constructorVisitor.visitEnd();
    AsmUtil.genClosureFields(TransformationUtilsKt.toNameTypePair(TransformationUtilsKt.filterSkipped(newFieldsWithSkipped)), classBuilder);
}
Also used : StackValue(org.jetbrains.kotlin.codegen.StackValue) InstructionAdapter(org.jetbrains.org.objectweb.asm.commons.InstructionAdapter) FieldInfo(org.jetbrains.kotlin.codegen.FieldInfo)

Example 3 with StackValue

use of org.jetbrains.kotlin.codegen.StackValue in project kotlin by JetBrains.

the class LocalVarRemapper method doRemap.

@NotNull
private RemapInfo doRemap(int index) {
    int remappedIndex;
    if (index < params.getArgsSizeOnStack()) {
        ParameterInfo info = params.getParameterByDeclarationSlot(index);
        StackValue remapped = remapValues[index];
        if (info.isSkipped || remapped == null) {
            return new RemapInfo(info);
        }
        if (info.isRemapped()) {
            return new RemapInfo(remapped, info, REMAPPED);
        } else {
            remappedIndex = ((StackValue.Local) remapped).index;
        }
    } else {
        //captured params are not used directly in this inlined method, they are used in closure
        remappedIndex = actualParamsSize - params.getArgsSizeOnStack() + index;
    }
    return new RemapInfo(StackValue.local(remappedIndex + additionalShift, AsmTypes.OBJECT_TYPE), null, SHIFT);
}
Also used : StackValue(org.jetbrains.kotlin.codegen.StackValue) NotNull(org.jetbrains.annotations.NotNull)

Example 4 with StackValue

use of org.jetbrains.kotlin.codegen.StackValue in project kotlin by JetBrains.

the class LocalVarRemapper method visitVarInsn.

public void visitVarInsn(int opcode, int var, @NotNull InstructionAdapter mv) {
    RemapInfo remapInfo = remap(var);
    StackValue value = remapInfo.value;
    if (value instanceof StackValue.Local) {
        boolean isStore = InlineCodegenUtil.isStoreInstruction(opcode);
        if (remapInfo.parameterInfo != null) {
            //All remapped value parameters can't be rewritten except case of default ones.
            //On remapping default parameter to actual value there is only one instruction that writes to it according to mask value
            //but if such parameter remapped then it passed and this mask branch code never executed
            //TODO add assertion about parameter default value: descriptor is required
            opcode = value.type.getOpcode(isStore ? Opcodes.ISTORE : Opcodes.ILOAD);
        }
        mv.visitVarInsn(opcode, ((StackValue.Local) value).index);
        if (remapInfo.parameterInfo != null && !isStore) {
            StackValue.coerce(value.type, remapInfo.parameterInfo.type, mv);
        }
    } else {
        assert remapInfo.parameterInfo != null : "Non local value should have parameter info";
        value.put(remapInfo.parameterInfo.type, mv);
    }
}
Also used : StackValue(org.jetbrains.kotlin.codegen.StackValue)

Example 5 with StackValue

use of org.jetbrains.kotlin.codegen.StackValue in project kotlin by JetBrains.

the class AnonymousObjectTransformer method extractParametersMappingAndPatchConstructor.

@NotNull
private List<CapturedParamInfo> extractParametersMappingAndPatchConstructor(@NotNull MethodNode constructor, @NotNull ParametersBuilder capturedParamBuilder, @NotNull ParametersBuilder constructorParamBuilder, @NotNull AnonymousObjectTransformationInfo transformationInfo, @NotNull FieldRemapper parentFieldRemapper) {
    //captured var of inlined parameter
    Set<LambdaInfo> capturedLambdas = new LinkedHashSet<LambdaInfo>();
    List<CapturedParamInfo> constructorAdditionalFakeParams = new ArrayList<CapturedParamInfo>();
    Map<Integer, LambdaInfo> indexToLambda = transformationInfo.getLambdasToInline();
    Set<Integer> capturedParams = new HashSet<Integer>();
    //load captured parameters and patch instruction list (NB: there is also could be object fields)
    AbstractInsnNode cur = constructor.instructions.getFirst();
    while (cur != null) {
        if (cur instanceof FieldInsnNode) {
            FieldInsnNode fieldNode = (FieldInsnNode) cur;
            String fieldName = fieldNode.name;
            if (fieldNode.getOpcode() == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(fieldName)) {
                boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode;
                boolean isPrevPrevVarNode = isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode;
                if (isPrevPrevVarNode) {
                    VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious();
                    if (node.var == 0) {
                        VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious();
                        int varIndex = previous.var;
                        LambdaInfo lambdaInfo = indexToLambda.get(varIndex);
                        String newFieldName = isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values()) ? getNewFieldName(fieldName, true) : fieldName;
                        CapturedParamInfo info = capturedParamBuilder.addCapturedParam(Type.getObjectType(transformationInfo.getOldClassName()), fieldName, newFieldName, Type.getType(fieldNode.desc), lambdaInfo != null, null);
                        if (lambdaInfo != null) {
                            info.setLambda(lambdaInfo);
                            capturedLambdas.add(lambdaInfo);
                        }
                        constructorAdditionalFakeParams.add(info);
                        capturedParams.add(varIndex);
                        constructor.instructions.remove(previous.getPrevious());
                        constructor.instructions.remove(previous);
                        AbstractInsnNode temp = cur;
                        cur = cur.getNext();
                        constructor.instructions.remove(temp);
                        continue;
                    }
                }
            }
        }
        cur = cur.getNext();
    }
    constructorParamBuilder.addThis(oldObjectType, false);
    String constructorDesc = transformationInfo.getConstructorDesc();
    if (constructorDesc == null) {
        // in case of anonymous object with empty closure
        constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE);
    }
    Type[] types = Type.getArgumentTypes(constructorDesc);
    for (Type type : types) {
        LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextParameterOffset());
        ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null);
        parameterInfo.setLambda(info);
        if (capturedParams.contains(parameterInfo.getIndex())) {
            parameterInfo.setCaptured(true);
        } else {
        //otherwise it's super constructor parameter
        }
    }
    //For all inlined lambdas add their captured parameters
    //TODO: some of such parameters could be skipped - we should perform additional analysis
    //captured var of inlined parameter
    Map<String, LambdaInfo> capturedLambdasToInline = new HashMap<String, LambdaInfo>();
    List<CapturedParamDesc> allRecapturedParameters = new ArrayList<CapturedParamDesc>();
    boolean addCapturedNotAddOuter = parentFieldRemapper.isRoot() || (parentFieldRemapper instanceof InlinedLambdaRemapper && parentFieldRemapper.getParent().isRoot());
    Map<String, CapturedParamInfo> alreadyAdded = new HashMap<String, CapturedParamInfo>();
    for (LambdaInfo info : capturedLambdas) {
        if (addCapturedNotAddOuter) {
            for (CapturedParamDesc desc : info.getCapturedVars()) {
                String key = desc.getFieldName() + "$$$" + desc.getType().getClassName();
                CapturedParamInfo alreadyAddedParam = alreadyAdded.get(key);
                CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, alreadyAddedParam != null ? alreadyAddedParam.getNewFieldName() : getNewFieldName(desc.getFieldName(), false), alreadyAddedParam != null);
                StackValue composed = StackValue.field(desc.getType(), oldObjectType, /*TODO owner type*/
                recapturedParamInfo.getNewFieldName(), false, StackValue.LOCAL_0);
                recapturedParamInfo.setRemapValue(composed);
                allRecapturedParameters.add(desc);
                constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()).setRemapValue(composed);
                if (isThis0(desc.getFieldName())) {
                    alreadyAdded.put(key, recapturedParamInfo);
                }
            }
        }
        capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info);
    }
    if (parentFieldRemapper instanceof InlinedLambdaRemapper && !capturedLambdas.isEmpty() && !addCapturedNotAddOuter) {
        //lambda with non InlinedLambdaRemapper already have outer
        FieldRemapper parent = parentFieldRemapper.getParent();
        assert parent instanceof RegeneratedLambdaFieldRemapper;
        Type ownerType = Type.getObjectType(parent.getLambdaInternalName());
        CapturedParamDesc desc = new CapturedParamDesc(ownerType, InlineCodegenUtil.THIS, ownerType);
        CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, InlineCodegenUtil.THIS$0, /*outer lambda/object*/
        false);
        StackValue composed = StackValue.LOCAL_0;
        recapturedParamInfo.setRemapValue(composed);
        allRecapturedParameters.add(desc);
        constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()).setRemapValue(composed);
    }
    transformationInfo.setAllRecapturedParameters(allRecapturedParameters);
    transformationInfo.setCapturedLambdasToInline(capturedLambdasToInline);
    return constructorAdditionalFakeParams;
}
Also used : StackValue(org.jetbrains.kotlin.codegen.StackValue) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

StackValue (org.jetbrains.kotlin.codegen.StackValue)7 NotNull (org.jetbrains.annotations.NotNull)3 FieldInsnNode (org.jetbrains.org.objectweb.asm.tree.FieldInsnNode)2 Nullable (org.jetbrains.annotations.Nullable)1 FieldInfo (org.jetbrains.kotlin.codegen.FieldInfo)1 Label (org.jetbrains.org.objectweb.asm.Label)1 InstructionAdapter (org.jetbrains.org.objectweb.asm.commons.InstructionAdapter)1