Method && Closure Inline
This commit is contained in:
@@ -42,7 +42,6 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
|
||||
protected final OwnerKind kind;
|
||||
protected final ClassDescriptor descriptor;
|
||||
protected final ClassBuilder v;
|
||||
protected final ClassContext context;
|
||||
|
||||
private MethodVisitor clInitMethod;
|
||||
|
||||
@@ -55,10 +54,9 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
|
||||
@NotNull GenerationState state,
|
||||
@Nullable MemberCodegen parentCodegen
|
||||
) {
|
||||
super(state, parentCodegen);
|
||||
super(state, parentCodegen, context, v);
|
||||
descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
|
||||
myClass = aClass;
|
||||
this.context = context;
|
||||
this.kind = context.getContextKind();
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
@@ -28,12 +28,15 @@ import org.jetbrains.asm4.commons.Method;
|
||||
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
import org.jetbrains.jet.codegen.context.LocalLookup;
|
||||
import org.jetbrains.jet.codegen.context.MethodContext;
|
||||
import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
|
||||
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
@@ -294,7 +297,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl {
|
||||
return signature;
|
||||
}
|
||||
|
||||
private static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) {
|
||||
public static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) {
|
||||
int paramCount = funDescriptor.getValueParameters().size();
|
||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||
ClassDescriptor funClass = funDescriptor.getReceiverParameter() == null
|
||||
|
||||
@@ -32,6 +32,8 @@ import org.jetbrains.asm4.MethodVisitor;
|
||||
import org.jetbrains.asm4.Type;
|
||||
import org.jetbrains.asm4.commons.InstructionAdapter;
|
||||
import org.jetbrains.asm4.commons.Method;
|
||||
import org.jetbrains.jet.codegen.asm.InlineCodegen;
|
||||
import org.jetbrains.jet.codegen.asm.Inliner;
|
||||
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.jet.codegen.binding.MutableClosure;
|
||||
@@ -1353,27 +1355,38 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
protected void pushClosureOnStack(CalculatedClosure closure, boolean ignoreThisAndReceiver) {
|
||||
pushClosureOnStack(closure, ignoreThisAndReceiver, Inliner.NOT_INLINE);
|
||||
}
|
||||
|
||||
public void pushClosureOnStack(CalculatedClosure closure, boolean ignoreThisAndReceiver, Inliner inliner) {
|
||||
if (closure != null) {
|
||||
if (!ignoreThisAndReceiver) {
|
||||
ClassDescriptor captureThis = closure.getCaptureThis();
|
||||
if (captureThis != null) {
|
||||
generateThisOrOuter(captureThis, false).put(OBJECT_TYPE, v);
|
||||
StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
|
||||
thisOrOuter.put(OBJECT_TYPE, v);
|
||||
inliner.putInLocal(OBJECT_TYPE, thisOrOuter);
|
||||
}
|
||||
|
||||
JetType captureReceiver = closure.getCaptureReceiverType();
|
||||
if (captureReceiver != null) {
|
||||
v.load(context.isStatic() ? 0 : 1, typeMapper.mapType(captureReceiver));
|
||||
Type asmType = typeMapper.mapType(captureReceiver);
|
||||
StackValue.Local capturedReceiver = StackValue.local(context.isStatic() ? 0 : 1, asmType);
|
||||
capturedReceiver.put(asmType, v);
|
||||
inliner.putInLocal(asmType, capturedReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
|
||||
//if (entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) {
|
||||
Type sharedVarType = typeMapper.getSharedVarType(entry.getKey());
|
||||
if (sharedVarType == null) {
|
||||
sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey());
|
||||
}
|
||||
entry.getValue().getOuterValue(this).put(sharedVarType, v);
|
||||
//}
|
||||
StackValue capturedVar = entry.getValue().getOuterValue(this);
|
||||
if (inliner.shouldPutValue(sharedVarType, capturedVar, context)) {
|
||||
capturedVar.put(sharedVarType, v);
|
||||
}
|
||||
inliner.putInLocal(sharedVarType, capturedVar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1971,7 +1984,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
@NotNull
|
||||
public StackValue invokeFunction(
|
||||
Call call,
|
||||
@NotNull Call call,
|
||||
StackValue receiver,
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall
|
||||
) {
|
||||
@@ -2095,20 +2108,31 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
|
||||
@NotNull StackValue receiver
|
||||
) {
|
||||
boolean disable = false;
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
boolean isInline = descriptor instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) descriptor).isInline();
|
||||
Inliner inliner = !isInline ? Inliner.NOT_INLINE
|
||||
: new InlineCodegen(this, true, state, disable, (SimpleFunctionDescriptor) unwrapFakeOverride((CallableMemberDescriptor)descriptor.getOriginal()));
|
||||
|
||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||
resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
|
||||
}
|
||||
|
||||
if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already
|
||||
if (!(descriptor instanceof ConstructorDescriptor)) { // otherwise already
|
||||
receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
|
||||
receiver.put(receiver.type, v);
|
||||
}
|
||||
|
||||
pushArgumentsAndInvoke(resolvedCall, callableMethod);
|
||||
assert inliner == Inliner.NOT_INLINE || !hasDefaults(resolvedCall) && !tailRecursionCodegen.isTailRecursion(resolvedCall) :
|
||||
"Method with defaults or tail recursive couldn't be inlined " + descriptor;
|
||||
|
||||
pushArgumentsAndInvoke(resolvedCall, callableMethod, inliner);
|
||||
}
|
||||
|
||||
private void pushArgumentsAndInvoke(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableMethod callable) {
|
||||
int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes());
|
||||
private void pushArgumentsAndInvoke(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableMethod callable, @NotNull Inliner inliner) {
|
||||
inliner.putHiddenParams();
|
||||
|
||||
int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes(), inliner);
|
||||
|
||||
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
|
||||
tailRecursionCodegen.generateTailRecursion(resolvedCall);
|
||||
@@ -2116,11 +2140,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
if (mask == 0) {
|
||||
callable.invokeWithNotNullAssertion(v, state, resolvedCall);
|
||||
if (inliner != Inliner.NOT_INLINE) {
|
||||
inliner.inlineCall(callable, getParentCodegen().getBuilder().getVisitor());
|
||||
} else {
|
||||
callable.invokeWithNotNullAssertion(v, state, resolvedCall);
|
||||
}
|
||||
}
|
||||
else {
|
||||
callable.invokeDefaultWithNotNullAssertion(v, state, resolvedCall, mask);
|
||||
}
|
||||
|
||||
inliner.leaveTemps();
|
||||
}
|
||||
|
||||
private void genThisAndReceiverFromResolvedCall(
|
||||
@@ -2283,10 +2313,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List<Type> valueParameterTypes) {
|
||||
return pushMethodArguments(resolvedCall, valueParameterTypes, false);
|
||||
return pushMethodArguments(resolvedCall, valueParameterTypes, null);
|
||||
}
|
||||
|
||||
private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List<Type> valueParameterTypes, boolean skipLast) {
|
||||
return pushMethodArguments(resolvedCall, valueParameterTypes, skipLast, null);
|
||||
}
|
||||
|
||||
private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List<Type> valueParameterTypes, Inliner inliner) {
|
||||
return pushMethodArguments(resolvedCall, valueParameterTypes, false, inliner);
|
||||
}
|
||||
|
||||
private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List<Type> valueParameterTypes, boolean skipLast, Inliner inliner) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
|
||||
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
||||
@@ -2296,15 +2334,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
inliner = inliner != null ? inliner : Inliner.NOT_INLINE;
|
||||
int mask = 0;
|
||||
|
||||
|
||||
for (Iterator<ValueParameterDescriptor> iterator = valueParameters.iterator(); iterator.hasNext(); ) {
|
||||
ValueParameterDescriptor valueParameter = iterator.next();
|
||||
if (skipLast && !iterator.hasNext()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean putInLocal = true;
|
||||
StackValue valueIfPresent = null;
|
||||
|
||||
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
|
||||
Type parameterType = valueParameterTypes.get(valueParameter.getIndex());
|
||||
if (resolvedValueArgument instanceof ExpressionValueArgument) {
|
||||
@@ -2313,9 +2354,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
assert argumentExpression != null : valueArgument.asElement().getText();
|
||||
|
||||
gen(argumentExpression, parameterType);
|
||||
}
|
||||
else if (resolvedValueArgument instanceof DefaultValueArgument) {
|
||||
if (inliner.isInliningClosure(argumentExpression)) {
|
||||
inliner.rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType);
|
||||
putInLocal = false;
|
||||
} else {
|
||||
StackValue value = gen(argumentExpression);
|
||||
if (inliner.shouldPutValue(parameterType, value, context)) {
|
||||
value.put(parameterType, v);
|
||||
}
|
||||
valueIfPresent = value;
|
||||
}
|
||||
} else if (resolvedValueArgument instanceof DefaultValueArgument) {
|
||||
pushDefaultValueOnStack(parameterType, v);
|
||||
mask |= (1 << valueParameter.getIndex());
|
||||
}
|
||||
@@ -2326,10 +2375,29 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
if (putInLocal) {
|
||||
inliner.putInLocal(parameterType, valueIfPresent);
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
private boolean hasDefaults(@NotNull ResolvedCall resolvedCall) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
|
||||
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
||||
|
||||
for (ValueParameterDescriptor valueParameter : fd.getValueParameters()) {
|
||||
StackValue valueIfPresent = null;
|
||||
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
|
||||
if (resolvedValueArgument instanceof DefaultValueArgument) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void genVarargs(ValueParameterDescriptor valueParameterDescriptor, VarargValueArgument valueArgument) {
|
||||
JetType outType = valueParameterDescriptor.getType();
|
||||
|
||||
@@ -2576,7 +2644,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
@NotNull
|
||||
private ReceiverValue computeAndSaveReceiver(
|
||||
@NotNull JvmMethodSignature signature,
|
||||
@NotNull JvmMethodSignature signature,
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@Nullable ReceiverParameterDescriptor receiver
|
||||
) {
|
||||
@@ -2951,7 +3019,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
receiver.put(receiver.type, v);
|
||||
}
|
||||
|
||||
pushArgumentsAndInvoke(resolvedCall, callable);
|
||||
pushArgumentsAndInvoke(resolvedCall, callable, Inliner.NOT_INLINE);
|
||||
|
||||
if (keepReturnValue) {
|
||||
value.store(callable.getReturnType(), v);
|
||||
@@ -3823,4 +3891,26 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
}
|
||||
throw new IllegalStateException("Script codegen should be present in codegen tree");
|
||||
}
|
||||
|
||||
public InstructionAdapter getInstructionAdapter() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public JetTypeMapper getTypeMapper() {
|
||||
return typeMapper;
|
||||
}
|
||||
|
||||
public MethodVisitor getMethodVisitor() {
|
||||
return methodVisitor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FrameMap getFrameMap() {
|
||||
return myFrameMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MethodContext getContext() {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@ public class FrameMap {
|
||||
return new Mark(myMaxIndex);
|
||||
}
|
||||
|
||||
public int getCurrentSize() {
|
||||
return myMaxIndex;
|
||||
}
|
||||
|
||||
public class Mark {
|
||||
private final int myIndex;
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
||||
mv,
|
||||
jvmSignature,
|
||||
functionDescriptor,
|
||||
getThisTypeForFunction(functionDescriptor, methodContext),
|
||||
getThisTypeForFunction(functionDescriptor, methodContext, state.getTypeMapper()),
|
||||
new Label(),
|
||||
new Label(),
|
||||
methodContext.getContextKind()
|
||||
@@ -138,7 +138,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy);
|
||||
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, getParentCodegen());
|
||||
|
||||
endVisit(mv, null, origin);
|
||||
|
||||
@@ -237,7 +237,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context) {
|
||||
private static Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context, @NotNull JetTypeMapper typeMapper) {
|
||||
ReceiverParameterDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject();
|
||||
if (functionDescriptor instanceof ConstructorDescriptor) {
|
||||
return typeMapper.mapType(functionDescriptor);
|
||||
@@ -253,18 +253,22 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateMethodBody(
|
||||
public static void generateMethodBody(
|
||||
@NotNull MethodVisitor mv,
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@NotNull MethodContext context,
|
||||
@NotNull JvmMethodSignature signature,
|
||||
@NotNull FunctionGenerationStrategy strategy
|
||||
@NotNull FunctionGenerationStrategy strategy,
|
||||
@NotNull MemberCodegen parentCodegen
|
||||
) {
|
||||
mv.visitCode();
|
||||
|
||||
Label methodBegin = new Label();
|
||||
mv.visitLabel(methodBegin);
|
||||
|
||||
GenerationState state = parentCodegen.getState();
|
||||
JetTypeMapper typeMapper = state.getTypeMapper();
|
||||
|
||||
if (context.getParentContext() instanceof PackageFacadeContext) {
|
||||
generateStaticDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext());
|
||||
}
|
||||
@@ -283,15 +287,16 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
||||
genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
|
||||
}
|
||||
|
||||
strategy.generateBody(mv, signature, context, getParentCodegen());
|
||||
strategy.generateBody(mv, signature, context, parentCodegen);
|
||||
}
|
||||
|
||||
Label methodEnd = new Label();
|
||||
mv.visitLabel(methodEnd);
|
||||
|
||||
|
||||
Type thisType = getThisTypeForFunction(functionDescriptor, context);
|
||||
generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind());
|
||||
if (strategy.generateLocalVarTable()) {
|
||||
Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper);
|
||||
generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind());
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateLocalVariableTable(
|
||||
|
||||
@@ -50,6 +50,10 @@ public abstract class FunctionGenerationStrategy {
|
||||
return frameMap;
|
||||
}
|
||||
|
||||
public boolean generateLocalVarTable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class FunctionDefault extends CodegenBased<CallableDescriptor> {
|
||||
private final JetDeclarationWithBody declaration;
|
||||
|
||||
|
||||
@@ -24,16 +24,34 @@ import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
import org.jetbrains.jet.codegen.context.FieldOwnerContext;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.name.SpecialNames;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class MemberCodegen extends ParentCodegenAwareImpl {
|
||||
|
||||
public MemberCodegen(@NotNull GenerationState state, @Nullable MemberCodegen parentCodegen) {
|
||||
protected final FieldOwnerContext context;
|
||||
|
||||
private final ClassBuilder builder;
|
||||
|
||||
@NotNull
|
||||
private Map<FunctionDescriptor, ClosureCodegen> inlinedClosures = new HashMap<FunctionDescriptor, ClosureCodegen>();
|
||||
|
||||
public MemberCodegen(
|
||||
@NotNull GenerationState state,
|
||||
@Nullable MemberCodegen parentCodegen,
|
||||
FieldOwnerContext context,
|
||||
ClassBuilder builder
|
||||
) {
|
||||
super(state, parentCodegen);
|
||||
this.context = context;
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
public void genFunctionOrProperty(
|
||||
@@ -75,35 +93,45 @@ public class MemberCodegen extends ParentCodegenAwareImpl {
|
||||
}
|
||||
}
|
||||
|
||||
public void genClassOrObject(CodegenContext parentContext, JetClassOrObject aClass) {
|
||||
public static void genClassOrObject(
|
||||
@NotNull CodegenContext parentContext,
|
||||
@NotNull JetClassOrObject aClass,
|
||||
@NotNull GenerationState state,
|
||||
@Nullable MemberCodegen parentCodegen
|
||||
) {
|
||||
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
|
||||
|
||||
if (descriptor == null || ErrorUtils.isError(descriptor)) {
|
||||
badDescriptor(descriptor);
|
||||
badDescriptor(descriptor, state.getClassBuilderMode());
|
||||
return;
|
||||
}
|
||||
|
||||
if (descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED)) {
|
||||
badDescriptor(descriptor);
|
||||
badDescriptor(descriptor, state.getClassBuilderMode());
|
||||
}
|
||||
|
||||
ClassBuilder classBuilder = state.getFactory().forClassImplementation(descriptor, aClass.getContainingFile());
|
||||
ClassContext classContext = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state);
|
||||
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, this).generate();
|
||||
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, parentCodegen).generate();
|
||||
classBuilder.done();
|
||||
|
||||
if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
|
||||
ClassBuilder traitBuilder = state.getFactory().forTraitImplementation(descriptor, state, aClass.getContainingFile());
|
||||
new TraitImplBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state, this)
|
||||
new TraitImplBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state, parentCodegen)
|
||||
.generate();
|
||||
traitBuilder.done();
|
||||
}
|
||||
}
|
||||
|
||||
private void badDescriptor(ClassDescriptor descriptor) {
|
||||
if (state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) {
|
||||
private static void badDescriptor(ClassDescriptor descriptor, ClassBuilderMode mode) {
|
||||
if (mode != ClassBuilderMode.LIGHT_CLASSES) {
|
||||
throw new IllegalStateException(
|
||||
"Generating bad descriptor in ClassBuilderMode = " + state.getClassBuilderMode() + ": " + descriptor);
|
||||
"Generating bad descriptor in ClassBuilderMode = " + mode + ": " + descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassBuilder getBuilder() {
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.asm4.Type;
|
||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
import org.jetbrains.jet.codegen.context.FieldOwnerContext;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.state.GenerationStateAware;
|
||||
import org.jetbrains.jet.descriptors.serialization.BitEncoding;
|
||||
import org.jetbrains.jet.descriptors.serialization.DescriptorSerializer;
|
||||
import org.jetbrains.jet.descriptors.serialization.PackageData;
|
||||
@@ -53,7 +54,8 @@ import static org.jetbrains.jet.codegen.AsmUtil.asmTypeByFqNameWithoutInnerClass
|
||||
import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver;
|
||||
import static org.jetbrains.jet.lang.resolve.java.PackageClassUtils.getPackageClassFqName;
|
||||
|
||||
public class PackageCodegen extends MemberCodegen {
|
||||
public class PackageCodegen extends GenerationStateAware {
|
||||
@NotNull
|
||||
private final ClassBuilderOnDemand v;
|
||||
|
||||
@NotNull
|
||||
@@ -69,7 +71,7 @@ public class PackageCodegen extends MemberCodegen {
|
||||
@NotNull GenerationState state,
|
||||
@NotNull Collection<JetFile> packageFiles
|
||||
) {
|
||||
super(state, null);
|
||||
super(state);
|
||||
checkAllFilesHaveSamePackage(packageFiles);
|
||||
|
||||
this.v = v;
|
||||
@@ -192,10 +194,10 @@ public class PackageCodegen extends MemberCodegen {
|
||||
new PackagePartCodegen(builder, file, packagePartType, packagePartContext, state).generate();
|
||||
|
||||
FieldOwnerContext packageFacade = CodegenContext.STATIC.intoPackageFacade(packagePartType, getPackageFragment(file));
|
||||
|
||||
MemberCodegen memberCodegen = new MemberCodegen(state, null, packageFacade, null);
|
||||
for (JetDeclaration declaration : file.getDeclarations()) {
|
||||
if (declaration instanceof JetNamedFunction || declaration instanceof JetProperty) {
|
||||
genFunctionOrProperty(packageFacade, (JetTypeParameterListOwner) declaration, v.getClassBuilder());
|
||||
memberCodegen.genFunctionOrProperty(packageFacade, (JetTypeParameterListOwner) declaration, v.getClassBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +213,7 @@ public class PackageCodegen extends MemberCodegen {
|
||||
|
||||
public void generateClassOrObject(@NotNull JetClassOrObject classOrObject) {
|
||||
CodegenContext context = CodegenContext.STATIC.intoPackagePart(getPackageFragment((JetFile) classOrObject.getContainingFile()));
|
||||
genClassOrObject(context, classOrObject);
|
||||
MemberCodegen.genClassOrObject(context, classOrObject, state, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,7 +59,7 @@ public class PackagePartCodegen extends MemberCodegen {
|
||||
@NotNull FieldOwnerContext context,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
super(state, null);
|
||||
super(state, null, context, v);
|
||||
this.v = v;
|
||||
this.jetFile = jetFile;
|
||||
this.packagePartName = packagePartName;
|
||||
|
||||
@@ -53,8 +53,12 @@ public class ScriptCodegen extends MemberCodegen {
|
||||
ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, scriptDescriptor);
|
||||
assert classDescriptorForScript != null;
|
||||
|
||||
Type className = state.getBindingContext().get(ASM_TYPE, classDescriptorForScript);
|
||||
assert className != null;
|
||||
|
||||
ClassBuilder builder = state.getFactory().newVisitor(className, declaration.getContainingFile());
|
||||
ScriptContext scriptContext = parentContext.intoScript(scriptDescriptor, classDescriptorForScript);
|
||||
return new ScriptCodegen(declaration, state, scriptContext, state.getEarlierScriptsForReplInterpreter());
|
||||
return new ScriptCodegen(declaration, state, scriptContext, state.getEarlierScriptsForReplInterpreter(), builder);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -70,9 +74,10 @@ public class ScriptCodegen extends MemberCodegen {
|
||||
@NotNull JetScript scriptDeclaration,
|
||||
@NotNull GenerationState state,
|
||||
@NotNull ScriptContext context,
|
||||
@Nullable List<ScriptDescriptor> earlierScripts
|
||||
@Nullable List<ScriptDescriptor> earlierScripts,
|
||||
@NotNull ClassBuilder builder
|
||||
) {
|
||||
super(state, null);
|
||||
super(state, null, context, builder);
|
||||
this.scriptDeclaration = scriptDeclaration;
|
||||
this.context = context;
|
||||
this.earlierScripts = earlierScripts == null ? Collections.<ScriptDescriptor>emptyList() : earlierScripts;
|
||||
@@ -84,8 +89,7 @@ public class ScriptCodegen extends MemberCodegen {
|
||||
Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript);
|
||||
assert classType != null;
|
||||
|
||||
ClassBuilder classBuilder = state.getFactory().newVisitor(classType, scriptDeclaration.getContainingFile());
|
||||
|
||||
ClassBuilder classBuilder = getBuilder();
|
||||
classBuilder.defineClass(scriptDeclaration,
|
||||
V1_6,
|
||||
ACC_PUBLIC,
|
||||
|
||||
@@ -387,6 +387,10 @@ public abstract class StackValue {
|
||||
coerceFrom(topOfStackType, v);
|
||||
v.store(index, this.type);
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
public static class OnStack extends StackValue {
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.asm;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.asm4.Type;
|
||||
import org.jetbrains.asm4.tree.MethodNode;
|
||||
import org.jetbrains.jet.codegen.AsmUtil;
|
||||
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
|
||||
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.JvmClassName;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.CLOSURE;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.anonymousClassForFunction;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
|
||||
|
||||
public class ClosureInfo {
|
||||
|
||||
public final JetFunctionLiteralExpression expression;
|
||||
|
||||
@NotNull private final JetTypeMapper typeMapper;
|
||||
|
||||
public final CalculatedClosure closure;
|
||||
|
||||
private MethodNode node;
|
||||
|
||||
private Collection<EnclosedValueDescriptor> capturedVars;
|
||||
|
||||
private final FunctionDescriptor functionDescriptor;
|
||||
|
||||
private final ClassDescriptor classDescriptor;
|
||||
|
||||
private final Type closureClassType;
|
||||
|
||||
private int paramOffset;
|
||||
|
||||
ClosureInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper) {
|
||||
this.expression = expression;
|
||||
this.typeMapper = typeMapper;
|
||||
BindingContext bindingContext = typeMapper.getBindingContext();
|
||||
functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression.getFunctionLiteral());
|
||||
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
|
||||
|
||||
classDescriptor = anonymousClassForFunction(bindingContext, functionDescriptor);
|
||||
closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
|
||||
|
||||
closure = bindingContext.get(CLOSURE, classDescriptor);
|
||||
|
||||
}
|
||||
|
||||
public MethodNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
public void setNode(MethodNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public FunctionDescriptor getFunctionDescriptor() {
|
||||
return functionDescriptor;
|
||||
}
|
||||
|
||||
public JetFunctionLiteral getFunctionLiteral() {
|
||||
return expression.getFunctionLiteral();
|
||||
}
|
||||
|
||||
public ClassDescriptor getClassDescriptor() {
|
||||
return classDescriptor;
|
||||
}
|
||||
|
||||
public Type getClosureClassType() {
|
||||
return closureClassType;
|
||||
}
|
||||
|
||||
public Collection<EnclosedValueDescriptor> getCapturedVars() {
|
||||
//lazy initialization cause it would be calculated after object creation
|
||||
if (capturedVars == null) {
|
||||
capturedVars = new ArrayList<EnclosedValueDescriptor>();
|
||||
|
||||
if (closure.getCaptureThis() != null) {
|
||||
EnclosedValueDescriptor descriptor = new EnclosedValueDescriptor(AsmUtil.CAPTURED_THIS_FIELD, null, null, typeMapper.mapType(closure.getCaptureThis()));
|
||||
capturedVars.add(descriptor);
|
||||
}
|
||||
|
||||
if (closure.getCaptureReceiverType() != null) {
|
||||
EnclosedValueDescriptor descriptor = new EnclosedValueDescriptor(AsmUtil.CAPTURED_RECEIVER_FIELD, null, null, typeMapper.mapType(closure.getCaptureReceiverType()));
|
||||
capturedVars.add(descriptor);
|
||||
}
|
||||
|
||||
if (closure != null) {
|
||||
capturedVars.addAll(closure.getCaptureVariables().values());
|
||||
}
|
||||
}
|
||||
return capturedVars;
|
||||
}
|
||||
|
||||
public int getParamOffset() {
|
||||
return paramOffset;
|
||||
}
|
||||
|
||||
public void setParamOffset(int paramOffset) {
|
||||
this.paramOffset = paramOffset;
|
||||
}
|
||||
|
||||
public List<Type> getParamsWithoutCapturedValOrVar() {
|
||||
Type[] types = typeMapper.mapSignature(functionDescriptor).getAsmMethod().getArgumentTypes();
|
||||
return Arrays.asList(types);
|
||||
}
|
||||
|
||||
public int getCapturedVarsSize() {
|
||||
int size = 0;
|
||||
for (Iterator<EnclosedValueDescriptor> iterator = getCapturedVars().iterator(); iterator.hasNext(); ) {
|
||||
EnclosedValueDescriptor next = iterator.next();
|
||||
size += next.getType().getSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.asm;
|
||||
|
||||
class ClosureUsage {
|
||||
|
||||
public final int index;
|
||||
|
||||
public final boolean inlinable;
|
||||
|
||||
ClosureUsage(int index, boolean isInlinable) {
|
||||
this.index = index;
|
||||
inlinable = isInlinable;
|
||||
}
|
||||
|
||||
public boolean isInlinable() {
|
||||
return inlinable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.asm;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.asm4.*;
|
||||
import org.jetbrains.asm4.commons.InstructionAdapter;
|
||||
import org.jetbrains.asm4.commons.Method;
|
||||
import org.jetbrains.asm4.tree.*;
|
||||
import org.jetbrains.asm4.tree.analysis.*;
|
||||
import org.jetbrains.asm4.tree.analysis.Frame;
|
||||
import org.jetbrains.asm4.util.Textifier;
|
||||
import org.jetbrains.asm4.util.TraceMethodVisitor;
|
||||
import org.jetbrains.jet.codegen.*;
|
||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
|
||||
import org.jetbrains.jet.codegen.context.MethodContext;
|
||||
import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
|
||||
import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature;
|
||||
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedSimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.*;
|
||||
|
||||
public class InlineCodegen implements ParentCodegenAware, Inliner {
|
||||
|
||||
public final static String INVOKE = "invoke";
|
||||
|
||||
private final ExpressionCodegen codegen;
|
||||
|
||||
private final boolean notSeparateInline;
|
||||
|
||||
private final GenerationState state;
|
||||
|
||||
private final boolean disabled;
|
||||
|
||||
private final SimpleFunctionDescriptor functionDescriptor;
|
||||
|
||||
private final List<ParameterInfo> tempTypes = new ArrayList<ParameterInfo>();
|
||||
|
||||
private final List<ClosureUsage> closures = new ArrayList<ClosureUsage>();
|
||||
|
||||
private final Map<Integer, ClosureInfo> expressionMap = new HashMap<Integer, ClosureInfo>();
|
||||
|
||||
private final JetTypeMapper typeMapper;
|
||||
|
||||
private final BindingContext bindingContext;
|
||||
|
||||
private final MethodContext context;
|
||||
|
||||
private final FrameMap originalFunctionFrame;
|
||||
|
||||
private final int initialFrameSize;
|
||||
|
||||
private final JvmMethodSignature jvmSignature;
|
||||
|
||||
public InlineCodegen(
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
boolean notSeparateInline,
|
||||
@NotNull GenerationState state,
|
||||
boolean disabled,
|
||||
@NotNull SimpleFunctionDescriptor functionDescriptor
|
||||
) {
|
||||
this.codegen = codegen;
|
||||
this.notSeparateInline = notSeparateInline;
|
||||
this.state = state;
|
||||
this.disabled = disabled;
|
||||
this.functionDescriptor = functionDescriptor.getOriginal();
|
||||
typeMapper = codegen.getTypeMapper();
|
||||
bindingContext = codegen.getBindingContext();
|
||||
initialFrameSize = codegen.getFrameMap().getCurrentSize();
|
||||
|
||||
context = (MethodContext) getContext(functionDescriptor, state);
|
||||
originalFunctionFrame = context.prepareFrame(typeMapper);
|
||||
jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void inlineCall(CallableMethod callableMethod, ClassVisitor visitor) {
|
||||
MethodNode node = null;
|
||||
|
||||
try {
|
||||
node = createMethodNode(callableMethod);
|
||||
inlineCall(node, true);
|
||||
}
|
||||
catch (CompilationException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
String text = getNodeText(node);
|
||||
PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, codegen.getContext().getContextDescriptor());
|
||||
throw new CompilationException("Couldn't inline method call '" +
|
||||
functionDescriptor.getName() +
|
||||
"' into \n" + (element != null ? element.getText() : "null psi element " + codegen.getContext().getContextDescriptor()) +
|
||||
"\ncause: " +
|
||||
text, e, null);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private MethodNode createMethodNode(CallableMethod callableMethod)
|
||||
throws ClassNotFoundException, IOException {
|
||||
MethodNode node = null;
|
||||
if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
|
||||
VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable((DeserializedSimpleFunctionDescriptor) functionDescriptor, state);
|
||||
node = InlineCodegenUtil.getMethodNode(file.getInputStream(), functionDescriptor.getName().asString(),
|
||||
callableMethod.getAsmMethod().getDescriptor());
|
||||
|
||||
if (node == null) {
|
||||
throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
|
||||
}
|
||||
}
|
||||
else {
|
||||
PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, functionDescriptor);
|
||||
|
||||
if (element == null) {
|
||||
throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor));
|
||||
}
|
||||
|
||||
JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
|
||||
Method asmMethod = jvmSignature.getAsmMethod();
|
||||
node = new MethodNode(Opcodes.ASM4,
|
||||
getMethodAsmFlags(functionDescriptor, context.getContextKind()),
|
||||
asmMethod.getName(),
|
||||
asmMethod.getDescriptor(),
|
||||
jvmSignature.getGenericsSignature(),
|
||||
null);
|
||||
|
||||
FunctionCodegen.generateMethodBody(node, functionDescriptor, context.getParentContext().intoFunction(functionDescriptor),
|
||||
jvmSignature,
|
||||
new FunctionGenerationStrategy.FunctionDefault(state,
|
||||
functionDescriptor,
|
||||
(JetDeclarationWithBody) element),
|
||||
getParentCodegen());
|
||||
//TODO
|
||||
node.visitMaxs(20, 20);
|
||||
node.visitEnd();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private void inlineCall(MethodNode node, boolean inlineClosures) {
|
||||
if (inlineClosures) {
|
||||
removeClosureAssertions(node);
|
||||
try {
|
||||
markPlacesForInlineAndRemoveInlinable(node);
|
||||
}
|
||||
catch (AnalyzerException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
int valueParamSize = originalFunctionFrame.getCurrentSize();
|
||||
int originalSize = codegen.getFrameMap().getCurrentSize();
|
||||
generateClosuresBodies();
|
||||
putClosureParametersOnStack();
|
||||
int additionalParams = codegen.getFrameMap().getCurrentSize() - originalSize;
|
||||
VarRemapper remapper = new VarRemapper.ParamRemapper(initialFrameSize, valueParamSize, additionalParams, tempTypes);
|
||||
|
||||
doInline(node.access, node.desc, codegen.getMethodVisitor(), node, remapper.doRemap(valueParamSize + additionalParams), inlineClosures, remapper);
|
||||
}
|
||||
|
||||
private void removeClosureAssertions(MethodNode node) {
|
||||
AbstractInsnNode cur = node.instructions.getFirst();
|
||||
while (cur != null && cur.getNext() != null) {
|
||||
AbstractInsnNode next = cur.getNext();
|
||||
if (next.getType() == AbstractInsnNode.METHOD_INSN) {
|
||||
MethodInsnNode methodInsnNode = (MethodInsnNode) next;
|
||||
if (methodInsnNode.name.equals("checkParameterIsNotNull") && methodInsnNode.owner.equals("jet/runtime/Intrinsics")) {
|
||||
AbstractInsnNode prev = cur.getPrevious();
|
||||
assert prev.getType() == AbstractInsnNode.VAR_INSN && prev.getOpcode() == Opcodes.ALOAD;
|
||||
int varIndex = ((VarInsnNode) prev).var;
|
||||
ClosureInfo closure = expressionMap.get(varIndex);
|
||||
if (closure != null) {
|
||||
node.instructions.remove(prev);
|
||||
node.instructions.remove(cur);
|
||||
cur = next.getNext();
|
||||
node.instructions.remove(next);
|
||||
next = cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
private void markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) throws AnalyzerException {
|
||||
Analyzer<SourceValue> analyzer = new Analyzer<SourceValue>(new SourceInterpreter());
|
||||
Frame<SourceValue>[] sources = analyzer.analyze("fake", node);
|
||||
|
||||
AbstractInsnNode cur = node.instructions.getFirst();
|
||||
int index = 0;
|
||||
while (cur != null) {
|
||||
if (cur.getType() == AbstractInsnNode.METHOD_INSN) {
|
||||
MethodInsnNode methodInsnNode = (MethodInsnNode) cur;
|
||||
//TODO check closure
|
||||
if (isInvokeOnInlinable(methodInsnNode.owner, methodInsnNode.name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) {
|
||||
Frame<SourceValue> frame = sources[index];
|
||||
SourceValue sourceValue = frame.getStack(frame.getStackSize() - Type.getArgumentTypes(methodInsnNode.desc).length - 1);
|
||||
assert sourceValue.insns.size() == 1;
|
||||
|
||||
AbstractInsnNode insnNode = sourceValue.insns.iterator().next();
|
||||
assert insnNode.getType() == AbstractInsnNode.VAR_INSN && insnNode.getOpcode() == Opcodes.ALOAD;
|
||||
int varIndex = ((VarInsnNode) insnNode).var;
|
||||
ClosureInfo closureInfo = expressionMap.get(varIndex);
|
||||
if (closureInfo != null) { //TODO: maybe add separate map for noninlinable closures
|
||||
closures.add(new ClosureUsage(varIndex, true));
|
||||
node.instructions.remove(insnNode);
|
||||
} else {
|
||||
closures.add(new ClosureUsage(varIndex, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
cur = cur.getNext();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
private void doInline(
|
||||
int access,
|
||||
String desc,
|
||||
MethodVisitor mv,
|
||||
MethodNode methodNode,
|
||||
int frameSize,
|
||||
final boolean inlineClosures,
|
||||
@NotNull VarRemapper remapper
|
||||
) {
|
||||
|
||||
Label end = new Label();
|
||||
|
||||
final LinkedList<ClosureUsage> infos = new LinkedList<ClosureUsage>(closures);
|
||||
methodNode.instructions.resetLabels();
|
||||
MethodVisitor methodVisitor = codegen.getMethodVisitor();
|
||||
|
||||
InliningAdapter inliner = new InliningAdapter(methodVisitor, Opcodes.ASM4, desc, end, frameSize, remapper) {
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
||||
if (inlineClosures && /*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnInlinable(owner, name)) { //TODO add method
|
||||
assert !infos.isEmpty();
|
||||
ClosureUsage closureUsage = infos.remove();
|
||||
ClosureInfo info = expressionMap.get(closureUsage.index);
|
||||
|
||||
if (!closureUsage.isInlinable()) {
|
||||
//noninlinable closure
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO replace with codegen
|
||||
int valueParamShift = getNextLocalIndex();
|
||||
remapper.setNestedRemap(true);
|
||||
putStackValuesIntoLocals(info.getParamsWithoutCapturedValOrVar(), valueParamShift, this, desc);
|
||||
Label closureEnd = new Label();
|
||||
InliningAdapter closureInliner = new InliningAdapter(mv, Opcodes.ASM4, desc, closureEnd, getNextLocalIndex(),
|
||||
new VarRemapper.ClosureRemapper(info, valueParamShift, tempTypes));
|
||||
|
||||
info.getNode().instructions.resetLabels();
|
||||
info.getNode().accept(closureInliner); //TODO
|
||||
|
||||
remapper.setNestedRemap(false);
|
||||
mv.visitLabel(closureEnd);
|
||||
|
||||
Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod();
|
||||
Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod();
|
||||
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), closureInliner);
|
||||
}
|
||||
else {
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
methodNode.accept(inliner);
|
||||
|
||||
methodVisitor.visitLabel(end);
|
||||
}
|
||||
|
||||
private boolean isInvokeOnInlinable(String owner, String name) {
|
||||
return INVOKE.equals(name) && /*TODO: check type*/owner.contains("Function");
|
||||
}
|
||||
|
||||
|
||||
private void generateClosuresBodies() {
|
||||
for (ClosureInfo info : expressionMap.values()) {
|
||||
info.setNode(generateClosureBody(info));
|
||||
}
|
||||
}
|
||||
|
||||
private MethodNode generateClosureBody(ClosureInfo info) {
|
||||
JetFunctionLiteral declaration = info.getFunctionLiteral();
|
||||
FunctionDescriptor descriptor = info.getFunctionDescriptor();
|
||||
|
||||
MethodContext parentContext = codegen.getContext();
|
||||
|
||||
MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoFunction(descriptor);
|
||||
|
||||
JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor);
|
||||
Method asmMethod = jvmMethodSignature.getAsmMethod();
|
||||
MethodNode methodNode = new MethodNode(Opcodes.ASM4, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null);
|
||||
|
||||
FunctionCodegen.generateMethodBody(methodNode, descriptor, context, jvmMethodSignature, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration) {
|
||||
@Override
|
||||
public boolean generateLocalVarTable() {
|
||||
return false;
|
||||
}
|
||||
}, codegen.getParentCodegen());
|
||||
|
||||
return transformClosure(methodNode, info);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static MethodNode transformClosure(@NotNull MethodNode node, @NotNull ClosureInfo info) {
|
||||
//remove all this and shift all variables to captured ones size
|
||||
final int localVarSHift = info.getCapturedVarsSize();
|
||||
MethodNode transformedNode = new MethodNode(node.access, node.name, node.desc, node.signature, null) {
|
||||
|
||||
private boolean remappingCaptured = false;
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
super.visitVarInsn(opcode, var + (remappingCaptured ? 0 : localVarSHift - 1/*remove this*/));
|
||||
}
|
||||
};
|
||||
node.accept(transformedNode);
|
||||
|
||||
|
||||
//remove all field access to local var
|
||||
AbstractInsnNode cur = transformedNode.instructions.getFirst();
|
||||
while (cur != null) {
|
||||
if (cur.getType() == AbstractInsnNode.FIELD_INSN) {
|
||||
FieldInsnNode fieldInsnNode = (FieldInsnNode) cur;
|
||||
//TODO check closure
|
||||
String owner = fieldInsnNode.owner;
|
||||
if (info.getClosureClassType().getInternalName().equals(fieldInsnNode.owner)) {
|
||||
int opcode = fieldInsnNode.getOpcode();
|
||||
String name = fieldInsnNode.name;
|
||||
String desc = fieldInsnNode.desc;
|
||||
|
||||
Collection<EnclosedValueDescriptor> vars = info.getCapturedVars();
|
||||
int index = 0;//skip this
|
||||
boolean found = false;
|
||||
for (EnclosedValueDescriptor valueDescriptor : vars) {
|
||||
Type type = valueDescriptor.getType();
|
||||
if (valueDescriptor.getFieldName().equals(name)) {
|
||||
opcode = opcode == Opcodes.GETFIELD ? type.getOpcode(Opcodes.ILOAD) : type.getOpcode(Opcodes.ISTORE);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
index += type.getSize();
|
||||
}
|
||||
if (!found) {
|
||||
throw new UnsupportedOperationException("Coudn't find field " +
|
||||
owner +
|
||||
"." +
|
||||
name +
|
||||
" (" +
|
||||
desc +
|
||||
") in captured vars of " +
|
||||
info.getFunctionLiteral().getText());
|
||||
}
|
||||
|
||||
|
||||
VarInsnNode varInsNode = new VarInsnNode(opcode, index);
|
||||
|
||||
AbstractInsnNode prev = cur.getPrevious();
|
||||
while (prev.getType() == AbstractInsnNode.LABEL || prev.getType() == AbstractInsnNode.LINE) {
|
||||
prev = prev.getPrevious();
|
||||
}
|
||||
|
||||
assert prev.getType() == AbstractInsnNode.VAR_INSN;
|
||||
VarInsnNode loadThis = (VarInsnNode) prev;
|
||||
assert /*loadThis.var == info.getCapturedVarsSize() - 1 && */loadThis.getOpcode() == Opcodes.ALOAD;
|
||||
|
||||
transformedNode.instructions.remove(prev);
|
||||
transformedNode.instructions.insertBefore(cur, varInsNode);
|
||||
transformedNode.instructions.remove(cur);
|
||||
cur = varInsNode;
|
||||
|
||||
}
|
||||
}
|
||||
cur = cur.getNext();
|
||||
}
|
||||
|
||||
return transformedNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putInLocal(Type type, StackValue stackValue) {
|
||||
if (!disabled && notSeparateInline && Type.VOID_TYPE != type) {
|
||||
//TODO remap only inlinable closure => otherwise we could get a lot of problem
|
||||
boolean couldBeRemapped = !shouldPutValue(type, stackValue, codegen.getContext());
|
||||
int remappedIndex = couldBeRemapped ? ((StackValue.Local) stackValue).getIndex() : -1;
|
||||
|
||||
ParameterInfo info = new ParameterInfo(type, false, remappedIndex, couldBeRemapped ? -1 : codegen.getFrameMap().enterTemp(type));
|
||||
|
||||
doWithParameter(info);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldPutValue(Type type, StackValue stackValue, MethodContext context) {
|
||||
if (stackValue != null && context.isInlineFunction() && stackValue instanceof StackValue.Local) {
|
||||
if (isInvokeOnInlinable(type.getClassName(), "invoke")) {
|
||||
//TODO remap only inlinable closure => otherwise we could get a lot of problem
|
||||
return false; //TODO check annotations
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doWithParameter(ParameterInfo info) {
|
||||
recordParamInfo(info, true);
|
||||
putParameterOnStack(info);
|
||||
}
|
||||
|
||||
private int recordParamInfo(ParameterInfo info, boolean addToFrame) {
|
||||
Type type = info.type;
|
||||
tempTypes.add(info);
|
||||
if (info.getType().getSize() == 2) {
|
||||
tempTypes.add(ParameterInfo.STUB);
|
||||
}
|
||||
if (addToFrame) {
|
||||
return originalFunctionFrame.enterTemp(type);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void putParameterOnStack(ParameterInfo info) {
|
||||
if (!info.isSkippedOrRemapped()) {
|
||||
int index = info.index;
|
||||
Type type = info.type;
|
||||
StackValue.local(index, type).store(type, codegen.getInstructionAdapter());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putHiddenParams() {
|
||||
List<JvmMethodParameterSignature> types = jvmSignature.getValueParameters();
|
||||
|
||||
if (!isStaticMethod(functionDescriptor, context)) {
|
||||
Type type = AsmTypeConstants.OBJECT_TYPE;
|
||||
ParameterInfo info = new ParameterInfo(type, false, -1, codegen.getFrameMap().enterTemp(type));
|
||||
recordParamInfo(info, false);
|
||||
}
|
||||
|
||||
for (JvmMethodParameterSignature param : types) {
|
||||
if (param.getKind() == JvmMethodParameterKind.VALUE) {
|
||||
break;
|
||||
}
|
||||
Type type = param.getAsmType();
|
||||
ParameterInfo info = new ParameterInfo(type, false, -1, codegen.getFrameMap().enterTemp(type));
|
||||
recordParamInfo(info, false);
|
||||
}
|
||||
|
||||
for (ListIterator<ParameterInfo> iterator = tempTypes.listIterator(tempTypes.size()); iterator.hasPrevious(); ) {
|
||||
ParameterInfo param = iterator.previous();
|
||||
putParameterOnStack(param);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveTemps() {
|
||||
FrameMap frameMap = codegen.getFrameMap();
|
||||
for (ListIterator<ParameterInfo> iterator = tempTypes.listIterator(tempTypes.size()); iterator.hasPrevious(); ) {
|
||||
ParameterInfo param = iterator.previous();
|
||||
if (!param.isSkippedOrRemapped()) {
|
||||
frameMap.leaveTemp(param.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
private static void putStackValuesIntoLocals(List<Type> directOrder, int shift, InstructionAdapter mv, String descriptor) {
|
||||
Type [] actualParams = Type.getArgumentTypes(descriptor); //last param is closure itself
|
||||
assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!";
|
||||
|
||||
int size = 0;
|
||||
for (Type next : directOrder) {
|
||||
size += next.getSize();
|
||||
}
|
||||
|
||||
shift += size;
|
||||
int index = directOrder.size();
|
||||
|
||||
for (Type next : Lists.reverse(directOrder)) {
|
||||
shift -= next.getSize();
|
||||
Type typeOnStack = actualParams[--index];
|
||||
if (!typeOnStack.equals(next)) {
|
||||
StackValue.onStack(typeOnStack).put(next, mv);
|
||||
}
|
||||
mv.visitVarInsn(next.getOpcode(Opcodes.ISTORE), shift);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInliningClosure(JetExpression expression) {
|
||||
return !disabled && expression instanceof JetFunctionLiteralExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rememberClosure(JetFunctionLiteralExpression expression, Type type) {
|
||||
ParameterInfo closureInfo = new ParameterInfo(type, true, -1, -1);
|
||||
int index = recordParamInfo(closureInfo, true);
|
||||
|
||||
ClosureInfo info = new ClosureInfo(expression, typeMapper);
|
||||
expressionMap.put(index, info);
|
||||
}
|
||||
|
||||
private void putClosureParametersOnStack() {
|
||||
//TODO: SORT
|
||||
for (ClosureInfo next : expressionMap.values()) {
|
||||
if (next.closure != null) {
|
||||
int size = tempTypes.size();
|
||||
next.setParamOffset(size);
|
||||
codegen.pushClosureOnStack(next.closure, false, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MemberCodegen getParentCodegen() {
|
||||
return codegen.getParentCodegen();
|
||||
}
|
||||
|
||||
public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) {
|
||||
if (descriptor instanceof NamespaceDescriptor) {
|
||||
return new NamespaceContext((NamespaceDescriptor) descriptor, null);
|
||||
}
|
||||
|
||||
CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state);
|
||||
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return parent.intoClass((ClassDescriptor) descriptor, OwnerKind.IMPLEMENTATION, state);
|
||||
}
|
||||
else if (descriptor instanceof FunctionDescriptor) {
|
||||
return parent.intoFunction((FunctionDescriptor) descriptor);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Coudn't build context for " + descriptorName(descriptor));
|
||||
}
|
||||
|
||||
private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) {
|
||||
return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getNodeText(@Nullable MethodNode node) {
|
||||
if (node == null) {
|
||||
return "Not generated";
|
||||
}
|
||||
Textifier p = new Textifier();
|
||||
node.accept(new TraceMethodVisitor(p));
|
||||
StringWriter sw = new StringWriter();
|
||||
p.print(new PrintWriter(sw));
|
||||
sw.flush();
|
||||
return node.name + ": \n " + sw.getBuffer().toString();
|
||||
}
|
||||
|
||||
private static String descriptorName(DeclarationDescriptor descriptor) {
|
||||
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.asm;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.asm4.ClassReader;
|
||||
import org.jetbrains.asm4.ClassVisitor;
|
||||
import org.jetbrains.asm4.MethodVisitor;
|
||||
import org.jetbrains.asm4.Opcodes;
|
||||
import org.jetbrains.asm4.tree.MethodNode;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf;
|
||||
import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedSimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFQName;
|
||||
|
||||
public class InlineCodegenUtil {
|
||||
|
||||
private final static int API = Opcodes.ASM4;
|
||||
|
||||
@Nullable
|
||||
public static MethodNode getMethodNode(
|
||||
InputStream classData,
|
||||
final String methodName,
|
||||
final String methodDescriptor
|
||||
) throws ClassNotFoundException, IOException {
|
||||
ClassReader cr = new ClassReader(classData);
|
||||
final MethodNode[] methodNode = new MethodNode[1];
|
||||
cr.accept(new ClassVisitor(API) {
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
if (methodName.equals(name) && methodDescriptor.equals(desc)) {
|
||||
return methodNode[0] = new MethodNode(access, name, desc, signature, exceptions);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
|
||||
return methodNode[0];
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static VirtualFile getVirtualFileForCallable(DeserializedSimpleFunctionDescriptor deserializedDescriptor, GenerationState state) {
|
||||
VirtualFile file = null;
|
||||
DeclarationDescriptor parentDeclatation = deserializedDescriptor.getContainingDeclaration();
|
||||
if (parentDeclatation instanceof NamespaceDescriptor) {
|
||||
ProtoBuf.Callable proto = deserializedDescriptor.getFunctionProto();
|
||||
if (proto.hasExtension(JavaProtoBuf.implClassName)) {
|
||||
Name name = deserializedDescriptor.getNameResolver().getName(proto.getExtension(JavaProtoBuf.implClassName));
|
||||
FqName namespaceFqName =
|
||||
PackageClassUtils.getPackageClassFqName(((NamespaceDescriptor) parentDeclatation).getFqName()).parent().child(
|
||||
name);
|
||||
file = findVirtualFile(state.getProject(), namespaceFqName);
|
||||
} else {
|
||||
assert false : "Function in namespace should have implClassName property in proto: " + deserializedDescriptor;
|
||||
}
|
||||
} else {
|
||||
file = findVirtualFileContainingDescriptor(state.getProject(), deserializedDescriptor);
|
||||
}
|
||||
|
||||
if (file == null) {
|
||||
throw new RuntimeException("Couldn't find declaration file for " + deserializedDescriptor.getName());
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile findVirtualFile(@NotNull Project project, @NotNull FqName containerFqName) {
|
||||
VirtualFileFinder fileFinder = ServiceManager.getService(project, VirtualFileFinder.class);
|
||||
VirtualFile virtualFile = fileFinder.find(containerFqName);
|
||||
if (virtualFile == null) {
|
||||
return null;
|
||||
}
|
||||
return virtualFile;
|
||||
}
|
||||
|
||||
//TODO: navigate to inner classes
|
||||
@Nullable
|
||||
private static FqName getContainerFqName(@NotNull DeclarationDescriptor referencedDescriptor) {
|
||||
ClassOrNamespaceDescriptor
|
||||
containerDescriptor = DescriptorUtils.getParentOfType(referencedDescriptor, ClassOrNamespaceDescriptor.class, false);
|
||||
if (containerDescriptor instanceof NamespaceDescriptor) {
|
||||
return PackageClassUtils.getPackageClassFqName(getFQName(containerDescriptor).toSafe());
|
||||
}
|
||||
if (containerDescriptor instanceof ClassDescriptor) {
|
||||
ClassKind classKind = ((ClassDescriptor) containerDescriptor).getKind();
|
||||
if (classKind == ClassKind.CLASS_OBJECT || classKind == ClassKind.ENUM_ENTRY) {
|
||||
return getContainerFqName(containerDescriptor.getContainingDeclaration());
|
||||
}
|
||||
return getFQName(containerDescriptor).toSafe();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile findVirtualFileContainingDescriptor(
|
||||
@NotNull Project project,
|
||||
@NotNull DeclarationDescriptor referencedDescriptor
|
||||
) {
|
||||
FqName containerFqName = getContainerFqName(referencedDescriptor);
|
||||
if (containerFqName == null) {
|
||||
return null;
|
||||
}
|
||||
return findVirtualFile(project, containerFqName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.asm;
|
||||
|
||||
import org.jetbrains.asm4.ClassVisitor;
|
||||
import org.jetbrains.asm4.Type;
|
||||
import org.jetbrains.jet.codegen.CallableMethod;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.codegen.context.MethodContext;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||
|
||||
public interface Inliner {
|
||||
|
||||
Inliner NOT_INLINE = new Inliner() {
|
||||
@Override
|
||||
public void inlineCall(
|
||||
CallableMethod callableMethod, ClassVisitor visitor
|
||||
) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putInLocal(Type type, StackValue stackValue) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveTemps() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInliningClosure(JetExpression expression) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rememberClosure(JetFunctionLiteralExpression expression, Type type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putHiddenParams() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldPutValue(
|
||||
Type type, StackValue stackValue, MethodContext context
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void inlineCall(CallableMethod callableMethod, ClassVisitor visitor);
|
||||
|
||||
void putInLocal(Type type, StackValue stackValue);
|
||||
|
||||
boolean shouldPutValue(Type type, StackValue stackValue, MethodContext context);
|
||||
|
||||
void putHiddenParams();
|
||||
|
||||
void leaveTemps();
|
||||
|
||||
boolean isInliningClosure(JetExpression expression);
|
||||
|
||||
void rememberClosure(JetFunctionLiteralExpression expression, Type type);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.asm;
|
||||
|
||||
import org.jetbrains.asm4.*;
|
||||
import org.jetbrains.asm4.commons.InstructionAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
//http://asm.ow2.org/current/asm-transformations.pdf
|
||||
public class InliningAdapter extends InstructionAdapter {
|
||||
|
||||
private final Label end;
|
||||
protected final VarRemapper remapper;
|
||||
private int nextLocalIndex = 0;
|
||||
|
||||
public InliningAdapter(MethodVisitor mv, int api, String desc, Label end, int localsStart, VarRemapper remapper) {
|
||||
super(api, mv);
|
||||
this.end = end;
|
||||
this.remapper = remapper;
|
||||
nextLocalIndex = localsStart;
|
||||
}
|
||||
|
||||
public void visitInsn(int opcode) {
|
||||
if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
|
||||
super.visitJumpInsn(Opcodes.GOTO, end);
|
||||
}
|
||||
else {
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(int var, int increment) {
|
||||
super.visitIincInsn(remapper.remap(var), increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
int newVar = remapper.remap(var);
|
||||
super.visitVarInsn(opcode, newVar);
|
||||
int size = newVar + (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE ? 2 : 1);
|
||||
if (size > nextLocalIndex) {
|
||||
nextLocalIndex = size;
|
||||
}
|
||||
}
|
||||
|
||||
public int getNextLocalIndex() {
|
||||
return nextLocalIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(
|
||||
String name, String desc, String signature, Label start, Label end, int index
|
||||
) {
|
||||
//super.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.asm;
|
||||
|
||||
import org.jetbrains.asm4.Type;
|
||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||
|
||||
class ParameterInfo {
|
||||
|
||||
public static final ParameterInfo STUB = new ParameterInfo(AsmTypeConstants.OBJECT_TYPE, true, -1, -1);
|
||||
|
||||
public final int index;
|
||||
|
||||
public final Type type;
|
||||
|
||||
public final boolean isSkipped;
|
||||
|
||||
public final int remapIndex;
|
||||
|
||||
ParameterInfo(Type type, boolean skipped, int remapIndex, int index) {
|
||||
this.type = type;
|
||||
this.isSkipped = skipped;
|
||||
this.remapIndex = remapIndex;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public boolean isSkippedOrRemapped() {
|
||||
return isSkipped || remapIndex != -1;
|
||||
}
|
||||
|
||||
public int getInlinedIndex() {
|
||||
return remapIndex != -1 ? remapIndex : index;
|
||||
}
|
||||
|
||||
public boolean isSkipped() {
|
||||
return isSkipped;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.asm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class VarRemapper {
|
||||
|
||||
public static class ShiftRemapper extends VarRemapper {
|
||||
|
||||
private final int shift;
|
||||
|
||||
public ShiftRemapper(int shift) {
|
||||
this.shift = shift;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doRemap(int index) {
|
||||
return index + shift;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClosureRemapper extends ShiftRemapper {
|
||||
|
||||
private final ClosureInfo info;
|
||||
private final List<ParameterInfo> originalParams;
|
||||
private final int capturedSize;
|
||||
|
||||
public ClosureRemapper(ClosureInfo info, int valueParametersShift, List<ParameterInfo> originalParams) {
|
||||
super(valueParametersShift);
|
||||
this.info = info;
|
||||
this.originalParams = originalParams;
|
||||
capturedSize = info.getCapturedVarsSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doRemap(int index) {
|
||||
if (index < capturedSize) {
|
||||
return originalParams.get(info.getParamOffset() + index).getInlinedIndex();
|
||||
}
|
||||
return super.doRemap(index - capturedSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParamRemapper extends VarRemapper {
|
||||
|
||||
private final int paramShift;
|
||||
private final int paramSize;
|
||||
private final int additionalParamsSize;
|
||||
private final List<ParameterInfo> params;
|
||||
private final int actualParams;
|
||||
|
||||
public ParamRemapper(int paramShift, int paramSize, int additionalParamsSize, List<ParameterInfo> params) {
|
||||
this.paramShift = paramShift;
|
||||
this.paramSize = paramSize;
|
||||
this.additionalParamsSize = additionalParamsSize;
|
||||
this.params = params;
|
||||
|
||||
int paramCount = 0;
|
||||
for (int i = 0; i < params.size(); i++) {
|
||||
ParameterInfo info = params.get(i);
|
||||
if (!info.isSkippedOrRemapped()) {
|
||||
paramCount += info.getType().getSize();
|
||||
}
|
||||
}
|
||||
actualParams = paramCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doRemap(int index) {
|
||||
if (index < paramSize) {
|
||||
ParameterInfo info = params.get(index);
|
||||
if (info.isSkipped) {
|
||||
throw new RuntimeException("Trying to access skipped parameter: " + info.type + " at " +index);
|
||||
}
|
||||
return info.getInlinedIndex();
|
||||
} else {
|
||||
return paramShift + actualParams + index; //captured params not used directly in this inlined method, they used in closure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected boolean nestedRemmapper;
|
||||
|
||||
public int remap(int index) {
|
||||
if (nestedRemmapper) {
|
||||
return index;
|
||||
}
|
||||
return doRemap(index);
|
||||
}
|
||||
|
||||
abstract public int doRemap(int index);
|
||||
|
||||
public void setNestedRemap(boolean nestedRemap) {
|
||||
nestedRemmapper = nestedRemap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,11 +23,13 @@ import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
|
||||
public final class EnclosedValueDescriptor {
|
||||
private final String fieldName;
|
||||
private final DeclarationDescriptor descriptor;
|
||||
private final StackValue innerValue;
|
||||
private final Type type;
|
||||
|
||||
public EnclosedValueDescriptor(DeclarationDescriptor descriptor, StackValue innerValue, Type type) {
|
||||
public EnclosedValueDescriptor(String fieldName, DeclarationDescriptor descriptor, StackValue innerValue, Type type) {
|
||||
this.fieldName = fieldName;
|
||||
this.descriptor = descriptor;
|
||||
this.innerValue = innerValue;
|
||||
this.type = type;
|
||||
@@ -55,4 +57,8 @@ public final class EnclosedValueDescriptor {
|
||||
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public interface LocalLookup {
|
||||
: StackValue.field(type, classType, fieldName, false);
|
||||
|
||||
closure.recordField(fieldName, type);
|
||||
closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, type));
|
||||
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, type));
|
||||
|
||||
return innerValue;
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public interface LocalLookup {
|
||||
StackValue innerValue = StackValue.field(localType, classType, fieldName, false);
|
||||
|
||||
closure.recordField(fieldName, localType);
|
||||
closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, localType));
|
||||
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
|
||||
|
||||
return innerValue;
|
||||
}
|
||||
|
||||
@@ -23,10 +23,7 @@ import org.jetbrains.jet.codegen.OwnerKind;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.codegen.binding.MutableClosure;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||
|
||||
public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
|
||||
@@ -81,4 +78,11 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
|
||||
return "Method: " + getContextDescriptor();
|
||||
}
|
||||
|
||||
public boolean isInlineFunction() {
|
||||
DeclarationDescriptor descriptor = getContextDescriptor();
|
||||
if (descriptor instanceof SimpleFunctionDescriptor) {
|
||||
return ((SimpleFunctionDescriptor) descriptor).isInline();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user