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);
}
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);
}
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);
}
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);
}
}
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;
}
Aggregations