Code simplification and clean

~special flag
This commit is contained in:
Mikhael Bogdanov
2014-02-21 17:04:59 +04:00
parent c8302fdf9c
commit e7603d2e62
19 changed files with 167 additions and 307 deletions
@@ -1711,7 +1711,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false);
if (value != null) {
if (context.isSpecialStackValue(value) != null) {
if (context.isSpecialStackValue(value)) {
return value;
}
@@ -2348,9 +2348,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
continue;
}
boolean putInLocal = true;
StackValue valueIfPresent = null;
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
Type parameterType = valueParameterTypes.get(valueParameter.getIndex());
if (resolvedValueArgument instanceof ExpressionValueArgument) {
@@ -2362,7 +2359,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
//TODO deparenthisise
if (callGenerator.isInliningClosure(argumentExpression, valueParameter)) {
callGenerator.rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType);
putInLocal = false;
} else {
StackValue value = gen(argumentExpression);
if (callGenerator.shouldPutValue(parameterType, value, valueParameter)) {
@@ -2373,18 +2369,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
} else if (resolvedValueArgument instanceof DefaultValueArgument) {
pushDefaultValueOnStack(parameterType, v);
mask |= (1 << valueParameter.getIndex());
callGenerator.putInLocal(parameterType, null, valueParameter);
}
else if (resolvedValueArgument instanceof VarargValueArgument) {
VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument;
genVarargs(valueParameter, valueArgument);
callGenerator.putInLocal(parameterType, null, valueParameter);
}
else {
throw new UnsupportedOperationException();
}
if (putInLocal) {
callGenerator.putInLocal(parameterType, valueIfPresent, valueParameter);
}
}
return mask;
}
@@ -104,17 +104,14 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
return isInlineClosure;
}
public StackValue isSpecialStackValue(StackValue stackValue) {
public boolean isSpecialStackValue(StackValue stackValue) {
if (isInlineClosure && stackValue instanceof StackValue.Composed) {
StackValue prefix = ((StackValue.Composed) stackValue).prefix;
StackValue suffix = ((StackValue.Composed) stackValue).suffix;
if (prefix instanceof StackValue.Local && ((StackValue.Local) prefix).index == 0) {
if (suffix instanceof StackValue.Field) {
StackValue.Field field = (StackValue.Field) suffix;
return StackValue.field(field.type, field.owner, field.name, true);
}
return suffix instanceof StackValue.Field;
}
}
return null;
return false;
}
}
@@ -62,20 +62,8 @@ public class CapturedParamInfo extends ParameterInfo {
this.recapturedFrom = recapturedFrom;
}
public CapturedParamInfo newRemapIndex(int newRamapIndex) {
return clone(index, newRamapIndex);
}
public CapturedParamInfo newIndex(int newIndex) {
return clone(newIndex, getRemapIndex());
}
public CapturedParamInfo clone(int newIndex, int newRamapIndex) {
CapturedParamInfo capturedParamInfo = new CapturedParamInfo(fieldName, type, isSkipped, newIndex, newRamapIndex);
capturedParamInfo.setLambda(lambda);
capturedParamInfo.setRecapturedFrom(recapturedFrom);
return capturedParamInfo;
return clone(newIndex, getRemapValue());
}
public CapturedParamInfo clone(int newIndex, StackValue newRamapIndex) {
@@ -25,9 +25,9 @@ public class ConstructorInvocation {
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;
@@ -37,7 +37,7 @@ public class ConstructorInvocation {
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.access = access;
this.isSameModule = isSameModule;
@@ -51,7 +51,7 @@ public class ConstructorInvocation {
return !access.isEmpty() || !isSameModule;
}
public Map<Integer, InlinableAccess> getAccess() {
public Map<Integer, InvokeCall> getAccess() {
return access;
}
@@ -75,19 +75,17 @@ public class InlineAdapter extends InstructionAdapter {
public void visitTryCatchBlock(Label start,
Label end, Label handler, String type) {
if(!isInlining) {
blocks.add(new CatchBlock(start, end,
handler, type));
} else {
super.visitTryCatchBlock(start, end,
handler, type);
blocks.add(new CatchBlock(start, end, handler, type));
}
else {
super.visitTryCatchBlock(start, end, handler, type);
}
}
@Override
public void visitMaxs(int stack, int locals) {
for (CatchBlock b : blocks) {
super.visitTryCatchBlock(b.start, b.end,
b.handler, b.type);
super.visitTryCatchBlock(b.start, b.end, b.handler, b.type);
}
super.visitMaxs(stack, locals);
}
@@ -89,8 +89,6 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
private SimpleFunctionDescriptor inlineFunctionDescriptor;
public InlineCodegen(
@NotNull ExpressionCodegen codegen,
@NotNull GenerationState state,
@@ -98,7 +96,6 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
@NotNull Call call
) {
assert functionDescriptor.getInlineStrategy().isInline() : "InlineCodegen could inline only inline function but " + functionDescriptor;
inlineFunctionDescriptor = functionDescriptor;
this.state = state;
this.typeMapper = state.getTypeMapper();
@@ -117,7 +114,7 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
this.asFunctionInline = false;
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) {
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);
}
}
/*descriptor is null for captured vars*/
@Override
public boolean shouldPutValue(
@NotNull Type type,
@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) {
//default or vararg
@@ -299,22 +291,13 @@ public class InlineCodegen implements ParentCodegenAware, CallGenerator {
return false;
}
if (codegen.getContext().isInlineClosure() && codegen.getContext().getContextDescriptor() instanceof AnonymousFunctionDescriptor) {
Type internalName = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) codegen.getContext().getContextDescriptor());
String owner = null;
if (stackValue instanceof StackValue.Field) {
owner = ((StackValue.Field) stackValue).owner.getInternalName();
}
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;
if (stackValue instanceof StackValue.Composed) {
//see: Method.isSpecialStackValue: go through aload 0
if (codegen.getContext().isInlineClosure() && codegen.getContext().getContextDescriptor() instanceof AnonymousFunctionDescriptor) {
if (descriptor != null && !InlineUtil.hasNoinlineAnnotation(descriptor)) {
//TODO: check type of context
return false;
}
}
}
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");
}
@@ -27,8 +27,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import static org.jetbrains.jet.codegen.inline.MethodInliner.getPreviousNoLabelNoLine;
public class InlineFieldRemapper extends LambdaFieldRemapper {
private final String oldOwnerType;
@@ -50,18 +48,14 @@ public class InlineFieldRemapper extends LambdaFieldRemapper {
public AbstractInsnNode doTransform(
MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField
) {
boolean isRecaptured = isRecapruredLambdaType(fieldInsnNode.owner);
boolean isRecaptured = isRecapturedLambdaType(fieldInsnNode.owner);
if (!isRecaptured && capturedField.getLambda() != null) {
//strict inlining
return super.doTransform(node, fieldInsnNode, capturedField);
}
AbstractInsnNode prev = getPreviousNoLabelNoLine(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;
AbstractInsnNode loadThis = getPreviousThis(fieldInsnNode);
int opcode = Opcodes.GETSTATIC;
@@ -95,10 +89,10 @@ public class InlineFieldRemapper extends LambdaFieldRemapper {
@Override
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);
}
@@ -106,7 +100,7 @@ public class InlineFieldRemapper extends LambdaFieldRemapper {
@Nullable
@Override
public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection<CapturedParamInfo> captured) {
if (!isRecapruredLambdaType(fieldInsnNode.owner)) {
if (!isRecapturedLambdaType(fieldInsnNode.owner)) {
return super.findField(fieldInsnNode, captured);
} else {
LambdaInfo info = recapturedLambdas.get(fieldInsnNode.owner);
@@ -29,7 +29,7 @@ public class InliningInfo {
public final Map<Integer, LambdaInfo> expresssionMap;
public final List<InlinableAccess> inlinableAccesses;
public final List<InvokeCall> invokeCalls;
public final List<ConstructorInvocation> constructorInvocation;
@@ -47,7 +47,7 @@ public class InliningInfo {
public InliningInfo(
Map<Integer, LambdaInfo> map,
List<InlinableAccess> accesses,
List<InvokeCall> accesses,
List<ConstructorInvocation> invocation,
VarRemapper remapper,
GenerationState state,
@@ -57,7 +57,7 @@ public class InliningInfo {
Map<String, String> typeMapping
) {
expresssionMap = map;
inlinableAccesses = accesses;
invokeCalls = accesses;
constructorInvocation = invocation;
this.remapper = remapper;
this.state = state;
@@ -74,7 +74,7 @@ public class InliningInfo {
public InliningInfo subInline(NameGenerator generator, Map<String, String> additionalTypeMappings) {
HashMap<String, String> newTypeMappings = new HashMap<String, String>(typeMapping);
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);
}
}
@@ -18,38 +18,14 @@ package org.jetbrains.jet.codegen.inline;
import org.jetbrains.annotations.Nullable;
import java.util.List;
class InlinableAccess {
class InvokeCall {
public final int index;
public final boolean inlinable;
public final LambdaInfo lambdaInfo;
private final List<ParameterInfo> parameters;
private LambdaInfo info;
InlinableAccess(int index, boolean isInlinable, List<ParameterInfo> parameterInfos) {
InvokeCall(int index, @Nullable LambdaInfo lambdaInfo) {
this.index = index;
inlinable = isInlinable;
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;
this.lambdaInfo = lambdaInfo;
}
}
@@ -31,21 +31,26 @@ import static org.jetbrains.jet.codegen.inline.MethodInliner.getPreviousNoLabelN
public class LambdaFieldRemapper {
public AbstractInsnNode doTransform(MethodNode node, FieldInsnNode fieldInsnNode, CapturedParamInfo capturedField) {
AbstractInsnNode prev = getPreviousNoLabelNoLine(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;
AbstractInsnNode loadThis = getPreviousThis(fieldInsnNode);
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.insertBefore(fieldInsnNode, insn);
node.instructions.remove(loadThis); //remove aload this
node.instructions.insertBefore(fieldInsnNode, newInstruction);
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) {
@@ -59,14 +64,11 @@ public class LambdaFieldRemapper {
@Nullable
public CapturedParamInfo findField(FieldInsnNode fieldInsnNode, Collection<CapturedParamInfo> captured) {
String name = fieldInsnNode.name;
CapturedParamInfo result = null;
for (CapturedParamInfo valueDescriptor : captured) {
if (valueDescriptor.getFieldName().equals(name)) {
result = valueDescriptor;
break;
if (valueDescriptor.getFieldName().equals(fieldInsnNode.name)) {
return valueDescriptor;
}
}
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.lang.descriptors.ClassDescriptor;
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.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import java.util.*;
@@ -39,7 +41,8 @@ public class LambdaInfo {
public final JetFunctionLiteralExpression expression;
@NotNull private final JetTypeMapper typeMapper;
@NotNull
private final JetTypeMapper typeMapper;
public final CalculatedClosure closure;
@@ -53,8 +56,6 @@ public class LambdaInfo {
private final Type closureClassType;
private int paramOffset;
LambdaInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper) {
this.expression = expression;
this.typeMapper = typeMapper;
@@ -126,19 +127,10 @@ public class LambdaInfo {
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) {
this.paramOffset = paramOffset;
shiftParams(paramOffset);
for (CapturedParamInfo var : getCapturedVars()) {
var.setShift(paramOffset);
}
}
public List<Type> getParamsWithoutCapturedValOrVar() {
@@ -146,6 +138,25 @@ public class LambdaInfo {
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() {
int size = 0;
for (CapturedParamInfo next : getCapturedVars()) {
@@ -65,7 +65,7 @@ public class LambdaTransformer {
private String signature;
private String superName;
private String[] interfaces;
private boolean isSameModule;
private final boolean isSameModule;
public LambdaTransformer(String lambdaInternalName, InliningInfo info, boolean isSameModule, Type newLambdaType) {
this.isSameModule = isSameModule;
@@ -189,7 +189,7 @@ public class LambdaTransformer {
}
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();
cur = cur.getNext(); //skip super call
@@ -202,9 +202,9 @@ public class LambdaTransformer {
paramMapping.put(fieldNode.name, varIndex);
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) {
LambdaInfo accessInfo = access.getInfo();
LambdaInfo accessInfo = access.lambdaInfo;
if (accessInfo != null) {
info.setLambda(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.StackValue;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.utils.UtilsPackage;
import java.util.*;
@@ -32,18 +31,18 @@ public class MethodInliner {
private final InliningInfo parent;
@Nullable
private final Type lambdaInfo;
private final Type lambdaType;
private final LambdaFieldRemapper lambdaFieldRemapper;
private boolean isSameModule;
private final boolean isSameModule;
private final JetTypeMapper typeMapper;
private final List<InlinableAccess> inlinableInvocation = new ArrayList<InlinableAccess>();
private final List<InvokeCall> invokeCalls = new ArrayList<InvokeCall>();
//keeps order
private final List<ConstructorInvocation> constructorInvocationList = new ArrayList<ConstructorInvocation>();
private final List<ConstructorInvocation> constructorInvocations = new ArrayList<ConstructorInvocation>();
//current state
private final Map<String, String> currentTypeMapping = new HashMap<String, String>();
@@ -52,20 +51,20 @@ public class MethodInliner {
* @param node
* @param parameters
* @param parent
* @param lambdaInfo - in case on lambda 'invoke' inlining
* @param lambdaType - in case on lambda 'invoke' inlining
*/
public MethodInliner(
@NotNull MethodNode node,
Parameters parameters,
@NotNull Parameters parameters,
@NotNull InliningInfo parent,
@Nullable Type lambdaInfo,
@Nullable Type lambdaType,
LambdaFieldRemapper lambdaFieldRemapper,
boolean isSameModule
) {
this.node = node;
this.parameters = parameters;
this.parent = parent;
this.lambdaInfo = lambdaInfo;
this.lambdaType = lambdaType;
this.lambdaFieldRemapper = lambdaFieldRemapper;
this.isSameModule = isSameModule;
this.typeMapper = parent.state.getTypeMapper();
@@ -87,7 +86,7 @@ public class MethodInliner {
transformedNode = markPlacesForInlineAndRemoveInlinable(transformedNode);
}
catch (AnalyzerException e) {
throw new RuntimeException(e);
throw UtilsPackage.rethrow(e);
}
transformedNode = doInline(transformedNode, capturedRemapper);
@@ -103,11 +102,11 @@ public class MethodInliner {
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);
final Iterator<ConstructorInvocation> iterator = constructorInvocationList.iterator();
final Iterator<ConstructorInvocation> iterator = constructorInvocations.iterator();
RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode,
new TypeRemapper(currentTypeMapping, isSameModule));
@@ -137,35 +136,34 @@ public class MethodInliner {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (/*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnInlinable(owner, name)) { //TODO add method
assert !infos.isEmpty();
InlinableAccess inlinableAccess = infos.remove();
if (/*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnLambda(owner, name)) { //TODO add method
assert !currentInvokes.isEmpty();
InvokeCall invokeCall = currentInvokes.remove();
LambdaInfo info = invokeCall.lambdaInfo;
if (!inlinableAccess.isInlinable()) {
//noninlinable closure
if (info == null) {
//noninlinable lambda
super.visitMethodInsn(opcode, owner, name, desc);
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);
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);
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);
VarRemapper.ParamRemapper remapper = new VarRemapper.ParamRemapper(lambdaParameters, valueParamShift);
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 delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod();
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
this.setInlining(true);
setInlining(false);
}
else if (isLambdaConstructorCall(owner, name)) { //TODO add method
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
@@ -248,12 +246,12 @@ public class MethodInliner {
node.accept(transformedNode);
if (lambdaInfo != null) {
transformCaptured(transformedNode, parameters, lambdaInfo, lambdaFieldRemapper);
}
transformCaptured(transformedNode);
return transformedNode;
}
@NotNull
protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) throws AnalyzerException {
node = prepareNode(node);
@@ -275,10 +273,9 @@ public class MethodInliner {
String name = methodInsnNode.name;
//TODO check closure
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);
boolean isInlinable = false;
LambdaInfo lambdaInfo = null;
int varIndex = -1;
@@ -288,19 +285,18 @@ public class MethodInliner {
assert insnNode.getOpcode() == Opcodes.ALOAD : insnNode.toString();
varIndex = ((VarInsnNode) insnNode).var;
lambdaInfo = getLambda(varIndex);
isInlinable = lambdaInfo != null;
if (isInlinable) {
if (lambdaInfo != null) {
//remove inlinable access
node.instructions.remove(insnNode);
}
}
}
inlinableInvocation.add(new InlinableAccess(varIndex, isInlinable, getParametersInfo(lambdaInfo, desc)));
invokeCalls.add(new InvokeCall(varIndex, lambdaInfo));
}
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;
for (int i = 0; i < paramLength; i++) {
@@ -311,19 +307,14 @@ public class MethodInliner {
int varIndex = ((VarInsnNode) insnNode).var;
LambdaInfo lambdaInfo = getLambda(varIndex);
if (lambdaInfo != null) {
InlinableAccess inlinableAccess = new InlinableAccess(varIndex, true, null);
inlinableAccess.setInfo(lambdaInfo);
infos.put(i, inlinableAccess);
//remove inlinable access
infos.put(i, new InvokeCall(varIndex, lambdaInfo));
node.instructions.remove(insnNode);
}
}
}
}
ConstructorInvocation invocation = new ConstructorInvocation(owner, infos, isSameModule);
constructorInvocationList.add(invocation);
constructorInvocations.add(new ConstructorInvocation(owner, infos, isSameModule));
}
}
}
@@ -343,7 +334,7 @@ public class MethodInliner {
}
}
//clean dead try catch blocks
//clean dead try/catch blocks
List<TryCatchBlockNode> blocks = node.tryCatchBlocks;
for (Iterator<TryCatchBlockNode> iterator = blocks.iterator(); iterator.hasNext(); ) {
TryCatchBlockNode block = iterator.next();
@@ -355,40 +346,7 @@ public class MethodInliner {
return node;
}
public List<ParameterInfo> getParametersInfo(LambdaInfo info, String desc) {
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;
}
@Nullable
public LambdaInfo getLambda(int index) {
if (index < parameters.totalSize()) {
return parameters.get(index).getLambda();
@@ -433,13 +391,10 @@ public class MethodInliner {
}
}
static List<FieldAccess> transformCaptured(
@NotNull MethodNode node,
@NotNull Parameters paramsToSearch,
@NotNull Type lambdaClassType,
@NotNull LambdaFieldRemapper lambdaFieldRemapper
) {
List<FieldAccess> capturedFields = new ArrayList<FieldAccess>();
private void transformCaptured(@NotNull MethodNode node) {
if (lambdaType == null) {
return;
}
//remove all this and shift all variables to captured ones size
AbstractInsnNode cur = node.instructions.getFirst();
@@ -447,53 +402,28 @@ public class MethodInliner {
if (cur.getType() == AbstractInsnNode.FIELD_INSN) {
FieldInsnNode fieldInsnNode = (FieldInsnNode) cur;
//TODO check closure
String owner = fieldInsnNode.owner;
if (lambdaFieldRemapper.canProcess(fieldInsnNode.owner, lambdaClassType.getInternalName())) {
String name = fieldInsnNode.name;
String desc = fieldInsnNode.desc;
Collection<CapturedParamInfo> vars = paramsToSearch.getCaptured();
CapturedParamInfo result = lambdaFieldRemapper.findField(fieldInsnNode, paramsToSearch.getCaptured());
if (lambdaFieldRemapper.canProcess(fieldInsnNode.owner, lambdaType.getInternalName())) {
CapturedParamInfo result = this.lambdaFieldRemapper.findField(fieldInsnNode, parameters.getCaptured());
if (result == null) {
throw new UnsupportedOperationException("Coudn't find field " +
owner +
fieldInsnNode.owner +
"." +
name +
fieldInsnNode.name +
" (" +
desc +
") in captured vars of " + lambdaClassType);
fieldInsnNode.desc +
") in captured vars of " + lambdaType);
}
if (result.isSkipped()) {
//lambda class transformation skip this captured
//lambda class transformation: skip captured this
} else {
cur = 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 = this.lambdaFieldRemapper.doTransform(node, fieldInsnNode, result);
}
}
}
cur = cur.getNext();
}
return capturedFields;
}
public static AbstractInsnNode getPreviousNoLabelNoLine(AbstractInsnNode cur) {
@@ -504,8 +434,8 @@ public class MethodInliner {
return prev;
}
public static void putStackValuesIntoLocals(List<Type> directOrder, int shift, InstructionAdapter mv, String descriptor) {
Type[] actualParams = Type.getArgumentTypes(descriptor); //last param is closure itself
public static void putStackValuesIntoLocals(List<Type> directOrder, int shift, InstructionAdapter iv, String descriptor) {
Type[] actualParams = Type.getArgumentTypes(descriptor);
assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!";
int size = 0;
@@ -520,9 +450,9 @@ public class MethodInliner {
shift -= next.getSize();
Type typeOnStack = actualParams[--index];
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;
//in case when parameter could be extracted from outer context (e.g. from local var)
private StackValue remapIndex;
private StackValue remapValue;
public LambdaInfo lambda;
ParameterInfo(Type type, boolean skipped, int index, int remapIndex) {
this(type, skipped, index, remapIndex == -1 ? null : StackValue.local(remapIndex, type));
ParameterInfo(Type type, boolean skipped, int index, int remapValue) {
this(type, skipped, index, remapValue == -1 ? null : StackValue.local(remapValue, type));
}
ParameterInfo(Type type, boolean skipped, int index, StackValue stackValue) {
this.type = type;
this.isSkipped = skipped;
this.remapIndex = stackValue;
this.remapValue = stackValue;
this.index = index;
}
public boolean isSkippedOrRemapped() {
return isSkipped || remapIndex != null;
return isSkipped || remapValue != null;
}
public boolean isRemapped() {
return remapIndex != null;
return remapValue != null;
}
@Nullable
public StackValue getRemapIndex() {
return remapIndex;
public StackValue getRemapValue() {
return remapValue;
}
public int getIndex() {
@@ -84,7 +84,7 @@ class ParameterInfo {
this.lambda = lambda;
}
public void setRemapIndex(StackValue remapIndex) {
this.remapIndex = remapIndex;
public void setRemapValue(StackValue remapValue) {
this.remapValue = remapValue;
}
}
@@ -60,20 +60,6 @@ public class Parameters implements Iterable<ParameterInfo> {
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) {
List<CapturedParamInfo> result = new ArrayList<CapturedParamInfo>();
for (CapturedParamInfo capturedParamInfo : capturedParams) {
@@ -27,7 +27,6 @@ public class ParametersBuilder {
private final List<ParameterInfo> params = new ArrayList<ParameterInfo>();
private final List<CapturedParamInfo> capturedParams = new ArrayList<CapturedParamInfo>();
private final List<CapturedParamInfo> additionalCapturedParams = new ArrayList<CapturedParamInfo>();
private int nextIndex = 0;
private int nextCaptured = 0;
@@ -36,9 +35,10 @@ public class ParametersBuilder {
return new ParametersBuilder();
}
public ParametersBuilder addThis(Type type, boolean skipped) {
addParameter(new ParameterInfo(type, skipped, nextIndex, -1));
return this;
public ParameterInfo addThis(Type type, boolean skipped) {
ParameterInfo info = new ParameterInfo(type, skipped, nextIndex, -1);
addParameter(info);
return info;
}
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 {
private int shift;
private final int shift;
public ShiftAdapter(MethodVisitor mv, int shift) {
super(mv);
@@ -32,9 +32,9 @@ public abstract class VarRemapper {
private final Parameters params;
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) {
this.additionalShift = additionalShift;
@@ -42,15 +42,15 @@ public abstract class VarRemapper {
this.params = params;
int realSize = 0;
remapIndex = new StackValue [params.totalSize()];
remapValues = new StackValue [params.totalSize()];
int index = 0;
for (ParameterInfo info : params) {
if (!info.isSkippedOrRemapped()) {
remapIndex[index] = StackValue.local(realSize, AsmTypeConstants.OBJECT_TYPE);
remapValues[index] = StackValue.local(realSize, AsmTypeConstants.OBJECT_TYPE);
realSize += info.getType().getSize();
} else {
remapIndex[index] = info.isRemapped() ? info.getRemapIndex() : null;
remapValues[index] = info.isRemapped() ? info.getRemapValue() : null;
}
index++;
}
@@ -64,7 +64,7 @@ public abstract class VarRemapper {
if (index < allParamsSize) {
ParameterInfo info = params.get(index);
StackValue remapped = remapIndex[index];
StackValue remapped = remapValues[index];
if (info.isSkipped || remapped == null) {
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);
if (remapInfo.parameterInfo != null) {
value.coerce(value.type, remapInfo.parameterInfo.type, mv);
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);
}
}