Code simplification and clean
~special flag
This commit is contained in:
@@ -1711,7 +1711,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
|
|
||||||
StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false);
|
StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (context.isSpecialStackValue(value) != null) {
|
if (context.isSpecialStackValue(value)) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2348,9 +2348,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean putInLocal = true;
|
|
||||||
StackValue valueIfPresent = null;
|
|
||||||
|
|
||||||
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
|
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
|
||||||
Type parameterType = valueParameterTypes.get(valueParameter.getIndex());
|
Type parameterType = valueParameterTypes.get(valueParameter.getIndex());
|
||||||
if (resolvedValueArgument instanceof ExpressionValueArgument) {
|
if (resolvedValueArgument instanceof ExpressionValueArgument) {
|
||||||
@@ -2362,7 +2359,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
//TODO deparenthisise
|
//TODO deparenthisise
|
||||||
if (callGenerator.isInliningClosure(argumentExpression, valueParameter)) {
|
if (callGenerator.isInliningClosure(argumentExpression, valueParameter)) {
|
||||||
callGenerator.rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType);
|
callGenerator.rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType);
|
||||||
putInLocal = false;
|
|
||||||
} else {
|
} else {
|
||||||
StackValue value = gen(argumentExpression);
|
StackValue value = gen(argumentExpression);
|
||||||
if (callGenerator.shouldPutValue(parameterType, value, valueParameter)) {
|
if (callGenerator.shouldPutValue(parameterType, value, valueParameter)) {
|
||||||
@@ -2373,18 +2369,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
} else if (resolvedValueArgument instanceof DefaultValueArgument) {
|
} else if (resolvedValueArgument instanceof DefaultValueArgument) {
|
||||||
pushDefaultValueOnStack(parameterType, v);
|
pushDefaultValueOnStack(parameterType, v);
|
||||||
mask |= (1 << valueParameter.getIndex());
|
mask |= (1 << valueParameter.getIndex());
|
||||||
|
callGenerator.putInLocal(parameterType, null, valueParameter);
|
||||||
}
|
}
|
||||||
else if (resolvedValueArgument instanceof VarargValueArgument) {
|
else if (resolvedValueArgument instanceof VarargValueArgument) {
|
||||||
VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument;
|
VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument;
|
||||||
genVarargs(valueParameter, valueArgument);
|
genVarargs(valueParameter, valueArgument);
|
||||||
|
callGenerator.putInLocal(parameterType, null, valueParameter);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (putInLocal) {
|
|
||||||
callGenerator.putInLocal(parameterType, valueIfPresent, valueParameter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,17 +104,14 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
|
|||||||
return isInlineClosure;
|
return isInlineClosure;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StackValue isSpecialStackValue(StackValue stackValue) {
|
public boolean isSpecialStackValue(StackValue stackValue) {
|
||||||
if (isInlineClosure && stackValue instanceof StackValue.Composed) {
|
if (isInlineClosure && stackValue instanceof StackValue.Composed) {
|
||||||
StackValue prefix = ((StackValue.Composed) stackValue).prefix;
|
StackValue prefix = ((StackValue.Composed) stackValue).prefix;
|
||||||
StackValue suffix = ((StackValue.Composed) stackValue).suffix;
|
StackValue suffix = ((StackValue.Composed) stackValue).suffix;
|
||||||
if (prefix instanceof StackValue.Local && ((StackValue.Local) prefix).index == 0) {
|
if (prefix instanceof StackValue.Local && ((StackValue.Local) prefix).index == 0) {
|
||||||
if (suffix instanceof StackValue.Field) {
|
return suffix instanceof StackValue.Field;
|
||||||
StackValue.Field field = (StackValue.Field) suffix;
|
|
||||||
return StackValue.field(field.type, field.owner, field.name, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,20 +62,8 @@ public class CapturedParamInfo extends ParameterInfo {
|
|||||||
this.recapturedFrom = recapturedFrom;
|
this.recapturedFrom = recapturedFrom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public CapturedParamInfo newRemapIndex(int newRamapIndex) {
|
|
||||||
return clone(index, newRamapIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CapturedParamInfo newIndex(int newIndex) {
|
public CapturedParamInfo newIndex(int newIndex) {
|
||||||
return clone(newIndex, getRemapIndex());
|
return clone(newIndex, getRemapValue());
|
||||||
}
|
|
||||||
|
|
||||||
public CapturedParamInfo clone(int newIndex, int newRamapIndex) {
|
|
||||||
CapturedParamInfo capturedParamInfo = new CapturedParamInfo(fieldName, type, isSkipped, newIndex, newRamapIndex);
|
|
||||||
capturedParamInfo.setLambda(lambda);
|
|
||||||
capturedParamInfo.setRecapturedFrom(recapturedFrom);
|
|
||||||
return capturedParamInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CapturedParamInfo clone(int newIndex, StackValue newRamapIndex) {
|
public CapturedParamInfo clone(int newIndex, StackValue newRamapIndex) {
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ public class ConstructorInvocation {
|
|||||||
|
|
||||||
private final String ownerInternalName;
|
private final String ownerInternalName;
|
||||||
|
|
||||||
private final Map<Integer, InlinableAccess> access;
|
private final Map<Integer, InvokeCall> access;
|
||||||
|
|
||||||
private boolean isSameModule;
|
private final boolean isSameModule;
|
||||||
|
|
||||||
private Type newLambdaType;
|
private Type newLambdaType;
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ public class ConstructorInvocation {
|
|||||||
|
|
||||||
private Map<String, LambdaInfo> recapturedLambdas;
|
private Map<String, LambdaInfo> recapturedLambdas;
|
||||||
|
|
||||||
ConstructorInvocation(String ownerInternalName, Map<Integer, InlinableAccess> access, boolean isSameModule) {
|
ConstructorInvocation(String ownerInternalName, Map<Integer, InvokeCall> access, boolean isSameModule) {
|
||||||
this.ownerInternalName = ownerInternalName;
|
this.ownerInternalName = ownerInternalName;
|
||||||
this.access = access;
|
this.access = access;
|
||||||
this.isSameModule = isSameModule;
|
this.isSameModule = isSameModule;
|
||||||
@@ -51,7 +51,7 @@ public class ConstructorInvocation {
|
|||||||
return !access.isEmpty() || !isSameModule;
|
return !access.isEmpty() || !isSameModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Integer, InlinableAccess> getAccess() {
|
public Map<Integer, InvokeCall> getAccess() {
|
||||||
return access;
|
return access;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,19 +75,17 @@ public class InlineAdapter extends InstructionAdapter {
|
|||||||
public void visitTryCatchBlock(Label start,
|
public void visitTryCatchBlock(Label start,
|
||||||
Label end, Label handler, String type) {
|
Label end, Label handler, String type) {
|
||||||
if(!isInlining) {
|
if(!isInlining) {
|
||||||
blocks.add(new CatchBlock(start, end,
|
blocks.add(new CatchBlock(start, end, handler, type));
|
||||||
handler, type));
|
}
|
||||||
} else {
|
else {
|
||||||
super.visitTryCatchBlock(start, end,
|
super.visitTryCatchBlock(start, end, handler, type);
|
||||||
handler, type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMaxs(int stack, int locals) {
|
public void visitMaxs(int stack, int locals) {
|
||||||
for (CatchBlock b : blocks) {
|
for (CatchBlock b : blocks) {
|
||||||
super.visitTryCatchBlock(b.start, b.end,
|
super.visitTryCatchBlock(b.start, b.end, b.handler, b.type);
|
||||||
b.handler, b.type);
|
|
||||||
}
|
}
|
||||||
super.visitMaxs(stack, locals);
|
super.visitMaxs(stack, locals);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,8 +89,6 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
|
|||||||
|
|
||||||
protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
|
protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
|
||||||
|
|
||||||
private SimpleFunctionDescriptor inlineFunctionDescriptor;
|
|
||||||
|
|
||||||
public InlineCodegen(
|
public InlineCodegen(
|
||||||
@NotNull ExpressionCodegen codegen,
|
@NotNull ExpressionCodegen codegen,
|
||||||
@NotNull GenerationState state,
|
@NotNull GenerationState state,
|
||||||
@@ -98,7 +96,6 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
|
|||||||
@NotNull Call call
|
@NotNull Call call
|
||||||
) {
|
) {
|
||||||
assert functionDescriptor.getInlineStrategy().isInline() : "InlineCodegen could inline only inline function but " + functionDescriptor;
|
assert functionDescriptor.getInlineStrategy().isInline() : "InlineCodegen could inline only inline function but " + functionDescriptor;
|
||||||
inlineFunctionDescriptor = functionDescriptor;
|
|
||||||
|
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.typeMapper = state.getTypeMapper();
|
this.typeMapper = state.getTypeMapper();
|
||||||
@@ -117,7 +114,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
|
|||||||
this.asFunctionInline = false;
|
this.asFunctionInline = false;
|
||||||
|
|
||||||
isSameModule = !(functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) /*not compiled library*/ &&
|
isSameModule = !(functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) /*not compiled library*/ &&
|
||||||
CodegenUtil.isCallInsideSameModuleAsDeclared(inlineFunctionDescriptor, codegen.getContext());
|
CodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -262,26 +259,21 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
|
|||||||
|
|
||||||
if (index >= 0 && couldBeRemapped) {
|
if (index >= 0 && couldBeRemapped) {
|
||||||
CapturedParamInfo capturedParamInfo = activeLambda.getCapturedVars().get(index);
|
CapturedParamInfo capturedParamInfo = activeLambda.getCapturedVars().get(index);
|
||||||
capturedParamInfo.setRemapIndex(remappedIndex != null ? remappedIndex : StackValue.local(info.getIndex(), info.getType()));
|
capturedParamInfo.setRemapValue(remappedIndex != null ? remappedIndex : StackValue.local(info.getIndex(), info.getType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
doWithParameter(info);
|
doWithParameter(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*descriptor is null for captured vars*/
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldPutValue(
|
public boolean shouldPutValue(
|
||||||
@NotNull Type type,
|
@NotNull Type type,
|
||||||
@Nullable StackValue stackValue,
|
@Nullable StackValue stackValue,
|
||||||
ValueParameterDescriptor descriptor
|
@Nullable ValueParameterDescriptor descriptor
|
||||||
) {
|
) {
|
||||||
//boolean isInline = true/*context.isInlineFunction() || context.getParentContext() instanceof ClosureContext*/;
|
|
||||||
//if (stackValue != null && isInline && stackValue instanceof StackValue.Local) {
|
|
||||||
// if (isInvokeOnInlinable(type.getClassName(), "invoke") && (descriptor == null || !InlineUtil.hasNoinlineAnnotation(descriptor))) {
|
|
||||||
// //TODO remap only inlinable closure => otherwise we could get a lot of problem
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (stackValue == null) {
|
if (stackValue == null) {
|
||||||
//default or vararg
|
//default or vararg
|
||||||
@@ -299,22 +291,13 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codegen.getContext().isInlineClosure() && codegen.getContext().getContextDescriptor() instanceof AnonymousFunctionDescriptor) {
|
if (stackValue instanceof StackValue.Composed) {
|
||||||
Type internalName = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) codegen.getContext().getContextDescriptor());
|
//see: Method.isSpecialStackValue: go through aload 0
|
||||||
|
if (codegen.getContext().isInlineClosure() && codegen.getContext().getContextDescriptor() instanceof AnonymousFunctionDescriptor) {
|
||||||
String owner = null;
|
if (descriptor != null && !InlineUtil.hasNoinlineAnnotation(descriptor)) {
|
||||||
if (stackValue instanceof StackValue.Field) {
|
//TODO: check type of context
|
||||||
owner = ((StackValue.Field) stackValue).owner.getInternalName();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackValue instanceof StackValue.Composed) {
|
|
||||||
//go through aload 0
|
|
||||||
owner = internalName.getInternalName();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor != null && !InlineUtil.hasNoinlineAnnotation(descriptor) && internalName.getInternalName().equals(owner)) {
|
|
||||||
//check type of context
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ public class InlineCodegenUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean isInvokeOnInlinable(String owner, String name) {
|
public static boolean isInvokeOnLambda(String owner, String name) {
|
||||||
return INVOKE.equals(name) && /*TODO: check type*/owner.contains("Function");
|
return INVOKE.equals(name) && /*TODO: check type*/owner.contains("Function");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.jetbrains.jet.codegen.inline.MethodInliner.getPreviousNoLabelNoLine;
|
|
||||||
|
|
||||||
public class InlineFieldRemapper extends LambdaFieldRemapper {
|
public class InlineFieldRemapper extends LambdaFieldRemapper {
|
||||||
|
|
||||||
private final String oldOwnerType;
|
private final String oldOwnerType;
|
||||||
@@ -50,18 +48,14 @@ public class InlineFieldRemapper extends LambdaFieldRemapper {
|
|||||||
public AbstractInsnNode doTransform(
|
public AbstractInsnNode doTransform(
|
||||||
MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField
|
MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField
|
||||||
) {
|
) {
|
||||||
boolean isRecaptured = isRecapruredLambdaType(fieldInsnNode.owner);
|
boolean isRecaptured = isRecapturedLambdaType(fieldInsnNode.owner);
|
||||||
|
|
||||||
if (!isRecaptured && capturedField.getLambda() != null) {
|
if (!isRecaptured && capturedField.getLambda() != null) {
|
||||||
//strict inlining
|
//strict inlining
|
||||||
return super.doTransform(node, fieldInsnNode, capturedField);
|
return super.doTransform(node, fieldInsnNode, capturedField);
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractInsnNode prev = getPreviousNoLabelNoLine(fieldInsnNode);
|
AbstractInsnNode loadThis = getPreviousThis(fieldInsnNode);
|
||||||
|
|
||||||
assert prev.getType() == AbstractInsnNode.VAR_INSN || prev.getType() == AbstractInsnNode.FIELD_INSN;
|
|
||||||
AbstractInsnNode loadThis = prev;
|
|
||||||
assert /*loadThis.var == info.getCapturedVarsSize() - 1 && */loadThis.getOpcode() == Opcodes.ALOAD || loadThis.getOpcode() == Opcodes.GETSTATIC;
|
|
||||||
|
|
||||||
int opcode = Opcodes.GETSTATIC;
|
int opcode = Opcodes.GETSTATIC;
|
||||||
|
|
||||||
@@ -95,10 +89,10 @@ public class InlineFieldRemapper extends LambdaFieldRemapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canProcess(String owner, String currentLambdaType) {
|
public boolean canProcess(String owner, String currentLambdaType) {
|
||||||
return super.canProcess(owner, currentLambdaType) || isRecapruredLambdaType(owner);
|
return super.canProcess(owner, currentLambdaType) || isRecapturedLambdaType(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isRecapruredLambdaType(String owner) {
|
private boolean isRecapturedLambdaType(String owner) {
|
||||||
return recapturedLambdas.containsKey(owner);
|
return recapturedLambdas.containsKey(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +100,7 @@ public class InlineFieldRemapper extends LambdaFieldRemapper {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection<CapturedParamInfo> captured) {
|
public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection<CapturedParamInfo> captured) {
|
||||||
if (!isRecapruredLambdaType(fieldInsnNode.owner)) {
|
if (!isRecapturedLambdaType(fieldInsnNode.owner)) {
|
||||||
return super.findField(fieldInsnNode, captured);
|
return super.findField(fieldInsnNode, captured);
|
||||||
} else {
|
} else {
|
||||||
LambdaInfo info = recapturedLambdas.get(fieldInsnNode.owner);
|
LambdaInfo info = recapturedLambdas.get(fieldInsnNode.owner);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class InliningInfo {
|
|||||||
|
|
||||||
public final Map<Integer, LambdaInfo> expresssionMap;
|
public final Map<Integer, LambdaInfo> expresssionMap;
|
||||||
|
|
||||||
public final List<InlinableAccess> inlinableAccesses;
|
public final List<InvokeCall> invokeCalls;
|
||||||
|
|
||||||
public final List<ConstructorInvocation> constructorInvocation;
|
public final List<ConstructorInvocation> constructorInvocation;
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ public class InliningInfo {
|
|||||||
|
|
||||||
public InliningInfo(
|
public InliningInfo(
|
||||||
Map<Integer, LambdaInfo> map,
|
Map<Integer, LambdaInfo> map,
|
||||||
List<InlinableAccess> accesses,
|
List<InvokeCall> accesses,
|
||||||
List<ConstructorInvocation> invocation,
|
List<ConstructorInvocation> invocation,
|
||||||
VarRemapper remapper,
|
VarRemapper remapper,
|
||||||
GenerationState state,
|
GenerationState state,
|
||||||
@@ -57,7 +57,7 @@ public class InliningInfo {
|
|||||||
Map<String, String> typeMapping
|
Map<String, String> typeMapping
|
||||||
) {
|
) {
|
||||||
expresssionMap = map;
|
expresssionMap = map;
|
||||||
inlinableAccesses = accesses;
|
invokeCalls = accesses;
|
||||||
constructorInvocation = invocation;
|
constructorInvocation = invocation;
|
||||||
this.remapper = remapper;
|
this.remapper = remapper;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
@@ -74,7 +74,7 @@ public class InliningInfo {
|
|||||||
public InliningInfo subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
|
public InliningInfo subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
|
||||||
HashMap<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
|
HashMap<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
|
||||||
newTypeMappings.putAll(additionalTypeMappings);
|
newTypeMappings.putAll(additionalTypeMappings);
|
||||||
return new InliningInfo(expresssionMap, inlinableAccesses, constructorInvocation, remapper, state, generator, startContext, call,
|
return new InliningInfo(expresssionMap, invokeCalls, constructorInvocation, remapper, state, generator, startContext, call,
|
||||||
newTypeMappings);
|
newTypeMappings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-28
@@ -18,38 +18,14 @@ package org.jetbrains.jet.codegen.inline;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
class InvokeCall {
|
||||||
|
|
||||||
class InlinableAccess {
|
|
||||||
|
|
||||||
public final int index;
|
public final int index;
|
||||||
|
|
||||||
public final boolean inlinable;
|
public final LambdaInfo lambdaInfo;
|
||||||
|
|
||||||
private final List<ParameterInfo> parameters;
|
InvokeCall(int index, @Nullable LambdaInfo lambdaInfo) {
|
||||||
|
|
||||||
private LambdaInfo info;
|
|
||||||
|
|
||||||
InlinableAccess(int index, boolean isInlinable, List<ParameterInfo> parameterInfos) {
|
|
||||||
this.index = index;
|
this.index = index;
|
||||||
inlinable = isInlinable;
|
this.lambdaInfo = lambdaInfo;
|
||||||
this.parameters = parameterInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInlinable() {
|
|
||||||
return inlinable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public LambdaInfo getInfo() {
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInfo(LambdaInfo info) {
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ParameterInfo> getParameters() {
|
|
||||||
return parameters;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,21 +31,26 @@ import static org.jetbrains.jet.codegen.inline.MethodInliner.getPreviousNoLabelN
|
|||||||
public class LambdaFieldRemapper {
|
public class LambdaFieldRemapper {
|
||||||
|
|
||||||
public AbstractInsnNode doTransform(MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField) {
|
public AbstractInsnNode doTransform(MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField) {
|
||||||
AbstractInsnNode prev = getPreviousNoLabelNoLine(fieldInsnNode);
|
AbstractInsnNode loadThis = getPreviousThis(fieldInsnNode);
|
||||||
|
|
||||||
assert prev.getType() == AbstractInsnNode.VAR_INSN || prev.getType() == AbstractInsnNode.FIELD_INSN;
|
|
||||||
AbstractInsnNode loadThis = prev;
|
|
||||||
int opcode1 = loadThis.getOpcode();
|
|
||||||
assert /*loadThis.var == info.getCapturedVarsSize() - 1 && */opcode1 == Opcodes.ALOAD || opcode1 == Opcodes.GETSTATIC;
|
|
||||||
|
|
||||||
int opcode = fieldInsnNode.getOpcode() == Opcodes.GETFIELD ? capturedField.getType().getOpcode(Opcodes.ILOAD) : capturedField.getType().getOpcode(Opcodes.ISTORE);
|
int opcode = fieldInsnNode.getOpcode() == Opcodes.GETFIELD ? capturedField.getType().getOpcode(Opcodes.ILOAD) : capturedField.getType().getOpcode(Opcodes.ISTORE);
|
||||||
VarInsnNode insn = new VarInsnNode(opcode, capturedField.getIndex());
|
VarInsnNode newInstruction = new VarInsnNode(opcode, capturedField.getIndex());
|
||||||
|
|
||||||
node.instructions.remove(prev); //remove aload this
|
node.instructions.remove(loadThis); //remove aload this
|
||||||
node.instructions.insertBefore(fieldInsnNode, insn);
|
node.instructions.insertBefore(fieldInsnNode, newInstruction);
|
||||||
node.instructions.remove(fieldInsnNode); //remove aload field
|
node.instructions.remove(fieldInsnNode); //remove aload field
|
||||||
|
|
||||||
return insn;
|
return newInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static AbstractInsnNode getPreviousThis(FieldInsnNode fieldInsnNode) {
|
||||||
|
AbstractInsnNode loadThis = getPreviousNoLabelNoLine(fieldInsnNode);
|
||||||
|
|
||||||
|
assert loadThis.getType() == AbstractInsnNode.VAR_INSN || loadThis.getType() == AbstractInsnNode.FIELD_INSN :
|
||||||
|
"Field access instruction should go after load this but goes after " + loadThis;
|
||||||
|
assert loadThis.getOpcode() == Opcodes.ALOAD || loadThis.getOpcode() == Opcodes.GETSTATIC :
|
||||||
|
"This should be loaded by ALOAD or GETSTATIC but " + loadThis.getOpcode();
|
||||||
|
return loadThis;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CapturedParamInfo> markRecaptured(List<CapturedParamInfo> originalCaptured, LambdaInfo lambda) {
|
public List<CapturedParamInfo> markRecaptured(List<CapturedParamInfo> originalCaptured, LambdaInfo lambda) {
|
||||||
@@ -59,14 +64,11 @@ public class LambdaFieldRemapper {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection<CapturedParamInfo> captured) {
|
public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection<CapturedParamInfo> captured) {
|
||||||
String name = fieldInsnNode.name;
|
|
||||||
CapturedParamInfo result = null;
|
|
||||||
for (CapturedParamInfo valueDescriptor : captured) {
|
for (CapturedParamInfo valueDescriptor : captured) {
|
||||||
if (valueDescriptor.getFieldName().equals(name)) {
|
if (valueDescriptor.getFieldName().equals(fieldInsnNode.name)) {
|
||||||
result = valueDescriptor;
|
return valueDescriptor;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,11 @@ import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
|
|||||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
|
||||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -39,7 +41,8 @@ public class LambdaInfo {
|
|||||||
|
|
||||||
public final JetFunctionLiteralExpression expression;
|
public final JetFunctionLiteralExpression expression;
|
||||||
|
|
||||||
@NotNull private final JetTypeMapper typeMapper;
|
@NotNull
|
||||||
|
private final JetTypeMapper typeMapper;
|
||||||
|
|
||||||
public final CalculatedClosure closure;
|
public final CalculatedClosure closure;
|
||||||
|
|
||||||
@@ -53,8 +56,6 @@ public class LambdaInfo {
|
|||||||
|
|
||||||
private final Type closureClassType;
|
private final Type closureClassType;
|
||||||
|
|
||||||
private int paramOffset;
|
|
||||||
|
|
||||||
LambdaInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper) {
|
LambdaInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper) {
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.typeMapper = typeMapper;
|
this.typeMapper = typeMapper;
|
||||||
@@ -126,19 +127,10 @@ public class LambdaInfo {
|
|||||||
return new CapturedParamInfo(descriptor.getFieldName(), descriptor.getType(), false, index, -1);
|
return new CapturedParamInfo(descriptor.getFieldName(), descriptor.getType(), false, index, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shiftParams(int shift) {
|
|
||||||
for (CapturedParamInfo var : getCapturedVars()) {
|
|
||||||
var.setShift(shift);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getParamOffset() {
|
|
||||||
return paramOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setParamOffset(int paramOffset) {
|
public void setParamOffset(int paramOffset) {
|
||||||
this.paramOffset = paramOffset;
|
for (CapturedParamInfo var : getCapturedVars()) {
|
||||||
shiftParams(paramOffset);
|
var.setShift(paramOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Type> getParamsWithoutCapturedValOrVar() {
|
public List<Type> getParamsWithoutCapturedValOrVar() {
|
||||||
@@ -146,6 +138,25 @@ public class LambdaInfo {
|
|||||||
return Arrays.asList(types);
|
return Arrays.asList(types);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Parameters addAllParameters(@NotNull LambdaFieldRemapper remapper) {
|
||||||
|
ParametersBuilder builder = ParametersBuilder.newBuilder();
|
||||||
|
//add skipped this cause inlined lambda doesn't have it
|
||||||
|
builder.addThis(AsmTypeConstants.OBJECT_TYPE, true).setLambda(this);
|
||||||
|
|
||||||
|
List<ValueParameterDescriptor> valueParameters = getFunctionDescriptor().getValueParameters();
|
||||||
|
for (ValueParameterDescriptor parameter : valueParameters) {
|
||||||
|
Type type = typeMapper.mapType(parameter.getType());
|
||||||
|
builder.addNextParameter(type, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<CapturedParamInfo> infos = remapper.markRecaptured(getCapturedVars(), this);
|
||||||
|
for (CapturedParamInfo info : infos) {
|
||||||
|
builder.addCapturedParam(info.getFieldName(), info.getType(), info.isSkipped, info);
|
||||||
|
}
|
||||||
|
return builder.buildParameters();
|
||||||
|
}
|
||||||
|
|
||||||
public int getCapturedVarsSize() {
|
public int getCapturedVarsSize() {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
for (CapturedParamInfo next : getCapturedVars()) {
|
for (CapturedParamInfo next : getCapturedVars()) {
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class LambdaTransformer {
|
|||||||
private String signature;
|
private String signature;
|
||||||
private String superName;
|
private String superName;
|
||||||
private String[] interfaces;
|
private String[] interfaces;
|
||||||
private boolean isSameModule;
|
private final boolean isSameModule;
|
||||||
|
|
||||||
public LambdaTransformer(String lambdaInternalName, InliningInfo info, boolean isSameModule, Type newLambdaType) {
|
public LambdaTransformer(String lambdaInternalName, InliningInfo info, boolean isSameModule, Type newLambdaType) {
|
||||||
this.isSameModule = isSameModule;
|
this.isSameModule = isSameModule;
|
||||||
@@ -189,7 +189,7 @@ public class LambdaTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void extractParametersMapping(MethodNode constructor, ParametersBuilder builder, ConstructorInvocation invocation) {
|
private void extractParametersMapping(MethodNode constructor, ParametersBuilder builder, ConstructorInvocation invocation) {
|
||||||
Map<Integer, InlinableAccess> indexToLambda = invocation.getAccess();
|
Map<Integer, InvokeCall> indexToLambda = invocation.getAccess();
|
||||||
|
|
||||||
AbstractInsnNode cur = constructor.instructions.getFirst();
|
AbstractInsnNode cur = constructor.instructions.getFirst();
|
||||||
cur = cur.getNext(); //skip super call
|
cur = cur.getNext(); //skip super call
|
||||||
@@ -202,9 +202,9 @@ public class LambdaTransformer {
|
|||||||
paramMapping.put(fieldNode.name, varIndex);
|
paramMapping.put(fieldNode.name, varIndex);
|
||||||
|
|
||||||
CapturedParamInfo info = builder.addCapturedParam(fieldNode.name, Type.getType(fieldNode.desc), false, null);
|
CapturedParamInfo info = builder.addCapturedParam(fieldNode.name, Type.getType(fieldNode.desc), false, null);
|
||||||
InlinableAccess access = indexToLambda.get(varIndex);
|
InvokeCall access = indexToLambda.get(varIndex);
|
||||||
if (access != null) {
|
if (access != null) {
|
||||||
LambdaInfo accessInfo = access.getInfo();
|
LambdaInfo accessInfo = access.lambdaInfo;
|
||||||
if (accessInfo != null) {
|
if (accessInfo != null) {
|
||||||
info.setLambda(accessInfo);
|
info.setLambda(accessInfo);
|
||||||
additionalCaptured.add(accessInfo);
|
additionalCaptured.add(accessInfo);
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ import org.jetbrains.asm4.tree.analysis.*;
|
|||||||
import org.jetbrains.jet.codegen.ClosureCodegen;
|
import org.jetbrains.jet.codegen.ClosureCodegen;
|
||||||
import org.jetbrains.jet.codegen.StackValue;
|
import org.jetbrains.jet.codegen.StackValue;
|
||||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.jet.utils.UtilsPackage;
|
||||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -32,18 +31,18 @@ public class MethodInliner {
|
|||||||
private final InliningInfo parent;
|
private final InliningInfo parent;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Type lambdaInfo;
|
private final Type lambdaType;
|
||||||
|
|
||||||
private final LambdaFieldRemapper lambdaFieldRemapper;
|
private final LambdaFieldRemapper lambdaFieldRemapper;
|
||||||
|
|
||||||
private boolean isSameModule;
|
private final boolean isSameModule;
|
||||||
|
|
||||||
private final JetTypeMapper typeMapper;
|
private final JetTypeMapper typeMapper;
|
||||||
|
|
||||||
private final List<InlinableAccess> inlinableInvocation = new ArrayList<InlinableAccess>();
|
private final List<InvokeCall> invokeCalls = new ArrayList<InvokeCall>();
|
||||||
|
|
||||||
//keeps order
|
//keeps order
|
||||||
private final List<ConstructorInvocation> constructorInvocationList = new ArrayList<ConstructorInvocation>();
|
private final List<ConstructorInvocation> constructorInvocations = new ArrayList<ConstructorInvocation>();
|
||||||
//current state
|
//current state
|
||||||
private final Map<String, String> currentTypeMapping = new HashMap<String, String>();
|
private final Map<String, String> currentTypeMapping = new HashMap<String, String>();
|
||||||
|
|
||||||
@@ -52,20 +51,20 @@ public class MethodInliner {
|
|||||||
* @param node
|
* @param node
|
||||||
* @param parameters
|
* @param parameters
|
||||||
* @param parent
|
* @param parent
|
||||||
* @param lambdaInfo - in case on lambda 'invoke' inlining
|
* @param lambdaType - in case on lambda 'invoke' inlining
|
||||||
*/
|
*/
|
||||||
public MethodInliner(
|
public MethodInliner(
|
||||||
@NotNull MethodNode node,
|
@NotNull MethodNode node,
|
||||||
Parameters parameters,
|
@NotNull Parameters parameters,
|
||||||
@NotNull InliningInfo parent,
|
@NotNull InliningInfo parent,
|
||||||
@Nullable Type lambdaInfo,
|
@Nullable Type lambdaType,
|
||||||
LambdaFieldRemapper lambdaFieldRemapper,
|
LambdaFieldRemapper lambdaFieldRemapper,
|
||||||
boolean isSameModule
|
boolean isSameModule
|
||||||
) {
|
) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.lambdaInfo = lambdaInfo;
|
this.lambdaType = lambdaType;
|
||||||
this.lambdaFieldRemapper = lambdaFieldRemapper;
|
this.lambdaFieldRemapper = lambdaFieldRemapper;
|
||||||
this.isSameModule = isSameModule;
|
this.isSameModule = isSameModule;
|
||||||
this.typeMapper = parent.state.getTypeMapper();
|
this.typeMapper = parent.state.getTypeMapper();
|
||||||
@@ -87,7 +86,7 @@ public class MethodInliner {
|
|||||||
transformedNode = markPlacesForInlineAndRemoveInlinable(transformedNode);
|
transformedNode = markPlacesForInlineAndRemoveInlinable(transformedNode);
|
||||||
}
|
}
|
||||||
catch (AnalyzerException e) {
|
catch (AnalyzerException e) {
|
||||||
throw new RuntimeException(e);
|
throw UtilsPackage.rethrow(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
transformedNode = doInline(transformedNode, capturedRemapper);
|
transformedNode = doInline(transformedNode, capturedRemapper);
|
||||||
@@ -103,11 +102,11 @@ public class MethodInliner {
|
|||||||
|
|
||||||
private MethodNode doInline(MethodNode node, final LambdaFieldRemapper capturedRemapper) {
|
private MethodNode doInline(MethodNode node, final LambdaFieldRemapper capturedRemapper) {
|
||||||
|
|
||||||
final Deque<InlinableAccess> infos = new LinkedList<InlinableAccess>(inlinableInvocation);
|
final Deque<InvokeCall> currentInvokes = new LinkedList<InvokeCall>(invokeCalls);
|
||||||
|
|
||||||
MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
|
MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
|
||||||
|
|
||||||
final Iterator<ConstructorInvocation> iterator = constructorInvocationList.iterator();
|
final Iterator<ConstructorInvocation> iterator = constructorInvocations.iterator();
|
||||||
|
|
||||||
RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode,
|
RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode,
|
||||||
new TypeRemapper(currentTypeMapping, isSameModule));
|
new TypeRemapper(currentTypeMapping, isSameModule));
|
||||||
@@ -137,35 +136,34 @@ public class MethodInliner {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
||||||
if (/*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnInlinable(owner, name)) { //TODO add method
|
if (/*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnLambda(owner, name)) { //TODO add method
|
||||||
assert !infos.isEmpty();
|
assert !currentInvokes.isEmpty();
|
||||||
InlinableAccess inlinableAccess = infos.remove();
|
InvokeCall invokeCall = currentInvokes.remove();
|
||||||
|
LambdaInfo info = invokeCall.lambdaInfo;
|
||||||
|
|
||||||
if (!inlinableAccess.isInlinable()) {
|
if (info == null) {
|
||||||
//noninlinable closure
|
//noninlinable lambda
|
||||||
super.visitMethodInsn(opcode, owner, name, desc);
|
super.visitMethodInsn(opcode, owner, name, desc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LambdaInfo info = getLambda(inlinableAccess.index);
|
|
||||||
|
|
||||||
int valueParamShift = getNextLocalIndex();
|
|
||||||
|
|
||||||
|
int valueParamShift = getNextLocalIndex();//NB: don't inline cause it changes
|
||||||
putStackValuesIntoLocals(info.getParamsWithoutCapturedValOrVar(), valueParamShift, this, desc);
|
putStackValuesIntoLocals(info.getParamsWithoutCapturedValOrVar(), valueParamShift, this, desc);
|
||||||
|
|
||||||
List<ParameterInfo> lambdaParameters = inlinableAccess.getParameters();
|
Parameters lambdaParameters = info.addAllParameters(capturedRemapper);
|
||||||
|
|
||||||
Parameters params = new Parameters(lambdaParameters, Parameters.transformList(capturedRemapper.markRecaptured(info.getCapturedVars(), info), lambdaParameters.size()));
|
setInlining(true);
|
||||||
|
MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(),
|
||||||
|
capturedRemapper, true /*cause all calls in same module as lambda*/);
|
||||||
|
|
||||||
this.setInlining(true);
|
VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(lambdaParameters, valueParamShift);
|
||||||
MethodInliner inliner = new MethodInliner(info.getNode(), params, parent.subInline(parent.nameGenerator.subGenerator("lambda")), info.getLambdaClassType(),
|
|
||||||
capturedRemapper, true /*cause all call in same module as lambda*/);
|
|
||||||
|
|
||||||
VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(params, valueParamShift);
|
|
||||||
inliner.doTransformAndMerge(this.mv, remapper); //TODO add skipped this and receiver
|
inliner.doTransformAndMerge(this.mv, remapper); //TODO add skipped this and receiver
|
||||||
|
|
||||||
|
//return value boxing/unboxing
|
||||||
Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod();
|
Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod();
|
||||||
Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod();
|
Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod();
|
||||||
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
|
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
|
||||||
this.setInlining(true);
|
setInlining(false);
|
||||||
}
|
}
|
||||||
else if (isLambdaConstructorCall(owner, name)) { //TODO add method
|
else if (isLambdaConstructorCall(owner, name)) { //TODO add method
|
||||||
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
|
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
|
||||||
@@ -248,12 +246,12 @@ public class MethodInliner {
|
|||||||
|
|
||||||
node.accept(transformedNode);
|
node.accept(transformedNode);
|
||||||
|
|
||||||
if (lambdaInfo != null) {
|
transformCaptured(transformedNode);
|
||||||
transformCaptured(transformedNode, parameters, lambdaInfo, lambdaFieldRemapper);
|
|
||||||
}
|
|
||||||
return transformedNode;
|
return transformedNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) throws AnalyzerException {
|
protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) throws AnalyzerException {
|
||||||
node = prepareNode(node);
|
node = prepareNode(node);
|
||||||
|
|
||||||
@@ -275,10 +273,9 @@ public class MethodInliner {
|
|||||||
String name = methodInsnNode.name;
|
String name = methodInsnNode.name;
|
||||||
//TODO check closure
|
//TODO check closure
|
||||||
int paramLength = Type.getArgumentTypes(desc).length + 1;//non static
|
int paramLength = Type.getArgumentTypes(desc).length + 1;//non static
|
||||||
if (isInvokeOnInlinable(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) {
|
if (isInvokeOnLambda(owner, name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) {
|
||||||
SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength);
|
SourceValue sourceValue = frame.getStack(frame.getStackSize() - paramLength);
|
||||||
|
|
||||||
boolean isInlinable = false;
|
|
||||||
LambdaInfo lambdaInfo = null;
|
LambdaInfo lambdaInfo = null;
|
||||||
int varIndex = -1;
|
int varIndex = -1;
|
||||||
|
|
||||||
@@ -288,19 +285,18 @@ public class MethodInliner {
|
|||||||
assert insnNode.getOpcode() == Opcodes.ALOAD : insnNode.toString();
|
assert insnNode.getOpcode() == Opcodes.ALOAD : insnNode.toString();
|
||||||
varIndex = ((VarInsnNode) insnNode).var;
|
varIndex = ((VarInsnNode) insnNode).var;
|
||||||
lambdaInfo = getLambda(varIndex);
|
lambdaInfo = getLambda(varIndex);
|
||||||
isInlinable = lambdaInfo != null;
|
|
||||||
|
|
||||||
if (isInlinable) {
|
if (lambdaInfo != null) {
|
||||||
//remove inlinable access
|
//remove inlinable access
|
||||||
node.instructions.remove(insnNode);
|
node.instructions.remove(insnNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inlinableInvocation.add(new InlinableAccess(varIndex, isInlinable, getParametersInfo(lambdaInfo, desc)));
|
invokeCalls.add(new InvokeCall(varIndex, lambdaInfo));
|
||||||
}
|
}
|
||||||
else if (isLambdaConstructorCall(owner, name)) {
|
else if (isLambdaConstructorCall(owner, name)) {
|
||||||
Map<Integer, InlinableAccess> infos = new HashMap<Integer, InlinableAccess>();
|
Map<Integer, InvokeCall> infos = new HashMap<Integer, InvokeCall>();
|
||||||
int paramStart = frame.getStackSize() - paramLength;
|
int paramStart = frame.getStackSize() - paramLength;
|
||||||
|
|
||||||
for (int i = 0; i < paramLength; i++) {
|
for (int i = 0; i < paramLength; i++) {
|
||||||
@@ -311,19 +307,14 @@ public class MethodInliner {
|
|||||||
int varIndex = ((VarInsnNode) insnNode).var;
|
int varIndex = ((VarInsnNode) insnNode).var;
|
||||||
LambdaInfo lambdaInfo = getLambda(varIndex);
|
LambdaInfo lambdaInfo = getLambda(varIndex);
|
||||||
if (lambdaInfo != null) {
|
if (lambdaInfo != null) {
|
||||||
InlinableAccess inlinableAccess = new InlinableAccess(varIndex, true, null);
|
infos.put(i, new InvokeCall(varIndex, lambdaInfo));
|
||||||
inlinableAccess.setInfo(lambdaInfo);
|
|
||||||
infos.put(i, inlinableAccess);
|
|
||||||
|
|
||||||
//remove inlinable access
|
|
||||||
node.instructions.remove(insnNode);
|
node.instructions.remove(insnNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstructorInvocation invocation = new ConstructorInvocation(owner, infos, isSameModule);
|
constructorInvocations.add(new ConstructorInvocation(owner, infos, isSameModule));
|
||||||
constructorInvocationList.add(invocation);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -343,7 +334,7 @@ public class MethodInliner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//clean dead try catch blocks
|
//clean dead try/catch blocks
|
||||||
List<TryCatchBlockNode> blocks = node.tryCatchBlocks;
|
List<TryCatchBlockNode> blocks = node.tryCatchBlocks;
|
||||||
for (Iterator<TryCatchBlockNode> iterator = blocks.iterator(); iterator.hasNext(); ) {
|
for (Iterator<TryCatchBlockNode> iterator = blocks.iterator(); iterator.hasNext(); ) {
|
||||||
TryCatchBlockNode block = iterator.next();
|
TryCatchBlockNode block = iterator.next();
|
||||||
@@ -355,40 +346,7 @@ public class MethodInliner {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ParameterInfo> getParametersInfo(LambdaInfo info, String desc) {
|
@Nullable
|
||||||
List<ParameterInfo> result = new ArrayList<ParameterInfo>();
|
|
||||||
Type[] types = Type.getArgumentTypes(desc);
|
|
||||||
|
|
||||||
//add skipped this cause closure doesn't have it
|
|
||||||
//result.add(ParameterInfo.STUB);
|
|
||||||
ParameterInfo thiz = new ParameterInfo(AsmTypeConstants.OBJECT_TYPE, true, -1, -1);
|
|
||||||
thiz.setLambda(info);
|
|
||||||
|
|
||||||
result.add(thiz);
|
|
||||||
int index = 1;
|
|
||||||
|
|
||||||
if (info != null) {
|
|
||||||
List<ValueParameterDescriptor> valueParameters = info.getFunctionDescriptor().getValueParameters();
|
|
||||||
for (ValueParameterDescriptor parameter : valueParameters) {
|
|
||||||
Type type = typeMapper.mapType(parameter.getType());
|
|
||||||
int paramIndex = index++;
|
|
||||||
result.add(new ParameterInfo(type, false, paramIndex, -1));
|
|
||||||
if (type.getSize() == 2) {
|
|
||||||
result.add(ParameterInfo.STUB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (Type type : types) {
|
|
||||||
int paramIndex = index++;
|
|
||||||
result.add(new ParameterInfo(type, false, paramIndex, -1));
|
|
||||||
if (type.getSize() == 2) {
|
|
||||||
result.add(ParameterInfo.STUB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LambdaInfo getLambda(int index) {
|
public LambdaInfo getLambda(int index) {
|
||||||
if (index < parameters.totalSize()) {
|
if (index < parameters.totalSize()) {
|
||||||
return parameters.get(index).getLambda();
|
return parameters.get(index).getLambda();
|
||||||
@@ -433,13 +391,10 @@ public class MethodInliner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<FieldAccess> transformCaptured(
|
private void transformCaptured(@NotNull MethodNode node) {
|
||||||
@NotNull MethodNode node,
|
if (lambdaType == null) {
|
||||||
@NotNull Parameters paramsToSearch,
|
return;
|
||||||
@NotNull Type lambdaClassType,
|
}
|
||||||
@NotNull LambdaFieldRemapper lambdaFieldRemapper
|
|
||||||
) {
|
|
||||||
List<FieldAccess> capturedFields = new ArrayList<FieldAccess>();
|
|
||||||
|
|
||||||
//remove all this and shift all variables to captured ones size
|
//remove all this and shift all variables to captured ones size
|
||||||
AbstractInsnNode cur = node.instructions.getFirst();
|
AbstractInsnNode cur = node.instructions.getFirst();
|
||||||
@@ -447,53 +402,28 @@ public class MethodInliner {
|
|||||||
if (cur.getType() == AbstractInsnNode.FIELD_INSN) {
|
if (cur.getType() == AbstractInsnNode.FIELD_INSN) {
|
||||||
FieldInsnNode fieldInsnNode = (FieldInsnNode) cur;
|
FieldInsnNode fieldInsnNode = (FieldInsnNode) cur;
|
||||||
//TODO check closure
|
//TODO check closure
|
||||||
String owner = fieldInsnNode.owner;
|
if (lambdaFieldRemapper.canProcess(fieldInsnNode.owner, lambdaType.getInternalName())) {
|
||||||
if (lambdaFieldRemapper.canProcess(fieldInsnNode.owner, lambdaClassType.getInternalName())) {
|
CapturedParamInfo result = this.lambdaFieldRemapper.findField(fieldInsnNode, parameters.getCaptured());
|
||||||
String name = fieldInsnNode.name;
|
|
||||||
String desc = fieldInsnNode.desc;
|
|
||||||
|
|
||||||
Collection<CapturedParamInfo> vars = paramsToSearch.getCaptured();
|
|
||||||
CapturedParamInfo result = lambdaFieldRemapper.findField(fieldInsnNode, paramsToSearch.getCaptured());
|
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new UnsupportedOperationException("Coudn't find field " +
|
throw new UnsupportedOperationException("Coudn't find field " +
|
||||||
owner +
|
fieldInsnNode.owner +
|
||||||
"." +
|
"." +
|
||||||
name +
|
fieldInsnNode.name +
|
||||||
" (" +
|
" (" +
|
||||||
desc +
|
fieldInsnNode.desc +
|
||||||
") in captured vars of " + lambdaClassType);
|
") in captured vars of " + lambdaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.isSkipped()) {
|
if (result.isSkipped()) {
|
||||||
//lambda class transformation skip this captured
|
//lambda class transformation: skip captured this
|
||||||
} else {
|
} else {
|
||||||
cur = lambdaFieldRemapper.doTransform(node, fieldInsnNode, result);
|
cur = this.lambdaFieldRemapper.doTransform(node, fieldInsnNode, result);
|
||||||
|
|
||||||
//AbstractInsnNode prev = getPreviousNoLableNoLine(cur);
|
|
||||||
//
|
|
||||||
//assert prev.getType() == AbstractInsnNode.VAR_INSN;
|
|
||||||
//VarInsnNode loadThis = (VarInsnNode) prev;
|
|
||||||
//assert /*loadThis.var == info.getCapturedVarsSize() - 1 && */loadThis.getOpcode() == Opcodes.ALOAD;
|
|
||||||
//
|
|
||||||
//int opcode = fieldInsnNode.getOpcode() == Opcodes.GETFIELD ? result.getType().getOpcode(Opcodes.ILOAD) : result.getType().getOpcode(Opcodes.ISTORE);
|
|
||||||
//VarInsnNode insn = new VarInsnNode(opcode, result.getIndex());
|
|
||||||
//
|
|
||||||
//node.instructions.remove(prev); //remove aload this
|
|
||||||
//node.instructions.insertBefore(cur, insn);
|
|
||||||
//node.instructions.remove(cur); //remove aload field
|
|
||||||
//
|
|
||||||
//cur = insn;
|
|
||||||
//
|
|
||||||
//FieldAccess fieldAccess = new FieldAccess(fieldInsnNode.name, fieldInsnNode.desc, new FieldAccess("" + loadThis.var, lambdaClassType.getInternalName()));
|
|
||||||
//capturedFields.add(fieldAccess);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur = cur.getNext();
|
cur = cur.getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
return capturedFields;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AbstractInsnNode getPreviousNoLabelNoLine(AbstractInsnNode cur) {
|
public static AbstractInsnNode getPreviousNoLabelNoLine(AbstractInsnNode cur) {
|
||||||
@@ -504,8 +434,8 @@ public class MethodInliner {
|
|||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void putStackValuesIntoLocals(List<Type> directOrder, int shift, InstructionAdapter mv, String descriptor) {
|
public static void putStackValuesIntoLocals(List<Type> directOrder, int shift, InstructionAdapter iv, String descriptor) {
|
||||||
Type[] actualParams = Type.getArgumentTypes(descriptor); //last param is closure itself
|
Type[] actualParams = Type.getArgumentTypes(descriptor);
|
||||||
assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!";
|
assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!";
|
||||||
|
|
||||||
int size = 0;
|
int size = 0;
|
||||||
@@ -520,9 +450,9 @@ public class MethodInliner {
|
|||||||
shift -= next.getSize();
|
shift -= next.getSize();
|
||||||
Type typeOnStack = actualParams[--index];
|
Type typeOnStack = actualParams[--index];
|
||||||
if (!typeOnStack.equals(next)) {
|
if (!typeOnStack.equals(next)) {
|
||||||
StackValue.onStack(typeOnStack).put(next, mv);
|
StackValue.onStack(typeOnStack).put(next, iv);
|
||||||
}
|
}
|
||||||
mv.visitVarInsn(next.getOpcode(Opcodes.ISTORE), shift);
|
iv.store(shift, next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,32 +34,32 @@ class ParameterInfo {
|
|||||||
public final boolean isSkipped;
|
public final boolean isSkipped;
|
||||||
|
|
||||||
//in case when parameter could be extracted from outer context (e.g. from local var)
|
//in case when parameter could be extracted from outer context (e.g. from local var)
|
||||||
private StackValue remapIndex;
|
private StackValue remapValue;
|
||||||
|
|
||||||
public LambdaInfo lambda;
|
public LambdaInfo lambda;
|
||||||
|
|
||||||
ParameterInfo(Type type, boolean skipped, int index, int remapIndex) {
|
ParameterInfo(Type type, boolean skipped, int index, int remapValue) {
|
||||||
this(type, skipped, index, remapIndex == -1 ? null : StackValue.local(remapIndex, type));
|
this(type, skipped, index, remapValue == -1 ? null : StackValue.local(remapValue, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
ParameterInfo(Type type, boolean skipped, int index, StackValue stackValue) {
|
ParameterInfo(Type type, boolean skipped, int index, StackValue stackValue) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.isSkipped = skipped;
|
this.isSkipped = skipped;
|
||||||
this.remapIndex = stackValue;
|
this.remapValue = stackValue;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSkippedOrRemapped() {
|
public boolean isSkippedOrRemapped() {
|
||||||
return isSkipped || remapIndex != null;
|
return isSkipped || remapValue != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRemapped() {
|
public boolean isRemapped() {
|
||||||
return remapIndex != null;
|
return remapValue != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public StackValue getRemapIndex() {
|
public StackValue getRemapValue() {
|
||||||
return remapIndex;
|
return remapValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIndex() {
|
public int getIndex() {
|
||||||
@@ -84,7 +84,7 @@ class ParameterInfo {
|
|||||||
this.lambda = lambda;
|
this.lambda = lambda;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRemapIndex(StackValue remapIndex) {
|
public void setRemapValue(StackValue remapValue) {
|
||||||
this.remapIndex = remapIndex;
|
this.remapValue = remapValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,20 +60,6 @@ public class Parameters implements Iterable<ParameterInfo> {
|
|||||||
return Iterables.concat(real, captured).iterator();
|
return Iterables.concat(real, captured).iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<CapturedParamInfo> transformList(List<CapturedParamInfo> capturedParams, int realSize) {
|
|
||||||
List<CapturedParamInfo> result = new ArrayList<CapturedParamInfo>();
|
|
||||||
for (CapturedParamInfo capturedParamInfo : capturedParams) {
|
|
||||||
CapturedParamInfo newInfo = capturedParamInfo.clone(result.size() + realSize, capturedParamInfo.getIndex());
|
|
||||||
|
|
||||||
result.add(newInfo);
|
|
||||||
|
|
||||||
if (capturedParamInfo.getType().getSize() == 2) {
|
|
||||||
result.add(CapturedParamInfo.STUB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<CapturedParamInfo> addStubs(List<CapturedParamInfo> capturedParams, int realSize) {
|
public static List<CapturedParamInfo> addStubs(List<CapturedParamInfo> capturedParams, int realSize) {
|
||||||
List<CapturedParamInfo> result = new ArrayList<CapturedParamInfo>();
|
List<CapturedParamInfo> result = new ArrayList<CapturedParamInfo>();
|
||||||
for (CapturedParamInfo capturedParamInfo : capturedParams) {
|
for (CapturedParamInfo capturedParamInfo : capturedParams) {
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ public class ParametersBuilder {
|
|||||||
|
|
||||||
private final List<ParameterInfo> params = new ArrayList<ParameterInfo>();
|
private final List<ParameterInfo> params = new ArrayList<ParameterInfo>();
|
||||||
private final List<CapturedParamInfo> capturedParams = new ArrayList<CapturedParamInfo>();
|
private final List<CapturedParamInfo> capturedParams = new ArrayList<CapturedParamInfo>();
|
||||||
private final List<CapturedParamInfo> additionalCapturedParams = new ArrayList<CapturedParamInfo>();
|
|
||||||
|
|
||||||
private int nextIndex = 0;
|
private int nextIndex = 0;
|
||||||
private int nextCaptured = 0;
|
private int nextCaptured = 0;
|
||||||
@@ -36,9 +35,10 @@ public class ParametersBuilder {
|
|||||||
return new ParametersBuilder();
|
return new ParametersBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParametersBuilder addThis(Type type, boolean skipped) {
|
public ParameterInfo addThis(Type type, boolean skipped) {
|
||||||
addParameter(new ParameterInfo(type, skipped, nextIndex, -1));
|
ParameterInfo info = new ParameterInfo(type, skipped, nextIndex, -1);
|
||||||
return this;
|
addParameter(info);
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParametersBuilder addNextParameter(Type type, boolean skipped, @Nullable ParameterInfo original) {
|
public ParametersBuilder addNextParameter(Type type, boolean skipped, @Nullable ParameterInfo original) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.jetbrains.asm4.commons.InstructionAdapter;
|
|||||||
|
|
||||||
public class ShiftAdapter extends InstructionAdapter {
|
public class ShiftAdapter extends InstructionAdapter {
|
||||||
|
|
||||||
private int shift;
|
private final int shift;
|
||||||
|
|
||||||
public ShiftAdapter(MethodVisitor mv, int shift) {
|
public ShiftAdapter(MethodVisitor mv, int shift) {
|
||||||
super(mv);
|
super(mv);
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ public abstract class VarRemapper {
|
|||||||
private final Parameters params;
|
private final Parameters params;
|
||||||
private final int actualParamsSize;
|
private final int actualParamsSize;
|
||||||
|
|
||||||
private final StackValue [] remapIndex;
|
private final StackValue [] remapValues;
|
||||||
|
|
||||||
private int additionalShift;
|
private final int additionalShift;
|
||||||
|
|
||||||
public ParamRemapper(Parameters params, int additionalShift) {
|
public ParamRemapper(Parameters params, int additionalShift) {
|
||||||
this.additionalShift = additionalShift;
|
this.additionalShift = additionalShift;
|
||||||
@@ -42,15 +42,15 @@ public abstract class VarRemapper {
|
|||||||
this.params = params;
|
this.params = params;
|
||||||
|
|
||||||
int realSize = 0;
|
int realSize = 0;
|
||||||
remapIndex = new StackValue [params.totalSize()];
|
remapValues = new StackValue [params.totalSize()];
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (ParameterInfo info : params) {
|
for (ParameterInfo info : params) {
|
||||||
if (!info.isSkippedOrRemapped()) {
|
if (!info.isSkippedOrRemapped()) {
|
||||||
remapIndex[index] = StackValue.local(realSize, AsmTypeConstants.OBJECT_TYPE);
|
remapValues[index] = StackValue.local(realSize, AsmTypeConstants.OBJECT_TYPE);
|
||||||
realSize += info.getType().getSize();
|
realSize += info.getType().getSize();
|
||||||
} else {
|
} else {
|
||||||
remapIndex[index] = info.isRemapped() ? info.getRemapIndex() : null;
|
remapValues[index] = info.isRemapped() ? info.getRemapValue() : null;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ public abstract class VarRemapper {
|
|||||||
|
|
||||||
if (index < allParamsSize) {
|
if (index < allParamsSize) {
|
||||||
ParameterInfo info = params.get(index);
|
ParameterInfo info = params.get(index);
|
||||||
StackValue remapped = remapIndex[index];
|
StackValue remapped = remapValues[index];
|
||||||
if (info.isSkipped || remapped == null) {
|
if (info.isSkipped || remapped == null) {
|
||||||
throw new RuntimeException("Trying to access skipped parameter: " + info.type + " at " +index);
|
throw new RuntimeException("Trying to access skipped parameter: " + info.type + " at " +index);
|
||||||
}
|
}
|
||||||
@@ -100,9 +100,10 @@ public abstract class VarRemapper {
|
|||||||
}
|
}
|
||||||
mv.visitVarInsn(opcode, ((StackValue.Local) value).index);
|
mv.visitVarInsn(opcode, ((StackValue.Local) value).index);
|
||||||
if (remapInfo.parameterInfo != null) {
|
if (remapInfo.parameterInfo != null) {
|
||||||
value.coerce(value.type, remapInfo.parameterInfo.type, mv);
|
StackValue.coerce(value.type, remapInfo.parameterInfo.type, mv);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
assert remapInfo.parameterInfo != null : "Non local value should have parameter info";
|
||||||
value.put(remapInfo.parameterInfo.type, mv);
|
value.put(remapInfo.parameterInfo.type, mv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user