big codegen rewrite

This commit is contained in:
Alex Tkachman
2012-08-27 17:43:03 +03:00
parent 52386e5294
commit 10a47ea86f
35 changed files with 1736 additions and 1549 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -125,7 +125,7 @@ public class ClassBuilderFactories {
return super.getCommonSuperClass(type1, type2); return super.getCommonSuperClass(type1, type2);
} }
catch (Throwable t) { catch (Throwable t) {
// @todo we might need at some point do more sofisticated handling // @todo we might need at some point do more sophisticated handling
return "java/lang/Object"; return "java/lang/Object";
} }
} }
@@ -16,6 +16,7 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -30,14 +31,14 @@ import java.util.Map;
*/ */
public class ClassCodegen { public class ClassCodegen {
private GenerationState state; private GenerationState state;
private JetTypeMapper jetTypeMapper; @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private JetTypeMapper jetTypeMapper;
@Inject @Inject
public void setState(GenerationState state) { public void setState(GenerationState state) {
this.state = state; this.state = state;
} }
@SuppressWarnings("UnusedParameters")
@Inject @Inject
public void setJetTypeMapper(JetTypeMapper jetTypeMapper) { public void setJetTypeMapper(JetTypeMapper jetTypeMapper) {
this.jetTypeMapper = jetTypeMapper; this.jetTypeMapper = jetTypeMapper;
@@ -48,13 +49,13 @@ public class ClassCodegen {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
ClassBuilder classBuilder = state.forClassImplementation(descriptor); ClassBuilder classBuilder = state.forClassImplementation(descriptor);
final CodegenContext contextForInners = context.intoClass(descriptor, OwnerKind.IMPLEMENTATION, jetTypeMapper); final CodegenContext contextForInners = context.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state);
if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) { if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) {
// Outer class implementation must happen prior inner classes so we get proper scoping tree in JetLightClass's delegate // Outer class implementation must happen prior inner classes so we get proper scoping tree in JetLightClass's delegate
// The same code is present below for the case when we generate real bytecode. This is because the order should be // The same code is present below for the case when we generate real bytecode. This is because the order should be
// different for the case when we compute closures // different for the case when we compute closures
generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.accessors, classBuilder); generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder);
} }
for (JetDeclaration declaration : aClass.getDeclarations()) { for (JetDeclaration declaration : aClass.getDeclarations()) {
@@ -72,7 +73,7 @@ public class ClassCodegen {
} }
if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES) { if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES) {
generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.accessors, classBuilder); generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder);
} }
classBuilder.done(); classBuilder.done();
@@ -86,13 +87,14 @@ public class ClassCodegen {
ClassBuilder classBuilder ClassBuilder classBuilder
) { ) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
CodegenContext classContext = context.intoClass(descriptor, kind, jetTypeMapper); CodegenContext classContext = context.intoClass(descriptor, kind, state);
classContext.copyAccessors(accessors); classContext.copyAccessors(accessors);
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate(); new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate();
if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) { if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
ClassBuilder traitBuilder = state.forTraitImplementation(descriptor); ClassBuilder traitBuilder = state.forTraitImplementation(descriptor);
new TraitImplBodyCodegen(aClass, context.intoClass(descriptor, OwnerKind.TRAIT_IMPL, jetTypeMapper), traitBuilder, state) new TraitImplBodyCodegen(aClass, context.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state)
.generate(); .generate();
traitBuilder.done(); traitBuilder.done();
} }
@@ -22,15 +22,16 @@ package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Label; import org.jetbrains.asm4.Label;
import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method; import org.jetbrains.asm4.commons.Method;
import org.jetbrains.asm4.signature.SignatureWriter; import org.jetbrains.asm4.signature.SignatureWriter;
import org.jetbrains.jet.codegen.signature.BothSignatureWriter; import org.jetbrains.jet.codegen.context.CalculatedClosure;
import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; import org.jetbrains.jet.codegen.context.ClosureAnnotator;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.MutableClosure;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
@@ -39,7 +40,6 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
@@ -48,81 +48,42 @@ import java.util.List;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
public class ClosureCodegen extends ObjectOrClosureCodegen { public class ClosureCodegen {
private final BindingContext bindingContext; private final BindingContext bindingContext;
private final ClosureAnnotator closureAnnotator; private final ClosureAnnotator closureAnnotator;
private final JetTypeMapper typeMapper; private final JetTypeMapper typeMapper;
public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, CodegenContext context) { Method constructor;
super(exprContext, context, state); private final GenerationState state;
private final MutableClosure closure;
JvmClassName name;
public ClosureCodegen(GenerationState state, MutableClosure closure) {
this.state = state;
this.closure = closure;
bindingContext = state.getBindingContext(); bindingContext = state.getBindingContext();
typeMapper = this.state.getInjector().getJetTypeMapper(); typeMapper = state.getInjector().getJetTypeMapper();
closureAnnotator = typeMapper.getClosureAnnotator(); closureAnnotator = typeMapper.getClosureAnnotator();
} }
private static JvmMethodSignature erasedInvokeSignature(FunctionDescriptor fd) { public ClosureCodegen gen(JetExpression fun, CodegenContext context, ExpressionCodegen expressionCodegen) {
final SimpleFunctionDescriptor descriptor = bindingContext.get(BindingContext.FUNCTION, fun);
assert descriptor != null;
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false);
signatureWriter.writeFormalTypeParametersStart();
signatureWriter.writeFormalTypeParametersEnd();
boolean isExtensionFunction = fd.getReceiverParameter().exists();
int paramCount = fd.getValueParameters().size();
if (isExtensionFunction) {
paramCount++;
}
signatureWriter.writeParametersStart();
for (int i = 0; i < paramCount; ++i) {
signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
signatureWriter.writeAsmType(JetTypeMapper.OBJECT_TYPE, true);
signatureWriter.writeParameterTypeEnd();
}
signatureWriter.writeParametersEnd();
signatureWriter.writeReturnType();
signatureWriter.writeAsmType(JetTypeMapper.OBJECT_TYPE, true);
signatureWriter.writeReturnTypeEnd();
return signatureWriter.makeJvmMethodSignature("invoke");
}
public static CallableMethod asCallableMethod(FunctionDescriptor fd, @NotNull JetTypeMapper typeMapper) {
JvmMethodSignature descriptor = erasedInvokeSignature(fd);
JvmClassName owner = getInternalClassName(fd);
Type receiverParameterType;
if (fd.getReceiverParameter().exists()) {
receiverParameterType = typeMapper.mapType(fd.getOriginal().getReceiverParameter().getType(), MapTypeMode.VALUE);
}
else {
receiverParameterType = null;
}
return new CallableMethod(
owner, null, null, descriptor, INVOKEVIRTUAL,
getInternalClassName(fd), receiverParameterType, getInternalClassName(fd).getAsmType());
}
protected JvmMethodSignature invokeSignature(FunctionDescriptor fd) {
return typeMapper.mapSignature(Name.identifier("invoke"), fd);
}
public GeneratedAnonymousClassDescriptor gen(JetExpression fun) {
final Pair<JvmClassName, ClassBuilder> nameAndVisitor = state.forAnonymousSubclass(fun); final Pair<JvmClassName, ClassBuilder> nameAndVisitor = state.forAnonymousSubclass(fun);
final FunctionDescriptor funDescriptor = bindingContext.get(BindingContext.FUNCTION, fun); final FunctionDescriptor funDescriptor = bindingContext.get(BindingContext.FUNCTION, fun);
cv = nameAndVisitor.getSecond(); ClassBuilder cv = nameAndVisitor.getSecond();
name = nameAndVisitor.getFirst(); name = nameAndVisitor.getFirst();
SignatureWriter signatureWriter = new SignatureWriter(); SignatureWriter signatureWriter = new SignatureWriter();
assert funDescriptor != null; assert funDescriptor != null;
final List<ValueParameterDescriptor> parameters = funDescriptor.getValueParameters(); final List<ValueParameterDescriptor> parameters = funDescriptor.getValueParameters();
final JvmClassName funClass = getInternalClassName(funDescriptor); final JvmClassName funClass = CodegenUtil.getInternalClassName(funDescriptor);
signatureWriter.visitClassType(funClass.getInternalName()); signatureWriter.visitClassType(funClass.getInternalName());
for (ValueParameterDescriptor parameter : parameters) { for (ValueParameterDescriptor parameter : parameters) {
appendType(signatureWriter, parameter.getType(), '='); appendType(signatureWriter, parameter.getType(), '=');
@@ -143,46 +104,27 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
generateBridge(name.getInternalName(), funDescriptor, fun, cv); generateBridge(name.getInternalName(), funDescriptor, fun, cv);
captureThis = generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun); generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun, context, expressionCodegen);
final ClassDescriptor enclosingClass = context.getEnclosingClass(); constructor = generateConstructor(funClass, fun, cv, closure);
if (enclosingClass == null) {
captureThis = null; if (CodegenUtil.isConst(closure)) {
generateConstInstance(fun, cv);
} }
final Method constructor = generateConstructor(funClass, fun, funDescriptor); CodegenUtil.generateClosureFields(closure, cv, state.getInjector().getJetTypeMapper());
if (captureThis != null) {
cv.newField(fun, ACC_FINAL, "this$0", typeMapper.mapType(enclosingClass.getDefaultType(), MapTypeMode.IMPL).getDescriptor(),
null, null);
}
if (isConst()) {
generateConstInstance(fun);
}
cv.done(); cv.done();
final GeneratedAnonymousClassDescriptor answer = return this;
new GeneratedAnonymousClassDescriptor(name, constructor, captureThis, captureReceiver);
for (DeclarationDescriptor descriptor : closure.keySet()) {
if (descriptor == funDescriptor) {
continue;
}
if (descriptor instanceof VariableDescriptor || CodegenUtil.isNamedFun(descriptor, state.getBindingContext()) &&
descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor);
answer.addArg(valueDescriptor.getOuterValue());
}
}
return answer;
} }
private void generateConstInstance(PsiElement fun) { private void generateConstInstance(PsiElement fun, ClassBuilder cv) {
String classDescr = name.getDescriptor(); String classDescr = name.getDescriptor();
cv.newField(fun, ACC_PRIVATE | ACC_STATIC | ACC_FINAL, "$instance", classDescr, null, null); cv.newField(fun, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, "$instance", classDescr, null, null);
MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC, "$getInstance", "()" + classDescr, null, new String[0]); MethodVisitor mv =
cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, "$getInstance", "()" + classDescr, null, new String[0]);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); StubCodegen.generateStubCode(mv);
} }
@@ -206,21 +148,29 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
} }
} }
private ClassDescriptor generateBody(FunctionDescriptor funDescriptor, ClassBuilder cv, JetDeclarationWithBody body) { private ClassDescriptor generateBody(
ClassDescriptor function = FunctionDescriptor funDescriptor,
closureAnnotator.classDescriptorForFunctionDescriptor(funDescriptor); ClassBuilder cv,
JetDeclarationWithBody body,
CodegenContext context,
ExpressionCodegen expressionCodegen
) {
final CodegenContexts.ClosureContext closureContext = context.intoClosure( final CodegenContext closureContext = context.intoClosure(funDescriptor, expressionCodegen);
funDescriptor, function, this, typeMapper);
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
JvmMethodSignature jvmMethodSignature = invokeSignature(funDescriptor); JvmMethodSignature jvmMethodSignature = typeMapper.invokeSignature(funDescriptor);
fc.generateMethod(body, jvmMethodSignature, false, null, funDescriptor); fc.generateMethod(body, jvmMethodSignature, false, null, funDescriptor);
return closureContext.outerWasUsed; return closureContext.closure.getCaptureThis();
} }
private void generateBridge(String className, FunctionDescriptor funDescriptor, JetExpression fun, ClassBuilder cv) { private void generateBridge(
final JvmMethodSignature bridge = erasedInvokeSignature(funDescriptor); String className,
final Method delegate = invokeSignature(funDescriptor).getAsmMethod(); FunctionDescriptor funDescriptor,
JetExpression fun,
ClassBuilder cv
) {
final JvmMethodSignature bridge = CodegenUtil.erasedInvokeSignature(funDescriptor);
final Method delegate = typeMapper.invokeSignature(funDescriptor).getAsmMethod();
if (bridge.getAsmMethod().getDescriptor().equals(delegate.getDescriptor())) { if (bridge.getAsmMethod().getDescriptor().equals(delegate.getDescriptor())) {
return; return;
@@ -265,9 +215,14 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
} }
} }
private Method generateConstructor(JvmClassName funClass, JetExpression fun, FunctionDescriptor funDescriptor) { private Method generateConstructor(
JvmClassName funClass,
JetExpression fun,
ClassBuilder cv,
CalculatedClosure closure
) {
final ArrayList<Pair<String, Type>> args = new ArrayList<Pair<String, Type>>(); final ArrayList<Pair<String, Type>> args = new ArrayList<Pair<String, Type>>();
boolean putFieldForMyself = calculateConstructorParameters(funDescriptor, args); calculateConstructorParameters(args, state, closure);
final Type[] argTypes = nameAnTypeListToTypeArray(args); final Type[] argTypes = nameAnTypeListToTypeArray(args);
@@ -293,14 +248,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
StackValue.field(type, name, nameAndType.first, false).store(type, iv); StackValue.field(type, name, nameAndType.first, false).store(type, iv);
} }
if (putFieldForMyself) {
Type type = name.getAsmType();
String fieldName = "$" + funDescriptor.getName();
iv.load(0, type);
iv.dup();
StackValue.field(type, name, fieldName, false).store(type, iv);
}
iv.visitInsn(RETURN); iv.visitInsn(RETURN);
FunctionCodegen.endVisit(iv, "constructor", fun); FunctionCodegen.endVisit(iv, "constructor", fun);
@@ -308,22 +255,24 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
return constructor; return constructor;
} }
private boolean calculateConstructorParameters(FunctionDescriptor funDescriptor, List<Pair<String, Type>> args) { private void calculateConstructorParameters(
List<Pair<String, Type>> args,
GenerationState state,
CalculatedClosure closure
) {
final ClassDescriptor captureThis = closure.getCaptureThis();
if (captureThis != null) { if (captureThis != null) {
final Type type = typeMapper.mapType(context.getThisDescriptor().getDefaultType(), MapTypeMode.VALUE); final Type type = typeMapper.mapType(captureThis.getDefaultType(), MapTypeMode.VALUE);
args.add(new Pair<String, Type>("this$0", type)); args.add(new Pair<String, Type>(CodegenUtil.THIS$0, type));
} }
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) { if (captureReceiver != null) {
args.add(new Pair<String, Type>("receiver$0", typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.VALUE))); args.add(new Pair<String, Type>(CodegenUtil.RECEIVER$0,
typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.VALUE)));
} }
boolean putFieldForMyself = false; for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
for (DeclarationDescriptor descriptor : closure.keySet()) {
if (descriptor == funDescriptor) {
putFieldForMyself = true;
}
else if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
final Type sharedVarType = typeMapper.getSharedVarType(descriptor); final Type sharedVarType = typeMapper.getSharedVarType(descriptor);
final Type type = sharedVarType != null final Type type = sharedVarType != null
@@ -343,7 +292,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
assert captureReceiver != null; assert captureReceiver != null;
} }
} }
return putFieldForMyself;
} }
private static Type[] nameAnTypeListToTypeArray(List<Pair<String, Type>> args) { private static Type[] nameAnTypeListToTypeArray(List<Pair<String, Type>> args) {
@@ -354,17 +302,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
return argTypes; return argTypes;
} }
@NotNull
public static JvmClassName getInternalClassName(FunctionDescriptor descriptor) {
final int paramCount = descriptor.getValueParameters().size();
if (descriptor.getReceiverParameter().exists()) {
return JvmClassName.byInternalName("jet/ExtensionFunction" + paramCount);
}
else {
return JvmClassName.byInternalName("jet/Function" + paramCount);
}
}
private void appendType(SignatureWriter signatureWriter, JetType type, char variance) { private void appendType(SignatureWriter signatureWriter, JetType type, char variance) {
signatureWriter.visitTypeArgument(variance); signatureWriter.visitTypeArgument(variance);
@@ -1,262 +0,0 @@
/*
* Copyright 2010-2012 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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.jetbrains.jet.codegen.JetTypeMapper.OBJECT_TYPE;
/*
* @author max
* @author alex.tkachman
*/
public abstract class CodegenContext {
@NotNull
private final DeclarationDescriptor contextDescriptor;
private final OwnerKind contextKind;
@Nullable
private final CodegenContext parentContext;
public final ObjectOrClosureCodegen closure;
private final ClassDescriptor thisDescriptor;
HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors;
protected StackValue outerExpression;
protected ClassDescriptor outerWasUsed;
public CodegenContext(
JetTypeMapper typeMapper,
@NotNull DeclarationDescriptor contextDescriptor,
OwnerKind contextKind,
@Nullable CodegenContext parentContext,
@Nullable ObjectOrClosureCodegen closureCodegen,
ClassDescriptor thisDescriptor
) {
this.contextDescriptor = contextDescriptor;
this.contextKind = contextKind;
this.parentContext = parentContext;
closure = closureCodegen;
this.thisDescriptor = thisDescriptor;
final ClassDescriptor enclosingClass = getEnclosingClass();
//outerExpression = enclosingClass != null && hasThisDescriptor() && typeMapper != null
// ? StackValue.field(typeMapper.mapType(enclosingClass.getDefaultType(),MapTypeMode.VALUE), typeMapper.getJvmClassName(thisDescriptor), "this$0", false)
// : null;
}
@NotNull
protected final ClassDescriptor getThisDescriptor() {
if (thisDescriptor == null) {
throw new UnsupportedOperationException();
}
return thisDescriptor;
}
protected final boolean hasThisDescriptor() {
return thisDescriptor != null;
}
public DeclarationDescriptor getClassOrNamespaceDescriptor() {
CodegenContext c = this;
while (true) {
assert c != null;
DeclarationDescriptor contextDescriptor = c.getContextDescriptor();
if (!(contextDescriptor instanceof ClassDescriptor) && !(contextDescriptor instanceof NamespaceDescriptor)) {
c = c.getParentContext();
}
else {
return contextDescriptor;
}
}
}
protected CallableDescriptor getReceiverDescriptor() {
return null;
}
protected StackValue getOuterExpression(@Nullable StackValue prefix) {
if (outerExpression == null) {
throw new UnsupportedOperationException();
}
outerWasUsed = getEnclosingClass();
return prefix != null ? StackValue.composed(prefix, outerExpression) : outerExpression;
}
@NotNull
public DeclarationDescriptor getContextDescriptor() {
return contextDescriptor;
}
public OwnerKind getContextKind() {
return contextKind;
}
public CodegenContext intoNamespace(NamespaceDescriptor descriptor, JetTypeMapper typeMapper) {
return new CodegenContexts.NamespaceContext(typeMapper, descriptor, this, null);
}
public CodegenContext intoNamespacePart(String delegateTo, NamespaceDescriptor descriptor, JetTypeMapper typeMapper) {
return new CodegenContexts.NamespaceContext(typeMapper, descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo));
}
public CodegenContext intoClass(ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) {
return new CodegenContexts.ClassContext(typeMapper, descriptor, kind, this);
}
public CodegenContext intoAnonymousClass(
@NotNull ObjectOrClosureCodegen closure,
ClassDescriptor descriptor,
OwnerKind kind,
JetTypeMapper typeMapper
) {
return new CodegenContexts.AnonymousClassContext(typeMapper, descriptor, kind, this, closure);
}
public CodegenContexts.MethodContext intoFunction(FunctionDescriptor descriptor, JetTypeMapper typeMapper) {
return new CodegenContexts.MethodContext(typeMapper, descriptor, getContextKind(), this);
}
public CodegenContexts.ConstructorContext intoConstructor(ConstructorDescriptor descriptor, JetTypeMapper typeMapper) {
if (descriptor == null) {
descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.<AnnotationDescriptor>emptyList(), true)
.initialize(Collections.<TypeParameterDescriptor>emptyList(), Collections.<ValueParameterDescriptor>emptyList(),
Visibilities.PUBLIC);
}
return new CodegenContexts.ConstructorContext(typeMapper, descriptor, getContextKind(), this);
}
public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
return new CodegenContexts.ScriptContext(typeMapper, script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
}
public CodegenContexts.ClosureContext intoClosure(
FunctionDescriptor funDescriptor,
ClassDescriptor classDescriptor,
ClosureCodegen closureCodegen,
JetTypeMapper typeMapper
) {
return new CodegenContexts.ClosureContext(typeMapper, funDescriptor, classDescriptor, this, closureCodegen);
}
public FrameMap prepareFrame(JetTypeMapper mapper) {
FrameMap frameMap = new FrameMap();
if (getContextKind() != OwnerKind.NAMESPACE) {
frameMap.enterTemp(OBJECT_TYPE); // 0 slot for this
}
CallableDescriptor receiverDescriptor = getReceiverDescriptor();
if (receiverDescriptor != null) {
Type type = mapper.mapType(receiverDescriptor.getReceiverParameter().getType(), MapTypeMode.VALUE);
frameMap.enterTemp(type); // Next slot for fake this
}
return frameMap;
}
@Nullable
public CodegenContext getParentContext() {
return parentContext;
}
public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v, StackValue result) {
final ObjectOrClosureCodegen top = closure;
if (top != null) {
final StackValue answer = top.lookupInContext(d, result);
if (answer != null) {
return result == null ? answer : StackValue.composed(result, answer);
}
StackValue outer = getOuterExpression(null);
result = result == null ? outer : StackValue.composed(result, outer);
}
return parentContext != null ? parentContext.lookupInContext(d, v, result) : null;
}
public ClassDescriptor getEnclosingClass() {
CodegenContext cur = getParentContext();
while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) {
cur = cur.getParentContext();
}
return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor();
}
DeclarationDescriptor getAccessor(DeclarationDescriptor descriptor) {
if (accessors == null) {
accessors = new HashMap<DeclarationDescriptor, DeclarationDescriptor>();
}
descriptor = descriptor.getOriginal();
DeclarationDescriptor accessor = accessors.get(descriptor);
if (accessor != null) {
return accessor;
}
if (descriptor instanceof SimpleFunctionDescriptor) {
accessor = new AccessorForFunctionDescriptor(descriptor, contextDescriptor, accessors.size());
}
else if (descriptor instanceof PropertyDescriptor) {
accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessors.size());
}
else {
throw new UnsupportedOperationException();
}
accessors.put(descriptor, accessor);
return accessor;
}
public StackValue getReceiverExpression(JetTypeMapper typeMapper) {
assert getReceiverDescriptor() != null;
Type asmType = typeMapper.mapType(getReceiverDescriptor().getReceiverParameter().getType(), MapTypeMode.VALUE);
return hasThisDescriptor() ? StackValue.local(1, asmType) : StackValue.local(0, asmType);
}
public abstract boolean isStatic();
public void copyAccessors(Map<DeclarationDescriptor, DeclarationDescriptor> accessors) {
if (accessors != null) {
if (this.accessors == null) {
this.accessors = new HashMap<DeclarationDescriptor, DeclarationDescriptor>();
}
this.accessors.putAll(accessors);
}
}
protected void initOuterExpression(JetTypeMapper typeMapper, ClassDescriptor classDescriptor) {
final ClassDescriptor enclosingClass = getEnclosingClass();
outerExpression = enclosingClass != null
? StackValue
.field(typeMapper.mapType(enclosingClass.getDefaultType(), MapTypeMode.VALUE), typeMapper.getJvmClassName(
classDescriptor), "this$0",
false)
: null;
}
}
@@ -1,290 +0,0 @@
/*
* Copyright 2010-2012 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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.List;
/**
* @author alex.tkachman
* @author Stepan Koltsov
*/
public class CodegenContexts {
private CodegenContexts() {
}
private static class FakeDescriptorForStaticContext implements DeclarationDescriptor {
@NotNull
@Override
public DeclarationDescriptor getOriginal() {
throw new IllegalStateException();
}
@Override
public DeclarationDescriptor getContainingDeclaration() {
throw new IllegalStateException();
}
@Override
public DeclarationDescriptor substitute(TypeSubstitutor substitutor) {
throw new IllegalStateException();
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
throw new IllegalStateException();
}
@Override
public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
throw new IllegalStateException();
}
@Override
public List<AnnotationDescriptor> getAnnotations() {
throw new IllegalStateException();
}
@NotNull
@Override
public Name getName() {
throw new IllegalStateException();
}
}
public static final CodegenContext STATIC =
new CodegenContext(null, new FakeDescriptorForStaticContext(), OwnerKind.NAMESPACE, null, null, null) {
@Override
public boolean isStatic() {
return true;
}
@Override
public String toString() {
return "ROOT";
}
};
private static final StackValue local1 = StackValue.local(1, JetTypeMapper.OBJECT_TYPE);
public abstract static class ReceiverContext extends CodegenContext {
final CallableDescriptor receiverDescriptor;
public ReceiverContext(
JetTypeMapper typeMapper,
CallableDescriptor contextDescriptor,
OwnerKind contextKind,
CodegenContext parentContext,
@Nullable ObjectOrClosureCodegen closureCodegen,
ClassDescriptor thisDescriptor
) {
super(typeMapper, contextDescriptor, contextKind, parentContext, closureCodegen, thisDescriptor);
receiverDescriptor = contextDescriptor.getReceiverParameter().exists() ? contextDescriptor : null;
}
@Override
protected CallableDescriptor getReceiverDescriptor() {
return receiverDescriptor;
}
}
public static class MethodContext extends ReceiverContext {
public MethodContext(
JetTypeMapper typeMapper,
@NotNull FunctionDescriptor contextType,
OwnerKind contextKind,
CodegenContext parentContext
) {
super(typeMapper, contextType instanceof PropertyAccessorDescriptor
? ((PropertyAccessorDescriptor) contextType).getCorrespondingProperty()
: contextType, contextKind, parentContext, null,
parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null);
}
@Override
public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v, StackValue result) {
//noinspection ConstantConditions
return getParentContext().lookupInContext(d, v, result);
}
@Override
public boolean isStatic() {
//noinspection ConstantConditions
return getParentContext().isStatic();
}
@Override
protected StackValue getOuterExpression(StackValue prefix) {
//noinspection ConstantConditions
return getParentContext().getOuterExpression(prefix);
}
@Override
public String toString() {
return "Method: " + getContextDescriptor();
}
}
public static class ConstructorContext extends MethodContext {
public ConstructorContext(
JetTypeMapper typeMapper,
ConstructorDescriptor contextDescriptor,
OwnerKind kind,
CodegenContext parent
) {
super(typeMapper, contextDescriptor, kind, parent);
final ClassDescriptor type = getEnclosingClass();
outerExpression = type != null ? local1 : null;
}
@Override
protected StackValue getOuterExpression(StackValue prefix) {
return outerExpression;
}
@Override
public String toString() {
return "Constructor: " + getContextDescriptor().getName();
}
}
public static class ScriptContext extends CodegenContext {
@NotNull
private final ScriptDescriptor scriptDescriptor;
public ScriptContext(
JetTypeMapper typeMapper,
@NotNull ScriptDescriptor scriptDescriptor,
@NotNull ClassDescriptor contextDescriptor,
@NotNull OwnerKind contextKind,
@Nullable CodegenContext parentContext,
@Nullable ObjectOrClosureCodegen closureCodegen
) {
super(typeMapper, contextDescriptor, contextKind, parentContext, closureCodegen, contextDescriptor);
this.scriptDescriptor = scriptDescriptor;
}
@NotNull
public ScriptDescriptor getScriptDescriptor() {
return scriptDescriptor;
}
@Override
public boolean isStatic() {
return true;
}
}
public static class ClassContext extends CodegenContext {
public ClassContext(
JetTypeMapper typeMapper,
ClassDescriptor contextDescriptor,
OwnerKind contextKind,
CodegenContext parentContext
) {
super(typeMapper, contextDescriptor, contextKind, parentContext, null, contextDescriptor);
initOuterExpression(typeMapper, contextDescriptor);
}
@Override
public boolean isStatic() {
return false;
}
}
public static class AnonymousClassContext extends CodegenContext {
public AnonymousClassContext(
JetTypeMapper typeMapper,
ClassDescriptor contextDescriptor,
OwnerKind contextKind,
CodegenContext parentContext,
@NotNull ObjectOrClosureCodegen closure
) {
super(typeMapper, contextDescriptor, contextKind, parentContext, closure, contextDescriptor);
initOuterExpression(typeMapper, contextDescriptor);
}
@Override
public boolean isStatic() {
return false;
}
@Override
public String toString() {
return "Anonymous: " + getThisDescriptor();
}
}
public static class ClosureContext extends ReceiverContext {
private final ClassDescriptor classDescriptor;
public ClosureContext(
JetTypeMapper typeMapper,
FunctionDescriptor contextDescriptor,
ClassDescriptor classDescriptor,
CodegenContext parentContext,
@NotNull ObjectOrClosureCodegen closureCodegen
) {
super(typeMapper, contextDescriptor, OwnerKind.IMPLEMENTATION, parentContext, closureCodegen, classDescriptor);
this.classDescriptor = classDescriptor;
initOuterExpression(typeMapper, classDescriptor);
}
@NotNull
@Override
public DeclarationDescriptor getContextDescriptor() {
return classDescriptor;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public String toString() {
return "Closure: " + classDescriptor;
}
}
public static class NamespaceContext extends CodegenContext {
public NamespaceContext(JetTypeMapper typeMapper, NamespaceDescriptor contextDescriptor, CodegenContext parent, OwnerKind kind) {
super(typeMapper, contextDescriptor, kind != null ? kind : OwnerKind.NAMESPACE, parent, null, null);
}
@Override
public boolean isStatic() {
return true;
}
@Override
public String toString() {
return "Namespace: " + getContextDescriptor().getName();
}
}
}
@@ -16,31 +16,39 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.context.CalculatedClosure;
import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import java.util.BitSet; import java.util.*;
import java.util.Collection;
import java.util.Collections; import static org.jetbrains.asm4.Opcodes.*;
import java.util.Random;
/** /**
* @author abreslav * @author abreslav
* @author alex.tkachman * @author alex.tkachman
*/ */
public class CodegenUtil { public class CodegenUtil {
public static final String RECEIVER$0 = "receiver$0";
public static final String THIS$0 = "this$0";
private CodegenUtil() { private CodegenUtil() {
} }
@@ -83,6 +91,14 @@ public class CodegenUtil {
!(myClass.getParent() instanceof JetClassObject); !(myClass.getParent() instanceof JetClassObject);
} }
public static boolean isObjectLiteral(ClassDescriptor declaration, BindingContext bindingContext) {
PsiElement psiElement = BindingContextUtils.descriptorToDeclaration(bindingContext, declaration);
if (psiElement instanceof JetObjectDeclaration && ((JetObjectDeclaration) psiElement).isObjectLiteral()) {
return true;
}
return false;
}
public static boolean isLocalFun(DeclarationDescriptor fd, BindingContext bindingContext) { public static boolean isLocalFun(DeclarationDescriptor fd, BindingContext bindingContext) {
PsiElement psiElement = BindingContextUtils.descriptorToDeclaration(bindingContext, fd); PsiElement psiElement = BindingContextUtils.descriptorToDeclaration(bindingContext, fd);
if (psiElement instanceof JetNamedFunction && psiElement.getParent() instanceof JetBlockExpression) { if (psiElement instanceof JetNamedFunction && psiElement.getParent() instanceof JetBlockExpression) {
@@ -126,12 +142,12 @@ public class CodegenUtil {
} }
public static void generateThrow(MethodVisitor mv, String exception, String message) { public static void generateThrow(MethodVisitor mv, String exception, String message) {
InstructionAdapter instructionAdapter = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
instructionAdapter.anew(Type.getObjectType(exception)); iv.anew(Type.getObjectType(exception));
instructionAdapter.dup(); iv.dup();
instructionAdapter.aconst(message); iv.aconst(message);
instructionAdapter.invokespecial(exception, "<init>", "(Ljava/lang/String;)V"); iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
instructionAdapter.athrow(); iv.athrow();
} }
public static void generateMethodThrow(MethodVisitor mv, String exception, String message) { public static void generateMethodThrow(MethodVisitor mv, String exception, String message) {
@@ -140,4 +156,92 @@ public class CodegenUtil {
mv.visitMaxs(-1, -1); mv.visitMaxs(-1, -1);
mv.visitEnd(); mv.visitEnd();
} }
@NotNull
public static JvmClassName getInternalClassName(FunctionDescriptor descriptor) {
final int paramCount = descriptor.getValueParameters().size();
if (descriptor.getReceiverParameter().exists()) {
return JvmClassName.byInternalName("jet/ExtensionFunction" + paramCount);
}
else {
return JvmClassName.byInternalName("jet/Function" + paramCount);
}
}
static JvmMethodSignature erasedInvokeSignature(FunctionDescriptor fd) {
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false);
signatureWriter.writeFormalTypeParametersStart();
signatureWriter.writeFormalTypeParametersEnd();
boolean isExtensionFunction = fd.getReceiverParameter().exists();
int paramCount = fd.getValueParameters().size();
if (isExtensionFunction) {
paramCount++;
}
signatureWriter.writeParametersStart();
for (int i = 0; i < paramCount; ++i) {
signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
signatureWriter.writeAsmType(JetTypeMapper.OBJECT_TYPE, true);
signatureWriter.writeParameterTypeEnd();
}
signatureWriter.writeParametersEnd();
signatureWriter.writeReturnType();
signatureWriter.writeAsmType(JetTypeMapper.OBJECT_TYPE, true);
signatureWriter.writeReturnTypeEnd();
return signatureWriter.makeJvmMethodSignature("invoke");
}
public static boolean isConst(CalculatedClosure closure) {
return closure.getCaptureThis() == null && closure.getCaptureReceiver() == null && closure.getCaptureVariables().isEmpty();
}
public static JetDelegatorToSuperCall findSuperCall(JetElement classOrObject, BindingContext bindingContext) {
if (!(classOrObject instanceof JetClassOrObject)) {
return null;
}
if (classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait()) {
return null;
}
for (JetDelegationSpecifier specifier : ((JetClassOrObject) classOrObject).getDelegationSpecifiers()) {
if (specifier instanceof JetDelegatorToSuperCall) {
JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
assert superType != null;
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
assert superClassDescriptor != null;
if (!isInterface(superClassDescriptor)) {
return (JetDelegatorToSuperCall) specifier;
}
}
}
return null;
}
public static void generateClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
final ClassifierDescriptor captureThis = closure.getCaptureThis();
final int access = ACC_PUBLIC | ACC_SYNTHETIC | ACC_FINAL;
if (captureThis != null) {
v.newField(null, access, THIS$0, typeMapper.mapType(captureThis.getDefaultType(), MapTypeMode.VALUE).getDescriptor(), null,
null);
}
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) {
v.newField(null, access, RECEIVER$0, typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.VALUE).getDescriptor(),
null, null);
}
final List<Pair<String, Type>> fields = closure.getRecordedFields();
for (Pair<String, Type> field : fields) {
v.newField(null, access, field.first, field.second.getDescriptor(), null, null);
}
}
} }
@@ -18,7 +18,8 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
@@ -32,23 +33,25 @@ import java.util.List;
public class ConstructorFrameMap extends FrameMap { public class ConstructorFrameMap extends FrameMap {
private int myOuterThisIndex = -1; private int myOuterThisIndex = -1;
public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, boolean hasThis0) { public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor) {
enterTemp(JetTypeMapper.OBJECT_TYPE); // this enterTemp(JetTypeMapper.OBJECT_TYPE); // this
if (descriptor != null) {
if (hasThis0) { final List<JvmMethodParameterSignature> parameterTypes = callableMethod.getSignature().getKotlinParameterTypes();
myOuterThisIndex = enterTemp(JetTypeMapper.OBJECT_TYPE); // outer class instance if (parameterTypes != null) {
for (JvmMethodParameterSignature parameterType : parameterTypes) {
if (parameterType.getKind() == JvmMethodParameterKind.OUTER) {
myOuterThisIndex = enterTemp(JetTypeMapper.OBJECT_TYPE); // this0
}
else if (parameterType.getKind() != JvmMethodParameterKind.VALUE) {
enterTemp(parameterType.getAsmType());
}
else {
break;
}
} }
} }
List<Type> explicitArgTypes = callableMethod.getValueParameterTypes(); List<Type> explicitArgTypes = callableMethod.getValueParameterTypes();
if (descriptor != null &&
(descriptor.getContainingDeclaration().getKind() == ClassKind.ENUM_CLASS ||
descriptor.getContainingDeclaration().getKind() == ClassKind.ENUM_ENTRY)) {
enterTemp(JetTypeMapper.OBJECT_TYPE); // name
enterTemp(Type.INT_TYPE); // ordinal
}
List<ValueParameterDescriptor> paramDescrs = descriptor != null List<ValueParameterDescriptor> paramDescrs = descriptor != null
? descriptor.getValueParameters() ? descriptor.getValueParameters()
: Collections.<ValueParameterDescriptor>emptyList(); : Collections.<ValueParameterDescriptor>emptyList();
@@ -33,6 +33,7 @@ import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method; import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.context.*;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
@@ -63,7 +64,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull;
* @author yole * @author yole
* @author alex.tkachman * @author alex.tkachman
*/ */
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implements LocalLookup {
private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException"; private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException";
private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException"; private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException";
@@ -78,7 +79,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private final Type returnType; private final Type returnType;
private final BindingContext bindingContext; private final BindingContext bindingContext;
private final CodegenContext context; final CodegenContext context;
private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>(); private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>();
private final Collection<String> localVariableNames = new HashSet<String>(); private final Collection<String> localVariableNames = new HashSet<String>();
@@ -136,6 +137,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
this.context = context; this.context = context;
} }
public GenerationState getState() {
return state;
}
StackValue castToRequiredTypeOfInterfaceIfNeeded(StackValue inner, DeclarationDescriptor provided, @Nullable ClassDescriptor required) { StackValue castToRequiredTypeOfInterfaceIfNeeded(StackValue inner, DeclarationDescriptor provided, @Nullable ClassDescriptor required) {
if (required == null) { if (required == null) {
return inner; return inner;
@@ -218,14 +223,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private StackValue visitClassOrObject(JetClassOrObject declaration) { private StackValue visitClassOrObject(JetClassOrObject declaration) {
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, declaration); ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, declaration);
ObjectOrClosureCodegen closure = new LocalClassClosureCodegen(this, context, state, descriptor); assert descriptor != null;
Pair<JvmClassName, ClassBuilder> nameAndVisitor = state.forAnonymousSubclass(declaration); Pair<JvmClassName, ClassBuilder> nameAndVisitor = state.forAnonymousSubclass(declaration);
closure.cv = nameAndVisitor.getSecond(); final CodegenContext objectContext = context.intoAnonymousClass(descriptor, this);
closure.name = nameAndVisitor.getFirst();
final CodegenContext objectContext = closure.context.intoAnonymousClass(
closure, descriptor, OwnerKind.IMPLEMENTATION,
typeMapper);
new ImplementationBodyCodegen(declaration, objectContext, nameAndVisitor.getSecond(), state).generate(); new ImplementationBodyCodegen(declaration, objectContext, nameAndVisitor.getSecond(), state).generate();
return StackValue.none(); return StackValue.none();
@@ -394,13 +396,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return StackValue.none(); return StackValue.none();
} }
generateForInIterable(expression, loopRangeType); generateForInIterable(expression);
return StackValue.none(); return StackValue.none();
} }
} }
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
private void generateForInIterable(JetForExpression expression, Type loopRangeType) { private void generateForInIterable(JetForExpression expression) {
generateForLoop(expression.getBody(), new IteratorForLoopGenerator(expression)); generateForLoop(expression.getBody(), new IteratorForLoopGenerator(expression));
} }
@@ -410,9 +412,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private interface ForLoopGenerator { private interface ForLoopGenerator {
void beforeLoop(); void beforeLoop();
void conditionAndJump(@NotNull Label loopExit); void conditionAndJump(@NotNull Label loopExit);
void beforeBody(); void beforeBody();
void afterBody(); void afterBody();
void afterLoop(); void afterLoop();
} }
@@ -457,6 +463,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@NotNull @NotNull
private JetType getElementType(JetForExpression forExpression) { private JetType getElementType(JetForExpression forExpression) {
JetExpression loopRange = forExpression.getLoopRange(); JetExpression loopRange = forExpression.getLoopRange();
assert loopRange != null;
ResolvedCall<FunctionDescriptor> nextCall = getNotNull(bindingContext, ResolvedCall<FunctionDescriptor> nextCall = getNotNull(bindingContext,
LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange, LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
"No next() function " + DiagnosticUtils.atLocation(loopRange)); "No next() function " + DiagnosticUtils.atLocation(loopRange));
@@ -470,7 +477,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (loopParameter != null) { if (loopParameter != null) {
// E e = tmp<iterator>.next() // E e = tmp<iterator>.next()
final VariableDescriptor parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, loopParameter); final VariableDescriptor parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, loopParameter);
final Type asmTypeForParameter = asmType(parameterDescriptor.getType()); @SuppressWarnings("ConstantConditions") final Type asmTypeForParameter = asmType(parameterDescriptor.getType());
final int parameterIndex = myFrameMap.enter(parameterDescriptor, asmTypeForParameter); final int parameterIndex = myFrameMap.enter(parameterDescriptor, asmTypeForParameter);
leaveVariableTasks.add(new Runnable() { leaveVariableTasks.add(new Runnable() {
@Override @Override
@@ -510,7 +517,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
for (JetMultiDeclarationEntry variableDeclaration : entries) { for (JetMultiDeclarationEntry variableDeclaration : entries) {
final VariableDescriptor componentDescriptor = bindingContext.get(BindingContext.VARIABLE, variableDeclaration); final VariableDescriptor componentDescriptor = bindingContext.get(BindingContext.VARIABLE, variableDeclaration);
final Type componentAsmType = asmType(componentDescriptor.getReturnType()); @SuppressWarnings("ConstantConditions") final Type componentAsmType = asmType(componentDescriptor.getReturnType());
final int componentVarIndex = myFrameMap.enter(componentDescriptor, componentAsmType); final int componentVarIndex = myFrameMap.enter(componentDescriptor, componentAsmType);
leaveVariableTasks.add(new Runnable() { leaveVariableTasks.add(new Runnable() {
@Override @Override
@@ -524,7 +531,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}); });
ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(BindingContext.COMPONENT_RESOLVED_CALL, variableDeclaration); ResolvedCall<FunctionDescriptor> resolvedCall =
bindingContext.get(BindingContext.COMPONENT_RESOLVED_CALL, variableDeclaration);
assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText(); assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
Call call = makeFakeCall(new TransientReceiver(elementType)); Call call = makeFakeCall(new TransientReceiver(elementType));
invokeFunction(call, StackValue.local(tmpParameterIndex, asmElementType), resolvedCall); invokeFunction(call, StackValue.local(tmpParameterIndex, asmElementType), resolvedCall);
@@ -554,9 +562,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
super(forExpression); super(forExpression);
JetExpression loopRange = forExpression.getLoopRange(); JetExpression loopRange = forExpression.getLoopRange();
assert loopRange != null;
this.iteratorCall = getNotNull(bindingContext, this.iteratorCall = getNotNull(bindingContext,
LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange, LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange,
"No .iterator() function " + DiagnosticUtils.atLocation(loopRange)); "No .iterator() function " + DiagnosticUtils.atLocation(loopRange));
JetType iteratorType = iteratorCall.getResultingDescriptor().getReturnType(); JetType iteratorType = iteratorCall.getResultingDescriptor().getReturnType();
assert iteratorType != null; assert iteratorType != null;
@@ -583,10 +592,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
// tmp<iterator>.hasNext() // tmp<iterator>.hasNext()
JetExpression loopRange = forExpression.getLoopRange(); JetExpression loopRange = forExpression.getLoopRange();
ResolvedCall<FunctionDescriptor> hasNextCall = getNotNull(bindingContext, @SuppressWarnings("ConstantConditions") ResolvedCall<FunctionDescriptor> hasNextCall = getNotNull(bindingContext,
LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange,
"No hasNext() function " + DiagnosticUtils.atLocation(loopRange)); "No hasNext() function " + DiagnosticUtils.atLocation(loopRange));
Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType())); @SuppressWarnings("ConstantConditions") Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
invokeFunction(fakeCall, StackValue.local(iteratorVarIndex, asmTypeForIterator), hasNextCall); invokeFunction(fakeCall, StackValue.local(iteratorVarIndex, asmTypeForIterator), hasNextCall);
JetType type = hasNextCall.getResultingDescriptor().getReturnType(); JetType type = hasNextCall.getResultingDescriptor().getReturnType();
@@ -599,9 +608,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override @Override
protected void assignToLoopParameter(int parameterIndex) { protected void assignToLoopParameter(int parameterIndex) {
Call fakeCall = @SuppressWarnings("ConstantConditions") Call fakeCall =
makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType())); makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
invokeFunction(fakeCall, StackValue.local(iteratorVarIndex, asmTypeForIterator), nextCall); invokeFunction(fakeCall, StackValue.local(iteratorVarIndex, asmTypeForIterator), nextCall);
//noinspection ConstantConditions
v.store(parameterIndex, asmType(nextCall.getResultingDescriptor().getReturnType())); v.store(parameterIndex, asmType(nextCall.getResultingDescriptor().getReturnType()));
} }
@@ -763,7 +773,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override @Override
protected void generatePrologue() { protected void generatePrologue() {
myIndexVar = lookupLocal(parameterDescriptor); myIndexVar = lookupLocalIndex(parameterDescriptor);
myCountVar = myFrameMap.enterTemp(Type.INT_TYPE); myCountVar = myFrameMap.enterTemp(Type.INT_TYPE);
myDeltaVar = myFrameMap.enterTemp(Type.INT_TYPE); myDeltaVar = myFrameMap.enterTemp(Type.INT_TYPE);
if (isIntRangeExpr(expression.getLoopRange())) { if (isIntRangeExpr(expression.getLoopRange())) {
@@ -977,7 +987,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
StackValue closure = genClosure(function); StackValue closure = genClosure(function);
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function); DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
int index = myFrameMap.getIndex(descriptor); int index = lookupLocalIndex(descriptor);
closure.put(OBJECT_TYPE, v); closure.put(OBJECT_TYPE, v);
v.store(index, OBJECT_TYPE); v.store(index, OBJECT_TYPE);
return StackValue.none(); return StackValue.none();
@@ -996,89 +1006,90 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
private StackValue genClosure(JetExpression expression) { private StackValue genClosure(JetExpression expression) {
ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context); final FunctionDescriptor descriptor = bindingContext.get(BindingContext.FUNCTION, expression);
final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression); final ClosureAnnotator closureAnnotator = state.getInjector().getClosureAnnotator();
final ClassDescriptor classDescriptor = closureAnnotator.classDescriptorForFunctionDescriptor(descriptor);
final CalculatedClosure closure = closureAnnotator.getCalculatedClosure(classDescriptor);
if (closureCodegen.isConst()) { ClosureCodegen closureCodegen = new ClosureCodegen(state, (MutableClosure) closure).gen(expression, context, this);
v.invokestatic(closure.getClassname().getInternalName(), "$getInstance", "()" + closure.getClassname().getDescriptor());
final JvmClassName className = closureCodegen.name;
final Type asmType = className.getAsmType();
final String internalName = className.getInternalName();
if (CodegenUtil.isConst(closure)) {
v.invokestatic(internalName, "$getInstance", "()" + className.getDescriptor());
} }
else { else {
v.anew(closure.getClassname().getAsmType()); v.anew(asmType);
v.dup(); v.dup();
final Method cons = closure.getConstructor(); final Method cons = closureCodegen.constructor;
pushClosureOnStack(closure, false);
int k = 0; v.invokespecial(internalName, "<init>", cons.getDescriptor());
if (closure.isCaptureThis()) {
k++;
v.load(0, OBJECT_TYPE);
}
if (closure.isCaptureReceiver()) {
k++;
v.load(context.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor ? 0 : 1,
typeMapper.mapType(closure.getCaptureReceiver().getDefaultType(), MapTypeMode.IMPL));
}
for (int i = 0; i < closure.getArgs().size(); i++) {
StackValue arg = closure.getArgs().get(i);
arg.put(cons.getArgumentTypes()[i + k], v);
}
v.invokespecial(closure.getClassname().getInternalName(), "<init>", cons.getDescriptor());
} }
return StackValue.onStack(closure.getClassname().getAsmType()); return StackValue.onStack(asmType);
} }
@Override @Override
public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) { public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) {
ObjectOrClosureCodegen closureCodegen = new ObjectOrClosureCodegen(this, context, state); CalculatedClosure closure = state.generateObjectLiteral(expression, this);
GeneratedAnonymousClassDescriptor closure = state.generateObjectLiteral(expression, closureCodegen);
Type type = closure.getClassname().getAsmType(); ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, expression.getObjectDeclaration());
assert constructorDescriptor != null;
CallableMethod constructor = typeMapper.mapToCallableMethod(constructorDescriptor, closure);
final JvmClassName name = closure.getClassName();
Type type = name.getAsmType();
v.anew(type); v.anew(type);
v.dup(); v.dup();
final List<Type> consArgTypes = new LinkedList<Type>(Arrays.asList(closure.getConstructor().getArgumentTypes())); final Method cons = constructor.getSignature().getAsmMethod();
if (consArgTypes.size() > 0) { pushClosureOnStack(closure, false);
v.load(0, OBJECT_TYPE);
}
if (closureCodegen.captureReceiver != null) { final JetDelegatorToSuperCall superCall = closure.getSuperCall();
final Type asmType = typeMapper.mapType(closureCodegen.captureReceiver.getDefaultType(), MapTypeMode.IMPL); if (superCall != null) {
v.load(context.isStatic() ? 0 : 1, asmType);
consArgTypes.add(asmType);
}
for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closureCodegen.closure.entrySet()) {
if (entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) {
Type sharedVarType = typeMapper.getSharedVarType(entry.getKey());
if (sharedVarType == null) {
sharedVarType = state.getInjector().getJetTypeMapper()
.mapType(((VariableDescriptor) entry.getKey()).getType(), MapTypeMode.VALUE);
}
consArgTypes.add(sharedVarType);
entry.getValue().getOuterValue().put(sharedVarType, v);
}
}
if (closureCodegen.superCall != null) {
ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET,
closureCodegen.superCall superCall
.getCalleeExpression() .getCalleeExpression()
.getConstructorReferenceExpression()); .getConstructorReferenceExpression());
assert superConstructor != null; assert superConstructor != null;
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, CallableMethod superCallable = typeMapper
typeMapper.hasThis0(superConstructor.getContainingDeclaration())); .mapToCallableMethod(superConstructor, typeMapper.getCalculatedClosure(superConstructor.getContainingDeclaration()));
Type[] argumentTypes = superCallable.getSignature().getAsmMethod().getArgumentTypes(); Type[] argumentTypes = superCallable.getSignature().getAsmMethod().getArgumentTypes();
Collections.addAll(consArgTypes, argumentTypes); ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, superCall.getCalleeExpression());
ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, closureCodegen.superCall.getCalleeExpression());
assert resolvedCall != null; assert resolvedCall != null;
pushMethodArguments(resolvedCall, Arrays.asList(argumentTypes)); pushMethodArguments(resolvedCall, Arrays.asList(argumentTypes));
} }
Method cons = new Method("<init>", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()])); v.invokespecial(name.getInternalName(), "<init>", cons.getDescriptor());
v.invokespecial(closure.getClassname().getInternalName(), "<init>", cons.getDescriptor()); return StackValue.onStack(type);
return StackValue.onStack(closure.getClassname().getAsmType()); }
protected void pushClosureOnStack(CalculatedClosure closure, boolean ignoreThisAndReceiver) {
if (closure != null) {
if (!ignoreThisAndReceiver) {
final ClassDescriptor captureThis = closure.getCaptureThis();
if (captureThis != null) {
generateThisOrOuter(captureThis).put(OBJECT_TYPE, v);
}
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) {
final Type asmType = typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.IMPL);
v.load(context.isStatic() ? 0 : 1, asmType);
}
}
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()).getType(), MapTypeMode.VALUE);
}
entry.getValue().getOuterValue(this).put(sharedVarType, v);
//}
}
}
} }
private StackValue generateBlock(List<JetElement> statements) { private StackValue generateBlock(List<JetElement> statements) {
@@ -1301,7 +1312,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
} }
int index = lookupLocal(descriptor); int index = lookupLocalIndex(descriptor);
if (index >= 0) { if (index >= 0) {
return stackValueForLocal(descriptor, index); return stackValueForLocal(descriptor, index);
} }
@@ -1379,7 +1390,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return StackValue.onStack(OBJECT_TYPE); return StackValue.onStack(OBJECT_TYPE);
} }
StackValue value = context.lookupInContext(descriptor, v, StackValue.local(0, OBJECT_TYPE)); StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false);
if (value != null) { if (value != null) {
if (value instanceof StackValue.Composed) { if (value instanceof StackValue.Composed) {
@@ -1445,39 +1456,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
} }
public int lookupLocal(DeclarationDescriptor descriptor) { @Override
return myFrameMap.getIndex(descriptor); public boolean lookupLocal(DeclarationDescriptor descriptor) {
return lookupLocalIndex(descriptor) != -1;
} }
public void invokeFunctionNoParams(FunctionDescriptor functionDescriptor, Type expectedType, InstructionAdapter v) { public int lookupLocalIndex(DeclarationDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = functionDescriptor.getOriginal().getContainingDeclaration(); return myFrameMap.getIndex(descriptor);
boolean isStatic = containingDeclaration instanceof NamespaceDescriptor;
functionDescriptor = functionDescriptor.getOriginal();
JvmClassName owner;
IntrinsicMethod intrinsic = state.getInjector().getIntrinsics().getIntrinsic(functionDescriptor);
if (intrinsic != null) {
intrinsic.generate(this, v, expectedType, null, null, StackValue.onStack(OBJECT_TYPE), state);
return;
}
boolean isInterface;
boolean isInsideClass = containingDeclaration == context.getThisDescriptor();
if (isInsideClass || isStatic) {
owner = typeMapper.getOwner(functionDescriptor, contextKind());
isInterface = false;
}
else {
owner = typeMapper.getOwner(functionDescriptor, OwnerKind.IMPLEMENTATION);
isInterface = CodegenUtil.isInterface(containingDeclaration);
}
int opcode = isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL;
v.visitMethodInsn(opcode, owner.getInternalName(), functionDescriptor.getName().getName(),
typeMapper.mapSignature(functionDescriptor.getName(), functionDescriptor).getAsmMethod().getDescriptor());
JetType returnType = functionDescriptor.getReturnType();
assert returnType != null;
StackValue.onStack(asmType(returnType)).coerce(expectedType, v);
} }
public StackValue.Property intermediateValueForProperty( public StackValue.Property intermediateValueForProperty(
@@ -1499,7 +1484,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
boolean isInsideClass = !isFakeOverride && boolean isInsideClass = !isFakeOverride &&
(((containingDeclaration == null && !context.hasThisDescriptor() || (((containingDeclaration == null && !context.hasThisDescriptor() ||
context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) || context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) ||
(context.getParentContext() instanceof CodegenContexts.NamespaceContext) && (context.getParentContext() instanceof CodegenContext.NamespaceContext) &&
context.getParentContext().getContextDescriptor() == containingDeclaration) context.getParentContext().getContextDescriptor() == containingDeclaration)
&& contextKind() != OwnerKind.TRAIT_IMPL); && contextKind() != OwnerKind.TRAIT_IMPL);
Method getter = null; Method getter = null;
@@ -1681,7 +1666,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (enclosed != context.getThisDescriptor()) { if (enclosed != context.getThisDescriptor()) {
CodegenContext c = context; CodegenContext c = context;
//noinspection ConstantConditions //noinspection ConstantConditions
while (!(c instanceof CodegenContexts.ClassContext) || while (!(c instanceof CodegenContext.ClassContext) ||
!DescriptorUtils.isSubclass(c.getThisDescriptor(), enclosed)) { !DescriptorUtils.isSubclass(c.getThisDescriptor(), enclosed)) {
c = c.getParentContext(); c = c.getParentContext();
assert c != null; assert c != null;
@@ -1761,7 +1746,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
//} //}
if (isCallAsFunctionObject(fd)) { if (isCallAsFunctionObject(fd)) {
SimpleFunctionDescriptor invoke = CodegenUtil.createInvoke(fd); SimpleFunctionDescriptor invoke = CodegenUtil.createInvoke(fd);
callableMethod = ClosureCodegen.asCallableMethod(invoke, typeMapper); callableMethod = typeMapper.asCallableMethod(invoke);
} }
else { else {
callableMethod = typeMapper.mapToCallableMethod(fd, superCall, OwnerKind.IMPLEMENTATION); callableMethod = typeMapper.mapToCallableMethod(fd, superCall, OwnerKind.IMPLEMENTATION);
@@ -1895,14 +1880,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
private StackValue generateReceiver(DeclarationDescriptor provided) { private StackValue generateReceiver(DeclarationDescriptor provided) {
assert context instanceof CodegenContexts.ReceiverContext; if (context.getReceiverDescriptor() == provided) {
CodegenContexts.ReceiverContext cur = (CodegenContexts.ReceiverContext) context; StackValue result = context.getReceiverExpression(typeMapper);
if (cur.getReceiverDescriptor() == provided) {
StackValue result = cur.getReceiverExpression(typeMapper);
return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null); return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null);
} }
StackValue result = context.lookupInContext(provided, v, StackValue.local(0, OBJECT_TYPE)); StackValue result = context.lookupInContext(provided, StackValue.local(0, OBJECT_TYPE), state, false);
return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null); return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null);
} }
@@ -1910,12 +1893,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
CodegenContext cur = context; CodegenContext cur = context;
StackValue result = StackValue.local(0, OBJECT_TYPE); StackValue result = StackValue.local(0, OBJECT_TYPE);
while (cur != null) { while (cur != null) {
if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext)) { if (cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext)) {
cur = cur.getParentContext(); cur = cur.getParentContext();
} }
if (cur instanceof CodegenContexts.ScriptContext) { if (cur instanceof CodegenContext.ScriptContext) {
CodegenContexts.ScriptContext scriptContext = (CodegenContexts.ScriptContext) cur; CodegenContext.ScriptContext scriptContext = (CodegenContext.ScriptContext) cur;
JvmClassName currentScriptClassName = JvmClassName currentScriptClassName =
state.getInjector().getClosureAnnotator().classNameForScriptDescriptor(scriptContext.getScriptDescriptor()); state.getInjector().getClosureAnnotator().classNameForScriptDescriptor(scriptContext.getScriptDescriptor());
@@ -1933,9 +1916,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
assert cur != null; assert cur != null;
result = cur.getOuterExpression(result); result = cur.getOuterExpression(result, false);
if (cur instanceof CodegenContexts.ConstructorContext) { if (cur instanceof CodegenContext.ConstructorContext) {
cur = cur.getParentContext(); cur = cur.getParentContext();
} }
assert cur != null; assert cur != null;
@@ -1953,7 +1936,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
Type type = asmType(calleeContainingClass.getDefaultType()); Type type = asmType(calleeContainingClass.getDefaultType());
StackValue result = StackValue.local(0, type); StackValue result = StackValue.local(0, type);
while (cur != null) { while (cur != null) {
if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext)) { if (cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext)) {
cur = cur.getParentContext(); cur = cur.getParentContext();
} }
@@ -1969,9 +1952,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
} }
result = cur.getOuterExpression(result); result = cur.getOuterExpression(result, false);
if (cur instanceof CodegenContexts.ConstructorContext) { if (cur instanceof CodegenContext.ConstructorContext) {
cur = cur.getParentContext(); cur = cur.getParentContext();
} }
assert cur != null; assert cur != null;
@@ -2125,7 +2108,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (typeMapper.isVarCapturedInClosure(declarationDescriptor)) { if (typeMapper.isVarCapturedInClosure(declarationDescriptor)) {
return -1; return -1;
} }
return lookupLocal(declarationDescriptor); return lookupLocalIndex(declarationDescriptor);
} }
@Override @Override
@@ -2220,7 +2203,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
private StackValue generateIn(JetBinaryExpression expression) { private StackValue generateIn(JetBinaryExpression expression) {
JetExpression expr = expression.getLeft();
boolean inverted = expression.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN; boolean inverted = expression.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN;
if (isIntRangeExpr(expression.getRight())) { if (isIntRangeExpr(expression.getRight())) {
StackValue leftValue = StackValue.expression(Type.INT_TYPE, expression.getLeft(), this); StackValue leftValue = StackValue.expression(Type.INT_TYPE, expression.getLeft(), this);
@@ -2651,9 +2633,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) { private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) {
int functionLocalIndex = myFrameMap.getIndex(op); int functionLocalIndex = lookupLocalIndex(op);
if (functionLocalIndex >= 0) { if (functionLocalIndex >= 0) {
stackValueForLocal(op, functionLocalIndex).put(ClosureCodegen.getInternalClassName(op).getAsmType(), v); stackValueForLocal(op, functionLocalIndex).put(CodegenUtil.getInternalClassName(op).getAsmType(), v);
} }
ResolvedCall<? extends CallableDescriptor> resolvedCall = ResolvedCall<? extends CallableDescriptor> resolvedCall =
bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference()); bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
@@ -2840,7 +2822,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) { if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
return; return;
} }
int index = lookupLocal(variableDescriptor); int index = lookupLocalIndex(variableDescriptor);
if (index < 0) { if (index < 0) {
throw new IllegalStateException("Local variable not found for " + variableDescriptor); throw new IllegalStateException("Local variable not found for " + variableDescriptor);
@@ -2894,15 +2876,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.anew(type); v.anew(type);
v.dup(); v.dup();
// TODO typechecker must verify that we're the outer class of the instance being created final ClassDescriptor classDescriptor = ((ConstructorDescriptor) constructorDescriptor).getContainingDeclaration();
//noinspection ConstantConditions
if (!receiver.type.equals(Type.VOID_TYPE)) {
receiver.put(receiver.type, v);
}
CallableMethod method = typeMapper CallableMethod method = typeMapper
.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, typeMapper .mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, typeMapper
.hasThis0(((ConstructorDescriptor) constructorDescriptor).getContainingDeclaration())); .getCalculatedClosure(classDescriptor));
receiver.put(receiver.type, v);
pushClosureOnStack(typeMapper.getCalculatedClosure(classDescriptor), true);
invokeMethodWithArguments(method, expression, StackValue.none()); invokeMethodWithArguments(method, expression, StackValue.none());
} }
} }
@@ -3089,10 +3069,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor); return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor);
} }
else { else {
if (descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor) { if (descriptor instanceof CallableDescriptor) {
return generateReceiver(descriptor); return generateReceiver(descriptor);
} }
throw new UnsupportedOperationException(); throw new UnsupportedOperationException("neither this nor receiver");
} }
} }
@@ -3143,7 +3123,7 @@ The "returned" value of try expression with no finally is either the last expres
assert descriptor != null; assert descriptor != null;
Type descriptorType = asmType(descriptor.getType()); Type descriptorType = asmType(descriptor.getType());
myFrameMap.enter(descriptor, descriptorType); myFrameMap.enter(descriptor, descriptorType);
int index = lookupLocal(descriptor); int index = lookupLocalIndex(descriptor);
v.store(index, descriptorType); v.store(index, descriptorType);
gen(clause.getCatchBody(), expectedAsmType); gen(clause.getCatchBody(), expectedAsmType);
@@ -3308,7 +3288,7 @@ The "returned" value of try expression with no finally is either the last expres
myFrameMap.enter(variableDescriptor, varType); myFrameMap.enter(variableDescriptor, varType);
expressionToMatch.dupReceiver(v); expressionToMatch.dupReceiver(v);
expressionToMatch.put(varType, v); expressionToMatch.put(varType, v);
final int varIndex = myFrameMap.getIndex(variableDescriptor); final int varIndex = lookupLocalIndex(variableDescriptor);
v.store(varIndex, varType); v.store(varIndex, varType);
return generateWhenCondition(varType, varIndex, false, ((JetBindingPattern) pattern).getCondition(), null); return generateWhenCondition(varType, varIndex, false, ((JetBindingPattern) pattern).getCondition(), null);
} }
@@ -3573,5 +3553,4 @@ The "returned" value of try expression with no finally is either the last expres
public String toString() { public String toString() {
return context.getContextDescriptor().toString(); return context.getContextDescriptor().toString();
} }
} }
@@ -25,6 +25,7 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method; import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter; import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter;
@@ -74,7 +75,7 @@ public class FunctionCodegen {
@Nullable String propertyTypeSignature, FunctionDescriptor functionDescriptor @Nullable String propertyTypeSignature, FunctionDescriptor functionDescriptor
) { ) {
CodegenContexts.MethodContext funContext = owner.intoFunction(functionDescriptor, state.getInjector().getJetTypeMapper()); CodegenContext.MethodContext funContext = owner.intoFunction(functionDescriptor);
final JetExpression bodyExpression = f.getBodyExpression(); final JetExpression bodyExpression = f.getBodyExpression();
generatedMethod(bodyExpression, jvmMethod, needJetAnnotations, propertyTypeSignature, funContext, functionDescriptor, f); generatedMethod(bodyExpression, jvmMethod, needJetAnnotations, propertyTypeSignature, funContext, functionDescriptor, f);
@@ -84,7 +85,7 @@ public class FunctionCodegen {
JetExpression bodyExpressions, JetExpression bodyExpressions,
JvmMethodSignature jvmSignature, JvmMethodSignature jvmSignature,
boolean needJetAnnotations, @Nullable String propertyTypeSignature, boolean needJetAnnotations, @Nullable String propertyTypeSignature,
CodegenContexts.MethodContext context, CodegenContext.MethodContext context,
FunctionDescriptor functionDescriptor, FunctionDescriptor functionDescriptor,
JetDeclarationWithBody fun JetDeclarationWithBody fun
) { ) {
@@ -334,7 +335,6 @@ public class FunctionCodegen {
} }
endVisit(mv, null, fun); endVisit(mv, null, fun);
mv.visitEnd();
generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor, kind); generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor, kind);
} }
@@ -417,7 +417,7 @@ public class FunctionCodegen {
} }
static void generateDefaultIfNeeded( static void generateDefaultIfNeeded(
CodegenContexts.MethodContext owner, CodegenContext.MethodContext owner,
GenerationState state, GenerationState state,
ClassBuilder v, ClassBuilder v,
Method jvmSignature, Method jvmSignature,
@@ -477,7 +477,7 @@ public class FunctionCodegen {
} }
private static void generateDefaultImpl( private static void generateDefaultImpl(
CodegenContexts.MethodContext owner, CodegenContext.MethodContext owner,
GenerationState state, GenerationState state,
Method jvmSignature, Method jvmSignature,
FunctionDescriptor functionDescriptor, FunctionDescriptor functionDescriptor,
@@ -1,81 +0,0 @@
/*
* Copyright 2010-2012 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.
*/
/*
* @author max
*/
package org.jetbrains.jet.codegen;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import java.util.ArrayList;
import java.util.List;
public class GeneratedAnonymousClassDescriptor {
private final JvmClassName classname;
private final Method constructor;
private final ClassDescriptor captureThis;
private final ClassifierDescriptor captureReceiver;
private final List<StackValue> args = new ArrayList<StackValue>();
public GeneratedAnonymousClassDescriptor(
JvmClassName classname,
Method constructor,
ClassDescriptor captureThis,
ClassifierDescriptor captureReceiver
) {
this.classname = classname;
this.constructor = constructor;
this.captureThis = captureThis;
this.captureReceiver = captureReceiver;
}
public JvmClassName getClassname() {
return classname;
}
public Method getConstructor() {
return constructor;
}
public void addArg(StackValue local) {
args.add(local);
}
public List<StackValue> getArgs() {
return args;
}
public boolean isCaptureThis() {
return captureThis != null;
}
public boolean isCaptureReceiver() {
return captureReceiver != null;
}
public ClassDescriptor getCaptureThis() {
return captureThis;
}
public ClassifierDescriptor getCaptureReceiver() {
return captureReceiver;
}
}
@@ -25,9 +25,10 @@ import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.commons.Method; import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.codegen.context.CalculatedClosure;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.di.InjectorForJvmCodegen; import org.jetbrains.jet.di.InjectorForJvmCodegen;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -56,7 +57,6 @@ public class GenerationState {
// out parameter // out parameter
private Method scriptConstructorMethod; private Method scriptConstructorMethod;
private final BindingContext bindingContext; private final BindingContext bindingContext;
private final JetTypeMapper typeMapper;
public GenerationState(Project project, ClassBuilderFactory builderFactory, AnalyzeExhaust analyzeExhaust, List<JetFile> files) { public GenerationState(Project project, ClassBuilderFactory builderFactory, AnalyzeExhaust analyzeExhaust, List<JetFile> files) {
@@ -75,7 +75,6 @@ public class GenerationState {
this.injector = new InjectorForJvmCodegen( this.injector = new InjectorForJvmCodegen(
bindingContext, bindingContext,
this.files, builtinToJavaTypesMapping, builderFactory.getClassBuilderMode(), this, builderFactory, project); this.files, builtinToJavaTypesMapping, builderFactory.getClassBuilderMode(), this, builderFactory, project);
typeMapper = injector.getJetTypeMapper();
} }
private void markUsed() { private void markUsed() {
@@ -195,25 +194,20 @@ public class GenerationState {
codegen.generate(errorHandler, progress); codegen.generate(errorHandler, progress);
} }
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ObjectOrClosureCodegen closure) { public CalculatedClosure generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen expressionCodegen) {
JetObjectDeclaration objectDeclaration = literal.getObjectDeclaration(); JetObjectDeclaration objectDeclaration = literal.getObjectDeclaration();
Pair<JvmClassName, ClassBuilder> nameAndVisitor = forAnonymousSubclass(objectDeclaration); Pair<JvmClassName, ClassBuilder> nameAndVisitor = forAnonymousSubclass(objectDeclaration);
closure.cv = nameAndVisitor.getSecond(); final ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, objectDeclaration);
closure.name = nameAndVisitor.getFirst(); assert classDescriptor != null;
final CodegenContext objectContext = closure.context.intoAnonymousClass(
closure, bindingContext.get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION, final CalculatedClosure closure = getInjector().getClosureAnnotator().getCalculatedClosure(classDescriptor);
typeMapper);
final CodegenContext objectContext = expressionCodegen.context.intoAnonymousClass(classDescriptor, expressionCodegen);
new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate(); new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate();
ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, objectDeclaration); return closure;
assert constructorDescriptor != null;
CallableMethod callableMethod = typeMapper.mapToCallableMethod(
constructorDescriptor,
typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, callableMethod.getSignature().getAsmMethod(),
objectContext.outerWasUsed, null);
} }
public String createText() { public String createText() {
@@ -26,6 +26,9 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method; import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.context.CalculatedClosure;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.MutableClosure;
import org.jetbrains.jet.codegen.signature.*; import org.jetbrains.jet.codegen.signature.*;
import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter; import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter;
@@ -34,6 +37,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.OverridingUtil; import org.jetbrains.jet.lang.resolve.OverridingUtil;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.JdkNames; import org.jetbrains.jet.lang.resolve.java.JdkNames;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
@@ -294,9 +298,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
assert superType != null; assert superType != null;
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
assert superClassDescriptor != null;
if (!CodegenUtil.isInterface(superClassDescriptor)) { if (!CodegenUtil.isInterface(superClassDescriptor)) {
superClassType = superType; superClassType = superType;
assert superClassDescriptor != null;
superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName(); superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName();
superCall = specifier; superCall = specifier;
} }
@@ -338,6 +342,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateAccessors(); generateAccessors();
generateEnumMethods(); generateEnumMethods();
CodegenUtil.generateClosureFields(context.closure, v, state.getInjector().getJetTypeMapper());
} }
private void generateEnumMethods() { private void generateEnumMethods() {
@@ -373,10 +379,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
private void generateAccessors() { private void generateAccessors() {
if (context.accessors != null) { for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : context.getAccessors().entrySet()) {
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : context.accessors.entrySet()) { genAccessor(entry);
genAccessor(entry);
}
} }
} }
@@ -551,73 +555,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass); ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass);
CodegenContexts.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper); final CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor);
JvmMethodSignature constructorMethod; lookupConstructorExpressionsInClosureIfPresent(constructorContext);
CallableMethod callableMethod;
boolean hasThis0 = typeMapper.hasThis0(descriptor);
if (constructorDescriptor == null) {
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false);
signatureWriter.writeFormalTypeParametersStart(); MutableClosure closure = context.closure;
signatureWriter.writeFormalTypeParametersEnd(); boolean hasThis0 = closure != null && closure.getCaptureThis() != null;
signatureWriter.writeParametersStart(); final CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure);
final JvmMethodSignature constructorMethod = callableMethod.getSignature();
if (hasThis0) {
signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0);
typeMapper
.mapType(typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor).getDefaultType(), signatureWriter,
MapTypeMode.VALUE);
signatureWriter.writeParameterTypeEnd();
}
signatureWriter.writeParametersEnd();
signatureWriter.writeVoidReturn();
constructorMethod = signatureWriter.makeJvmMethodSignature("<init>");
callableMethod =
new CallableMethod(JvmClassName.byInternalName("Ignored"), null, null, constructorMethod, INVOKESPECIAL, null, null,
null);
}
else {
callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor,
typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
constructorMethod = callableMethod.getSignature();
}
lookupDelegateExpressionInClosureIfPresent();
ObjectOrClosureCodegen closure = context.closure;
int firstSuperArgument = -1;
final List<JvmMethodParameterSignature> consArgTypes =
new LinkedList<JvmMethodParameterSignature>(constructorMethod.getKotlinParameterTypes());
int insert = addClosureToConstructorParameters(hasThis0, closure, consArgTypes);
if (myClass instanceof JetObjectDeclaration && ((JetObjectDeclaration) myClass).isObjectLiteral()) {
if (superCall instanceof JetDelegatorToSuperCall) {
if (closure != null) {
closure.superCall = (JetDelegatorToSuperCall) superCall;
}
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET,
((JetDelegatorToSuperCall) superCall).getCalleeExpression()
.getConstructorReferenceExpression());
if (declarationDescriptor instanceof ClassDescriptorFromSource) {
declarationDescriptor = ((ClassDescriptorFromSource) declarationDescriptor).getUnsubstitutedPrimaryConstructor();
}
ConstructorDescriptor superConstructor = (ConstructorDescriptor) declarationDescriptor;
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, typeMapper
.hasThis0(superConstructor.getContainingDeclaration()));
firstSuperArgument = insert;
for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) {
consArgTypes.add(insert++, new JvmMethodParameterSignature(t, "", JvmMethodParameterKind.SHARED_VAR));
}
}
constructorMethod = JvmMethodSignature.simple("<init>", Type.VOID_TYPE, consArgTypes);
}
assert constructorDescriptor != null; assert constructorDescriptor != null;
int flags = JetTypeMapper.getAccessModifiers(constructorDescriptor, 0); int flags = JetTypeMapper.getAccessModifiers(constructorDescriptor, 0);
@@ -643,18 +589,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return; return;
} }
generatePrimiryConstructorImpl(constructorDescriptor, constructorContext, constructorMethod, callableMethod, hasThis0, closure, generatePrimiryConstructorImpl(constructorDescriptor, constructorContext, constructorMethod, callableMethod, hasThis0, closure, mv);
firstSuperArgument, mv);
} }
private void generatePrimiryConstructorImpl( private void generatePrimiryConstructorImpl(
ConstructorDescriptor constructorDescriptor, ConstructorDescriptor constructorDescriptor,
CodegenContexts.ConstructorContext constructorContext, CodegenContext.ConstructorContext constructorContext,
JvmMethodSignature constructorMethod, JvmMethodSignature constructorMethod,
CallableMethod callableMethod, CallableMethod callableMethod,
boolean hasThis0, boolean hasThis0,
ObjectOrClosureCodegen closure, MutableClosure closure,
int firstSuperArgument,
MethodVisitor mv MethodVisitor mv
) { ) {
mv.visitCode(); mv.visitCode();
@@ -663,7 +607,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
? constructorDescriptor.getValueParameters() ? constructorDescriptor.getValueParameters()
: Collections.<ValueParameterDescriptor>emptyList(); : Collections.<ValueParameterDescriptor>emptyList();
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, hasThis0); ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor);
final InstructionAdapter iv = new InstructionAdapter(mv); final InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, constructorContext, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, constructorContext, state);
@@ -678,38 +622,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
genSuperCallToDelegatorToSuperClass(iv); genSuperCallToDelegatorToSuperClass(iv);
} }
else { else {
ConstructorDescriptor constructorDescriptor1 = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, frameMap);
((JetDelegatorToSuperCall) superCall)
.getCalleeExpression()
.getConstructorReferenceExpression());
generateDelegatorToConstructorCall(iv, codegen, (JetDelegatorToSuperCall) superCall, constructorDescriptor1, frameMap,
firstSuperArgument);
} }
final ClassDescriptor outerDescriptor = typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor); if (hasThis0) {
final boolean hasOuterThis = typeMapper.hasThis0(descriptor) && outerDescriptor != null; final Type type = typeMapper
if (hasOuterThis) { .mapType(typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor).getDefaultType(), MapTypeMode.VALUE);
final Type type = typeMapper.mapType(outerDescriptor.getDefaultType(), MapTypeMode.VALUE);
String interfaceDesc = type.getDescriptor(); String interfaceDesc = type.getDescriptor();
final String fieldName = "this$0";
v.newField(myClass, ACC_FINAL, fieldName, interfaceDesc, null, null);
iv.load(0, classType); iv.load(0, classType);
iv.load(frameMap.getOuterThisIndex(), type); iv.load(frameMap.getOuterThisIndex(), type);
iv.putfield(classname.getInternalName(), fieldName, interfaceDesc); iv.putfield(classname.getInternalName(), CodegenUtil.THIS$0, interfaceDesc);
} }
if (closure != null) { if (closure != null) {
int k = hasOuterThis ? 2 : 1; int k = hasThis0 ? 2 : 1;
if (closure.captureReceiver != null) { final String internalName = typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName();
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) {
iv.load(0, JetTypeMapper.OBJECT_TYPE); iv.load(0, JetTypeMapper.OBJECT_TYPE);
final Type asmType = typeMapper.mapType(closure.captureReceiver.getDefaultType(), MapTypeMode.IMPL); final Type asmType = typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.IMPL);
iv.load(1, asmType); iv.load(1, asmType);
iv.putfield(typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName(), "receiver$0", iv.putfield(internalName, CodegenUtil.RECEIVER$0, asmType.getDescriptor());
asmType.getDescriptor());
k += asmType.getSize(); k += asmType.getSize();
} }
for (DeclarationDescriptor varDescr : closure.closure.keySet()) { for (DeclarationDescriptor varDescr : closure.getCaptureVariables().keySet()) {
if (varDescr instanceof VariableDescriptor && !(varDescr instanceof PropertyDescriptor)) { if (varDescr instanceof VariableDescriptor && !(varDescr instanceof PropertyDescriptor)) {
Type sharedVarType = typeMapper.getSharedVarType(varDescr); Type sharedVarType = typeMapper.getSharedVarType(varDescr);
if (sharedVarType == null) { if (sharedVarType == null) {
@@ -718,7 +655,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.load(0, JetTypeMapper.OBJECT_TYPE); iv.load(0, JetTypeMapper.OBJECT_TYPE);
iv.load(k, StackValue.refType(sharedVarType)); iv.load(k, StackValue.refType(sharedVarType));
k += StackValue.refType(sharedVarType).getSize(); k += StackValue.refType(sharedVarType).getSize();
iv.putfield(typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName(), iv.putfield(internalName,
"$" + varDescr.getName(), sharedVarType.getDescriptor()); "$" + varDescr.getName(), sharedVarType.getDescriptor());
} }
} }
@@ -847,37 +784,30 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
.getDefaultType(), .getDefaultType(),
MapTypeMode.IMPL) MapTypeMode.IMPL)
.getInternalName()), .getInternalName()),
state.getInjector().getJetTypeMapper()); state);
generateDelegates(superClass, delegateContext, field); generateDelegates(superClass, delegateContext, field);
} }
private int addClosureToConstructorParameters( private int addClosureToConstructorParameters(
boolean hasThis0, MutableClosure closure,
ObjectOrClosureCodegen closure,
List<JvmMethodParameterSignature> consArgTypes List<JvmMethodParameterSignature> consArgTypes
) { ) {
int insert = 0; int insert = 0;
if (closure != null) { if (closure != null) {
if (closure.captureThis != null) { if (closure.getCaptureThis() != null) {
if (!hasThis0) { consArgTypes.add(insert,
consArgTypes.add(insert, new JvmMethodParameterSignature(Type.getObjectType(context.getThisDescriptor().getName().getName()),
new JvmMethodParameterSignature(Type.getObjectType(context.getThisDescriptor().getName().getName()), "", JvmMethodParameterKind.OUTER));
"", JvmMethodParameterKind.THIS0));
}
insert++; insert++;
} }
else {
if (hasThis0) {
insert++;
}
}
if (closure.captureReceiver != null) { final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
final Type asmType = typeMapper.mapType(closure.captureReceiver.getDefaultType(), MapTypeMode.IMPL); if (captureReceiver != null) {
final Type asmType = typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.IMPL);
consArgTypes.add(insert++, new JvmMethodParameterSignature(asmType, "", JvmMethodParameterKind.RECEIVER)); consArgTypes.add(insert++, new JvmMethodParameterSignature(asmType, "", JvmMethodParameterKind.RECEIVER));
} }
for (DeclarationDescriptor descriptor : closure.closure.keySet()) { for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
final Type sharedVarType = typeMapper.getSharedVarType(descriptor); final Type sharedVarType = typeMapper.getSharedVarType(descriptor);
final Type type; final Type type;
@@ -891,30 +821,64 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
consArgTypes.add(insert++, new JvmMethodParameterSignature(type, "", JvmMethodParameterKind.SHARED_VAR)); consArgTypes.add(insert++, new JvmMethodParameterSignature(type, "", JvmMethodParameterKind.SHARED_VAR));
} }
else if (descriptor instanceof FunctionDescriptor) { else if (descriptor instanceof FunctionDescriptor) {
assert closure.captureReceiver != null; assert captureReceiver != null;
} }
} }
} }
return insert; return insert;
} }
private void lookupDelegateExpressionInClosureIfPresent() { private void lookupConstructorExpressionsInClosureIfPresent(final CodegenContext.ConstructorContext constructorContext) {
if (context.closure != null) { final JetVisitorVoid visitor = new JetVisitorVoid() {
for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { @Override
if (specifier != superCall && specifier instanceof JetDelegatorByExpressionSpecifier) { public void visitJetElement(JetElement e) {
e.acceptChildren(this);
}
@Override
public void visitSimpleNameExpression(JetSimpleNameExpression expr) {
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr);
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) constructorContext.getContextDescriptor();
for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
//noinspection ConstantConditions
if (descriptor.equals(parameterDescriptor)) {
return;
}
}
constructorContext.lookupInContext(descriptor, null, state, true);
}
}
};
for (JetDeclaration declaration : myClass.getDeclarations()) {
if (declaration instanceof JetProperty) {
final JetProperty property = (JetProperty) declaration;
final JetExpression initializer = property.getInitializer();
if (initializer != null) {
initializer.accept(visitor);
}
}
else if (declaration instanceof JetClassInitializer) {
final JetClassInitializer initializer = (JetClassInitializer) declaration;
initializer.accept(visitor);
}
}
for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
if (specifier != superCall) {
if (specifier instanceof JetDelegatorByExpressionSpecifier) {
JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
assert delegateExpression != null; assert delegateExpression != null;
delegateExpression.accept(new JetVisitorVoid() { delegateExpression.accept(visitor);
@Override }
public void visitJetElement(JetElement e) { }
e.acceptChildren(this); else {
} if (superCall instanceof JetDelegatorToSuperCall) {
final JetValueArgumentList argumentList = ((JetDelegatorToSuperCall) superCall).getValueArgumentList();
@Override if (argumentList != null) {
public void visitSimpleNameExpression(JetSimpleNameExpression expr) { argumentList.accept(visitor);
context.closure.lookupInContext(bindingContext.get(BindingContext.REFERENCE_TARGET, expr), null); }
}
});
} }
} }
} }
@@ -1059,48 +1023,63 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
private void generateDelegatorToConstructorCall( private void generateDelegatorToConstructorCall(
InstructionAdapter iv, ExpressionCodegen codegen, JetCallElement constructorCall, InstructionAdapter iv, ExpressionCodegen codegen,
ConstructorDescriptor constructorDescriptor, ConstructorDescriptor constructorDescriptor,
ConstructorFrameMap frameMap, int firstSuperArgument ConstructorFrameMap frameMap
) { ) {
ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration(); ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
iv.load(0, OBJECT_TYPE); iv.load(0, OBJECT_TYPE);
if (classDecl.getKind() == ClassKind.ENUM_CLASS || classDecl.getKind() == ClassKind.ENUM_ENTRY) { if (classDecl.getKind() == ClassKind.ENUM_CLASS || classDecl.getKind() == ClassKind.ENUM_ENTRY) {
iv.load(1, JetTypeMapper.OBJECT_TYPE); iv.load(1, OBJECT_TYPE);
iv.load(2, Type.INT_TYPE); iv.load(2, Type.INT_TYPE);
} }
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) { CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure);
iv.load(frameMap.getOuterThisIndex(),
typeMapper.mapType(((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), MapTypeMode.IMPL));
}
CallableMethod method = typeMapper final ResolvedCall<? extends CallableDescriptor> resolvedCall =
.mapToCallableMethod(constructorDescriptor, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration())); bindingContext.get(BindingContext.RESOLVED_CALL, ((JetCallElement) superCall).getCalleeExpression());
assert resolvedCall != null;
final ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
final CalculatedClosure closureForSuper = typeMapper.getCalculatedClosure(superConstructor.getContainingDeclaration());
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor,
closureForSuper);
if (closureForSuper != null && closureForSuper.getCaptureThis() != null) {
iv.load(frameMap.getOuterThisIndex(), OBJECT_TYPE);
}
if (myClass instanceof JetObjectDeclaration && if (myClass instanceof JetObjectDeclaration &&
superCall instanceof JetDelegatorToSuperCall && superCall instanceof JetDelegatorToSuperCall &&
((JetObjectDeclaration) myClass).isObjectLiteral()) { ((JetObjectDeclaration) myClass).isObjectLiteral()) {
ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, int nextVar = findFirstSuperArgument(method);
((JetDelegatorToSuperCall) superCall)
.getCalleeExpression()
.getConstructorReferenceExpression());
assert superConstructor != null;
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor,
typeMapper.hasThis0(superConstructor.getContainingDeclaration()));
int nextVar = firstSuperArgument + 1;
for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) { for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) {
iv.load(nextVar, t); iv.load(nextVar, t);
nextVar += t.getSize(); nextVar += t.getSize();
} }
method.invoke(codegen.v); superCallable.invoke(codegen.v);
} }
else { else {
codegen.invokeMethodWithArguments(method, constructorCall, StackValue.none()); codegen.invokeMethodWithArguments(superCallable, (JetCallElement) superCall, StackValue.none());
} }
} }
private static int findFirstSuperArgument(CallableMethod method) {
final List<JvmMethodParameterSignature> types = method.getSignature().getKotlinParameterTypes();
if (types != null) {
int i = 0;
for (JvmMethodParameterSignature type : types) {
if (type.getKind() == JvmMethodParameterKind.SUPER_CALL_PARAM) {
return i + 1; // because of this
}
i += type.getAsmType().getSize();
}
}
return -1;
}
@Override @Override
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
if (declaration instanceof JetClassObject) { if (declaration instanceof JetClassObject) {
@@ -1171,7 +1150,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
.get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression()); .get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression());
assert constructorDescriptor != null; assert constructorDescriptor != null;
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, typeMapper CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, typeMapper
.hasThis0(constructorDescriptor.getContainingDeclaration())); .getCalculatedClosure(constructorDescriptor.getContainingDeclaration()));
codegen.invokeMethodWithArguments(method, superCall, StackValue.none()); codegen.invokeMethodWithArguments(method, superCall, StackValue.none());
} }
else { else {
@@ -1206,7 +1185,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
Type type = typeMapper.mapType(jetType, MapTypeMode.VALUE); Type type = typeMapper.mapType(jetType, MapTypeMode.VALUE);
if (skipDefaultValue(propertyDescriptor, value, type)) continue; if (skipDefaultValue(propertyDescriptor, value, type)) continue;
} }
iv.load(0, JetTypeMapper.OBJECT_TYPE); iv.load(0, OBJECT_TYPE);
Type type = codegen.expressionType(initializer); Type type = codegen.expressionType(initializer);
if (jetType.isNullable()) { if (jetType.isNullable()) {
type = JetTypeMapper.boxType(type); type = JetTypeMapper.boxType(type);
@@ -21,12 +21,13 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.signature.BothSignatureWriter; import org.jetbrains.jet.codegen.context.CalculatedClosure;
import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; import org.jetbrains.jet.codegen.context.ClosureAnnotator;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; import org.jetbrains.jet.codegen.signature.*;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetClassObject; import org.jetbrains.jet.lang.psi.JetClassObject;
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration; import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -40,10 +41,7 @@ import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
@@ -103,7 +101,12 @@ public class JetTypeMapper {
} }
public boolean hasThis0(ClassDescriptor classDescriptor) { public boolean hasThis0(ClassDescriptor classDescriptor) {
return closureAnnotator.hasThis0(classDescriptor); final CalculatedClosure closure = closureAnnotator.getCalculatedClosure(classDescriptor);
return closure != null && closure.getCaptureThis() != null;
}
public CalculatedClosure getCalculatedClosure(ClassDescriptor classDescriptor) {
return closureAnnotator.getCalculatedClosure(classDescriptor);
} }
public ClosureAnnotator getClosureAnnotator() { public ClosureAnnotator getClosureAnnotator() {
@@ -856,22 +859,27 @@ public class JetTypeMapper {
jvmMethodSignature.getKotlinParameterType(jvmMethodSignature.getParameterCount() - 1)); jvmMethodSignature.getKotlinParameterType(jvmMethodSignature.getParameterCount() - 1));
} }
private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor, boolean hasThis0) { private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor, CalculatedClosure closure) {
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true); BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
List<ValueParameterDescriptor> parameters = descriptor.getOriginal().getValueParameters();
// constructor type parmeters are fake // constructor type parmeters are fake
writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter); writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter);
signatureWriter.writeParametersStart(); signatureWriter.writeParametersStart();
ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration(); ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (hasThis0) { final ClassDescriptor captureThis = closure != null ? closure.getCaptureThis() : null;
signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0); if (captureThis != null) {
mapType(closureAnnotator.getEclosingClassDescriptor(containingDeclaration).getDefaultType(), signatureWriter, signatureWriter.writeParameterType(JvmMethodParameterKind.OUTER);
MapTypeMode.VALUE); mapType(captureThis.getDefaultType(), signatureWriter, MapTypeMode.VALUE);
signatureWriter.writeParameterTypeEnd();
}
final ClassifierDescriptor captureReceiver = closure != null ? closure.getCaptureReceiver() : null;
if (captureReceiver != null) {
signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER);
mapType(captureReceiver.getDefaultType(), signatureWriter, MapTypeMode.VALUE);
signatureWriter.writeParameterTypeEnd(); signatureWriter.writeParameterTypeEnd();
} }
@@ -884,7 +892,46 @@ public class JetTypeMapper {
signatureWriter.writeParameterTypeEnd(); signatureWriter.writeParameterTypeEnd();
} }
for (ValueParameterDescriptor parameter : parameters) { if (closure != null) {
for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
if (entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) {
Type sharedVarType = getSharedVarType(entry.getKey());
if (sharedVarType == null) {
sharedVarType = mapType(((VariableDescriptor) entry.getKey()).getType(), MapTypeMode.VALUE);
}
signatureWriter.writeParameterType(JvmMethodParameterKind.SHARED_VAR);
signatureWriter.writeAsmType(sharedVarType, false);
signatureWriter.writeParameterTypeEnd();
}
}
final JetDelegatorToSuperCall superCall = closure.getSuperCall();
if (superCall != null) {
DeclarationDescriptor superDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET,
superCall
.getCalleeExpression()
.getConstructorReferenceExpression());
if(superDescriptor instanceof ConstructorDescriptor) {
final ConstructorDescriptor superConstructor = (ConstructorDescriptor) superDescriptor;
if (CodegenUtil.isObjectLiteral(descriptor.getContainingDeclaration(), bindingContext)) {
CallableMethod superCallable = mapToCallableMethod(superConstructor,
getCalculatedClosure(superConstructor.getContainingDeclaration()));
final List<JvmMethodParameterSignature> types = superCallable.getSignature().getKotlinParameterTypes();
if (types != null) {
for (JvmMethodParameterSignature type : types) {
signatureWriter.writeParameterType(JvmMethodParameterKind.SUPER_CALL_PARAM);
signatureWriter.writeAsmType(type.getAsmType(), false);
signatureWriter.writeParameterTypeEnd();
}
}
}
}
}
}
for (ValueParameterDescriptor parameter : descriptor.getOriginal().getValueParameters()) {
signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE); signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE);
mapType(parameter.getType(), signatureWriter, MapTypeMode.VALUE); mapType(parameter.getType(), signatureWriter, MapTypeMode.VALUE);
signatureWriter.writeParameterTypeEnd(); signatureWriter.writeParameterTypeEnd();
@@ -925,8 +972,8 @@ public class JetTypeMapper {
return signatureWriter.makeJvmMethodSignature("<init>"); return signatureWriter.makeJvmMethodSignature("<init>");
} }
public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, boolean hasThis0) { public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, CalculatedClosure closure) {
final JvmMethodSignature method = mapConstructorSignature(descriptor, hasThis0); final JvmMethodSignature method = mapConstructorSignature(descriptor, closure);
JetType defaultType = descriptor.getContainingDeclaration().getDefaultType(); JetType defaultType = descriptor.getContainingDeclaration().getDefaultType();
Type mapped = mapType(defaultType, MapTypeMode.IMPL); Type mapped = mapType(defaultType, MapTypeMode.IMPL);
if (mapped.getSort() != Type.OBJECT) { if (mapped.getSort() != Type.OBJECT) {
@@ -999,4 +1046,23 @@ public class JetTypeMapper {
return Boolean.TRUE.equals(bindingContext.get(BindingContext.CAPTURED_IN_CLOSURE, variableDescriptor)) && return Boolean.TRUE.equals(bindingContext.get(BindingContext.CAPTURED_IN_CLOSURE, variableDescriptor)) &&
variableDescriptor.isVar(); variableDescriptor.isVar();
} }
protected JvmMethodSignature invokeSignature(FunctionDescriptor fd) {
return mapSignature(Name.identifier("invoke"), fd);
}
public CallableMethod asCallableMethod(FunctionDescriptor fd) {
JvmMethodSignature descriptor = CodegenUtil.erasedInvokeSignature(fd);
JvmClassName owner = CodegenUtil.getInternalClassName(fd);
Type receiverParameterType;
if (fd.getReceiverParameter().exists()) {
receiverParameterType = mapType(fd.getOriginal().getReceiverParameter().getType(), MapTypeMode.VALUE);
}
else {
receiverParameterType = null;
}
return new CallableMethod(
owner, null, null, descriptor, INVOKEVIRTUAL,
CodegenUtil.getInternalClassName(fd), receiverParameterType, CodegenUtil.getInternalClassName(fd).getAsmType());
}
} }
@@ -1,35 +0,0 @@
/*
* Copyright 2010-2012 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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
/**
* @author alex.tkachman
*/
public class LocalClassClosureCodegen extends ObjectOrClosureCodegen {
public LocalClassClosureCodegen(
ExpressionCodegen exprContext,
CodegenContext context,
@NotNull GenerationState state,
ClassDescriptor descriptor
) {
super(exprContext, context, state);
state.getInjector().getClosureAnnotator().recordLocalClass(descriptor, this);
}
}
@@ -17,6 +17,7 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner; import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner;
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
@@ -122,19 +123,19 @@ public class NamespaceCodegen {
NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file);
for (JetDeclaration declaration : file.getDeclarations()) { for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper()); final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
state.getInjector().getMemberCodegen().generateFunctionOrProperty( state.getInjector().getMemberCodegen().generateFunctionOrProperty(
(JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); (JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
} }
else if (declaration instanceof JetNamedFunction) { else if (declaration instanceof JetNamedFunction) {
if (!multiFile) { if (!multiFile) {
final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper()); final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
state.getInjector().getMemberCodegen().generateFunctionOrProperty( state.getInjector().getMemberCodegen().generateFunctionOrProperty(
(JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); (JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
} }
} }
else if (declaration instanceof JetClassOrObject) { else if (declaration instanceof JetClassOrObject) {
final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper()); final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
state.getInjector().getClassCodegen().generate(context, (JetClassOrObject) declaration); state.getInjector().getClassCodegen().generate(context, (JetClassOrObject) declaration);
} }
else if (declaration instanceof JetScript) { else if (declaration instanceof JetScript) {
@@ -170,13 +171,13 @@ public class NamespaceCodegen {
if (declaration instanceof JetNamedFunction) { if (declaration instanceof JetNamedFunction) {
{ {
final CodegenContext context = final CodegenContext context =
CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper()); CodegenContext.STATIC.intoNamespace(descriptor);
state.getInjector().getMemberCodegen() state.getInjector().getMemberCodegen()
.generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, builder); .generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, builder);
} }
{ {
final CodegenContext context = final CodegenContext context =
CodegenContexts.STATIC.intoNamespacePart(className, descriptor, state.getInjector().getJetTypeMapper()); CodegenContext.STATIC.intoNamespacePart(className, descriptor);
state.getInjector().getMemberCodegen() state.getInjector().getMemberCodegen()
.generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); .generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
} }
@@ -232,7 +233,7 @@ public class NamespaceCodegen {
mv.visitCode(); mv.visitCode();
FrameMap frameMap = new FrameMap(); FrameMap frameMap = new FrameMap();
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContext.STATIC, state);
for (JetFile file : files) { for (JetFile file : files) {
for (JetDeclaration declaration : file.getDeclarations()) { for (JetDeclaration declaration : file.getDeclarations()) {
@@ -1,144 +0,0 @@
/*
* Copyright 2010-2012 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;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author alex.tkachman
*/
public class ObjectOrClosureCodegen {
protected ClassDescriptor captureThis;
protected ClassifierDescriptor captureReceiver;
public final GenerationState state;
private final ExpressionCodegen exprContext;
protected final CodegenContext context;
protected ClassBuilder cv = null;
public JvmClassName name = null;
protected final Map<DeclarationDescriptor, EnclosedValueDescriptor> closure =
new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
public JetDelegatorToSuperCall superCall;
public ObjectOrClosureCodegen(ExpressionCodegen exprContext, CodegenContext context, GenerationState state) {
this.exprContext = exprContext;
this.context = context;
this.state = state;
}
public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result) {
EnclosedValueDescriptor answer = closure.get(d);
if (answer != null) {
StackValue innerValue = answer.getInnerValue();
return result != null ? innerValue : StackValue.composed(result, innerValue);
}
if (d instanceof VariableDescriptor && !(d instanceof PropertyDescriptor)) {
VariableDescriptor vd = (VariableDescriptor) d;
final int idx = exprContext.lookupLocal(vd);
if (idx < 0) return null;
final Type sharedVarType = state.getInjector().getJetTypeMapper().getSharedVarType(vd);
Type localType = state.getInjector().getJetTypeMapper().mapType(vd.getType(), MapTypeMode.VALUE);
final Type type = sharedVarType != null ? sharedVarType : localType;
StackValue outerValue = StackValue.local(idx, type);
final String fieldName = "$" + vd.getName();
StackValue innerValue = sharedVarType != null
? StackValue.fieldForSharedVar(localType, name, fieldName)
: StackValue.field(type, name, fieldName, false);
cv.newField(null, Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null);
answer = new EnclosedValueDescriptor(d, innerValue, outerValue);
closure.put(d, answer);
return innerValue;
}
if (CodegenUtil.isNamedFun(d, state.getBindingContext()) && d.getContainingDeclaration() instanceof FunctionDescriptor) {
FunctionDescriptor vd = (FunctionDescriptor) d;
final int idx = exprContext.lookupLocal(vd);
if (idx < 0) return null;
JetElement expression = (JetElement) BindingContextUtils.callableDescriptorToDeclaration(state.getBindingContext(), vd);
JvmClassName cn = state.getInjector().getJetTypeMapper().getClosureAnnotator().classNameForAnonymousClass(expression);
Type localType = cn.getAsmType();
StackValue outerValue = StackValue.local(idx, localType);
final String fieldName = "$" + vd.getName();
StackValue innerValue = StackValue.field(localType, name, fieldName, false);
cv.newField(null, Opcodes.ACC_PUBLIC, fieldName, localType.getDescriptor(), null, null);
answer = new EnclosedValueDescriptor(d, innerValue, outerValue);
closure.put(d, answer);
return innerValue;
}
if (d instanceof FunctionDescriptor) {
// we are looking for receiver
FunctionDescriptor fd = (FunctionDescriptor) d;
// we generate method
assert context instanceof CodegenContexts.ReceiverContext;
CodegenContexts.ReceiverContext fcontext = (CodegenContexts.ReceiverContext) context;
if (fcontext.getReceiverDescriptor() != fd) {
return null;
}
Type type = state.getInjector().getJetTypeMapper()
.mapType(fcontext.getReceiverDescriptor().getReceiverParameter().getType(), MapTypeMode.VALUE);
boolean isStatic = fcontext.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor;
StackValue outerValue = StackValue.local(isStatic ? 0 : 1, type);
final String fieldName = "receiver$0";
StackValue innerValue = StackValue.field(type, name, fieldName, false);
cv.newField(null, Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null);
answer = new EnclosedValueDescriptor(d, innerValue, outerValue);
closure.put(d, answer);
assert captureReceiver == null;
captureReceiver =
fcontext.getReceiverDescriptor().getReceiverParameter().getType().getConstructor().getDeclarationDescriptor();
return innerValue;
}
return null;
}
public boolean isConst() {
return captureThis == null && captureReceiver == null && closure.isEmpty();
}
}
@@ -24,6 +24,7 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature;
import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
@@ -23,6 +23,8 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.context.ClosureAnnotator;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
@@ -99,9 +101,9 @@ public class ScriptCodegen {
assert scriptDescriptor != null; assert scriptDescriptor != null;
ClassDescriptor classDescriptorForScript = closureAnnotator.classDescriptorForScriptDescriptor(scriptDescriptor); ClassDescriptor classDescriptorForScript = closureAnnotator.classDescriptorForScriptDescriptor(scriptDescriptor);
CodegenContexts.ScriptContext context = CodegenContext.ScriptContext context =
(CodegenContexts.ScriptContext) CodegenContexts.STATIC (CodegenContext.ScriptContext) CodegenContext.STATIC
.intoScript(scriptDescriptor, classDescriptorForScript, state.getInjector().getJetTypeMapper()); .intoScript(scriptDescriptor, classDescriptorForScript);
JvmClassName className = closureAnnotator.classNameForClassDescriptor(classDescriptorForScript); JvmClassName className = closureAnnotator.classNameForClassDescriptor(classDescriptorForScript);
@@ -117,7 +119,7 @@ public class ScriptCodegen {
genMembers(scriptDeclaration, context, classBuilder); genMembers(scriptDeclaration, context, classBuilder);
genFieldsForParameters(scriptDescriptor, classBuilder); genFieldsForParameters(scriptDescriptor, classBuilder);
genConstructor(scriptDeclaration, scriptDescriptor, classDescriptorForScript, classBuilder, genConstructor(scriptDeclaration, scriptDescriptor, classDescriptorForScript, classBuilder,
context.intoFunction(scriptDescriptor.getScriptCodeDescriptor(), state.getInjector().getJetTypeMapper()), context.intoFunction(scriptDescriptor.getScriptCodeDescriptor()),
earlierScripts); earlierScripts);
classBuilder.done(); classBuilder.done();
@@ -17,6 +17,7 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Opcodes;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.psi.JetClassOrObject; import org.jetbrains.jet.lang.psi.JetClassOrObject;
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2012 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.context;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import java.util.List;
import java.util.Map;
/**
* @author alex.tkachman
*/
public interface CalculatedClosure {
@Nullable
ClassDescriptor getEnclosingClass();
@NotNull
JvmClassName getClassName();
@Nullable
JetDelegatorToSuperCall getSuperCall();
@Nullable
ClassDescriptor getCaptureThis();
@Nullable
ClassifierDescriptor getCaptureReceiver();
@NotNull
Map<DeclarationDescriptor, EnclosedValueDescriptor> getCaptureVariables();
@NotNull
List<Pair<String, Type>> getRecordedFields();
}
@@ -14,14 +14,17 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen.context;
import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
@@ -36,15 +39,11 @@ import java.util.*;
* @author alex.tkachman * @author alex.tkachman
*/ */
public class ClosureAnnotator { public class ClosureAnnotator {
private final Map<ClassDescriptor, JvmClassName> classNamesForClassDescriptor = new HashMap<ClassDescriptor, JvmClassName>(); private final Map<ClassDescriptor, CalculatedClosure> closuresForClassDescriptor = new HashMap<ClassDescriptor, CalculatedClosure>();
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
private final Map<ScriptDescriptor, JvmClassName> classNameForScript = new HashMap<ScriptDescriptor, JvmClassName>(); private final Map<ScriptDescriptor, JvmClassName> classNameForScript = new HashMap<ScriptDescriptor, JvmClassName>();
private final Map<ClassDescriptor, LocalClassClosureCodegen> localClassCodegenForClass =
new HashMap<ClassDescriptor, LocalClassClosureCodegen>();
private final Set<JvmClassName> scriptClassNames = new HashSet<JvmClassName>(); private final Set<JvmClassName> scriptClassNames = new HashSet<JvmClassName>();
private final Map<DeclarationDescriptor, ClassDescriptorImpl> classesForFunctions = private final Map<DeclarationDescriptor, ClassDescriptorImpl> classesForFunctions =
new HashMap<DeclarationDescriptor, ClassDescriptorImpl>(); new HashMap<DeclarationDescriptor, ClassDescriptorImpl>();
private final Map<DeclarationDescriptor, ClassDescriptor> enclosing = new HashMap<DeclarationDescriptor, ClassDescriptor>();
private final MultiMap<FqName, JetFile> namespaceName2MultiNamespaceFiles = MultiMap.create(); private final MultiMap<FqName, JetFile> namespaceName2MultiNamespaceFiles = MultiMap.create();
private final MultiMap<FqName, JetFile> namespaceName2Files = MultiMap.create(); private final MultiMap<FqName, JetFile> namespaceName2Files = MultiMap.create();
@@ -76,7 +75,7 @@ public class ClosureAnnotator {
int arity = funDescriptor.getValueParameters().size(); int arity = funDescriptor.getValueParameters().size();
classDescriptor = new ClassDescriptorImpl( classDescriptor = new ClassDescriptorImpl(
funDescriptor, funDescriptor.getContainingDeclaration(),
Collections.<AnnotationDescriptor>emptyList(), Collections.<AnnotationDescriptor>emptyList(),
Modality.FINAL, Modality.FINAL,
Name.special("<closure>")); Name.special("<closure>"));
@@ -107,7 +106,6 @@ public class ClosureAnnotator {
Collections.<AnnotationDescriptor>emptyList(), Collections.<AnnotationDescriptor>emptyList(),
Modality.FINAL, Modality.FINAL,
Name.special("<script-" + className + ">")); Name.special("<script-" + className + ">"));
recordName(classDescriptor, className);
classDescriptor.initialize( classDescriptor.initialize(
false, false,
Collections.<TypeParameterDescriptor>emptyList(), Collections.<TypeParameterDescriptor>emptyList(),
@@ -116,6 +114,8 @@ public class ClosureAnnotator {
Collections.<ConstructorDescriptor>emptySet(), Collections.<ConstructorDescriptor>emptySet(),
null); null);
recordClosure(null, classDescriptor, null, className, false);
ClassDescriptorImpl oldDescriptor = classesForFunctions.put(scriptDescriptor, classDescriptor); ClassDescriptorImpl oldDescriptor = classesForFunctions.put(scriptDescriptor, classDescriptor);
if (oldDescriptor != null) { if (oldDescriptor != null) {
throw new IllegalStateException("Rewrite at key " + scriptDescriptor + " for class"); throw new IllegalStateException("Rewrite at key " + scriptDescriptor + " for class");
@@ -150,7 +150,8 @@ public class ClosureAnnotator {
@NotNull @NotNull
public JvmClassName classNameForScriptDescriptor(@NotNull ScriptDescriptor scriptDescriptor) { public JvmClassName classNameForScriptDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
return classNameForClassDescriptor(classDescriptorForScriptDescriptor(scriptDescriptor)); final ClassDescriptor classDescriptor = classDescriptorForScriptDescriptor(scriptDescriptor);
return closuresForClassDescriptor.get(classDescriptor).getClassName();
} }
private void mapFilesToNamespaces(Collection<JetFile> files) { private void mapFilesToNamespaces(Collection<JetFile> files) {
@@ -213,65 +214,90 @@ public class ClosureAnnotator {
return classNameForClassDescriptor(descriptor); return classNameForClassDescriptor(descriptor);
} }
public ClassDescriptor getEclosingClassDescriptor(ClassDescriptor descriptor) { public JvmClassName classNameForClassDescriptor(ClassDescriptor descriptor) {
return enclosing.get(descriptor); final CalculatedClosure closure = closuresForClassDescriptor.get(descriptor);
return closure == null ? null : closure.getClassName();
} }
public boolean hasThis0(ClassDescriptor classDescriptor) { public ClassDescriptor getEclosingClassDescriptor(ClassDescriptor descriptor) {
if (classDescriptor.getKind() == ClassKind.ENUM_CLASS final CalculatedClosure closure = closuresForClassDescriptor.get(descriptor);
|| classDescriptor.getKind() == ClassKind.ENUM_ENTRY return closure == null ? null : closure.getEnclosingClass();
|| classDescriptor.getKind() == ClassKind.CLASS_OBJECT) { }
public boolean canHaveOuter(ClassDescriptor classDescriptor) {
if (DescriptorUtils.isClassObject(classDescriptor)) {
return false;
}
if (classDescriptor.getKind() == ClassKind.ENUM_CLASS || classDescriptor.getKind() == ClassKind.ENUM_ENTRY) {
return false; return false;
} }
ClassDescriptor other = enclosing.get(classDescriptor); return getEclosingClassDescriptor(classDescriptor) != null;
return other != null;
} }
public boolean enumEntryNeedSubclass(JetEnumEntry enumEntry) { public boolean enumEntryNeedSubclass(JetEnumEntry enumEntry) {
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, enumEntry); return Boolean.TRUE.equals(enumEntryNeedSubclass.get(bindingContext.get(BindingContext.CLASS, enumEntry)));
return enumEntryNeedSubclass.get(descriptor);
} }
public boolean enumEntryNeedSubclass(ClassDescriptor enumEntry) { public boolean enumEntryNeedSubclass(ClassDescriptor enumEntry) {
Boolean aBoolean = enumEntryNeedSubclass.get(enumEntry); return Boolean.TRUE.equals(enumEntryNeedSubclass.get(enumEntry));
return aBoolean != null && aBoolean;
} }
public void recordLocalClass(ClassDescriptor descriptor, LocalClassClosureCodegen codegen) { public CalculatedClosure getCalculatedClosure(@NotNull ClassDescriptor descriptor) {
LocalClassClosureCodegen put = localClassCodegenForClass.put(descriptor, codegen); //noinspection SuspiciousMethodCalls
assert put == null; return closuresForClassDescriptor.get(descriptor.getOriginal());
} }
private class MyJetVisitorVoid extends JetVisitorVoid { private void recordClosure(
private final LinkedList<ClassDescriptor> classStack = new LinkedList<ClassDescriptor>(); @Nullable JetElement element,
private final LinkedList<String> nameStack = new LinkedList<String>(); ClassDescriptor classDescriptor,
@Nullable ClassDescriptor enclosing,
JvmClassName name,
boolean functionLiteral
) {
final JetDelegatorToSuperCall superCall = CodegenUtil.findSuperCall(element, bindingContext);
private void recordEnclosing(ClassDescriptor classDescriptor) { CallableDescriptor enclosingReceiver = null;
if (classStack.size() > 0) { if (classDescriptor.getContainingDeclaration() instanceof CallableDescriptor) {
ClassDescriptor put = enclosing.put(classDescriptor, classStack.peek()); enclosingReceiver = (CallableDescriptor) classDescriptor.getContainingDeclaration();
assert put == null; enclosingReceiver = enclosingReceiver instanceof PropertyAccessorDescriptor
? ((PropertyAccessorDescriptor) enclosingReceiver).getCorrespondingProperty()
: enclosingReceiver;
if (!enclosingReceiver.getReceiverParameter().exists()) {
enclosingReceiver = null;
} }
} }
private JvmClassName recordAnonymousClass(JetElement declaration) { final MutableClosure closure = new MutableClosure(superCall, enclosing, name, enclosingReceiver);
final CalculatedClosure old = closuresForClassDescriptor.put(classDescriptor, closure);
assert old == null;
// TODO: this is temporary before we have proper inner classes
if (canHaveOuter(classDescriptor) && !functionLiteral) {
closure.setCaptureThis();
}
}
private class MyJetVisitorVoid extends JetVisitorVoid {
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
private final LinkedList<ClassDescriptor> classStack = new LinkedList<ClassDescriptor>();
private final LinkedList<String> nameStack = new LinkedList<String>();
private String inventAnonymousClassName(JetElement declaration) {
String top = nameStack.peek(); String top = nameStack.peek();
Integer cnt = anonymousSubclassesCount.get(top); Integer cnt = anonymousSubclassesCount.get(top);
if (cnt == null) { if (cnt == null) {
cnt = 0; cnt = 0;
} }
JvmClassName name = JvmClassName.byInternalName(top + "$" + (cnt + 1)); String name = top + "$" + (cnt + 1);
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, declaration); ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, declaration);
if (descriptor == null) { if (descriptor == null) {
if (declaration instanceof JetFunctionLiteralExpression || declaration instanceof JetNamedFunction) { if (declaration instanceof JetFunctionLiteralExpression ||
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.FUNCTION, declaration); declaration instanceof JetNamedFunction ||
assert declarationDescriptor instanceof FunctionDescriptor; declaration instanceof JetObjectLiteralExpression) {
descriptor = classDescriptorForFunctionDescriptor((FunctionDescriptor) declarationDescriptor);
}
else if (declaration instanceof JetObjectLiteralExpression) {
descriptor =
bindingContext.get(BindingContext.CLASS, ((JetObjectLiteralExpression) declaration).getObjectDeclaration());
assert descriptor != null;
} }
else { else {
throw new IllegalStateException( throw new IllegalStateException(
@@ -279,20 +305,11 @@ public class ClosureAnnotator {
declaration.getClass().getName()); declaration.getClass().getName());
} }
} }
recordName(descriptor, name);
anonymousSubclassesCount.put(top, cnt + 1); anonymousSubclassesCount.put(top, cnt + 1);
return name; return name;
} }
private JvmClassName recordClassObject(JetClassObject declaration) {
JvmClassName name = JvmClassName.byInternalName(nameStack.peek() + JvmAbi.CLASS_OBJECT_SUFFIX);
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, declaration.getObjectDeclaration());
assert classDescriptor != null;
recordName(classDescriptor, name);
return name;
}
@Override @Override
public void visitJetElement(JetElement element) { public void visitJetElement(JetElement element) {
super.visitJetElement(element); super.visitJetElement(element);
@@ -302,6 +319,8 @@ public class ClosureAnnotator {
@Override @Override
public void visitJetFile(JetFile file) { public void visitJetFile(JetFile file) {
if (file.isScript()) { if (file.isScript()) {
//noinspection ConstantConditions
classStack.push(classDescriptorForScriptDescriptor(bindingContext.get(BindingContext.SCRIPT, file.getScript())));
//noinspection ConstantConditions //noinspection ConstantConditions
nameStack.push(classNameForScriptPsi(file.getScript()).getInternalName()); nameStack.push(classNameForScriptPsi(file.getScript()).getInternalName());
} }
@@ -310,21 +329,39 @@ public class ClosureAnnotator {
} }
file.acceptChildren(this); file.acceptChildren(this);
nameStack.pop(); nameStack.pop();
if (file.isScript()) {
classStack.pop();
}
} }
@Override @Override
public void visitEnumEntry(JetEnumEntry enumEntry) { public void visitEnumEntry(JetEnumEntry enumEntry) {
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, enumEntry); ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, enumEntry);
enumEntryNeedSubclass.put(descriptor, !enumEntry.getDeclarations().isEmpty()); assert descriptor != null;
super.visitEnumEntry(enumEntry);
final boolean trivial = enumEntry.getDeclarations().isEmpty();
if (!trivial) {
enumEntryNeedSubclass.put(descriptor, Boolean.TRUE);
classStack.push(descriptor);
nameStack.push(nameStack.peek() + "$" + descriptor.getName().getName());
super.visitEnumEntry(enumEntry);
nameStack.pop();
classStack.pop();
}
else {
super.visitEnumEntry(enumEntry);
}
} }
@Override @Override
public void visitClassObject(JetClassObject classObject) { public void visitClassObject(JetClassObject classObject) {
JvmClassName name = recordClassObject(classObject);
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration()); ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration());
assert classDescriptor != null; assert classDescriptor != null;
recordEnclosing(classDescriptor);
JvmClassName name = JvmClassName.byInternalName(nameStack.peek() + JvmAbi.CLASS_OBJECT_SUFFIX);
recordClosure(classObject, classDescriptor, classStack.peek(), name, false);
classStack.push(classDescriptor); classStack.push(classDescriptor);
nameStack.push(name.getInternalName()); nameStack.push(name.getInternalName());
super.visitClassObject(classObject); super.visitClassObject(classObject);
@@ -341,16 +378,12 @@ public class ClosureAnnotator {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, declaration); ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, declaration);
// working around a problem with shallow analysis // working around a problem with shallow analysis
if (classDescriptor == null) return; if (classDescriptor == null) return;
recordEnclosing(classDescriptor);
String name = getName(classDescriptor);
recordClosure(declaration, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), false);
classStack.push(classDescriptor); classStack.push(classDescriptor);
String base = nameStack.peek(); nameStack.push(name);
if (classDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
nameStack.push(base.isEmpty() ? classDescriptor.getName().getName() : base + '/' + classDescriptor.getName());
}
else {
nameStack.push(base + '$' + classDescriptor.getName());
}
recordName(classDescriptor, JvmClassName.byInternalName(nameStack.peek()));
super.visitObjectDeclaration(declaration); super.visitObjectDeclaration(declaration);
nameStack.pop(); nameStack.pop();
classStack.pop(); classStack.pop();
@@ -362,21 +395,23 @@ public class ClosureAnnotator {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, klass); ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, klass);
// working around a problem with shallow analysis // working around a problem with shallow analysis
if (classDescriptor == null) return; if (classDescriptor == null) return;
recordEnclosing(classDescriptor);
String name = getName(classDescriptor);
recordClosure(klass, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), false);
classStack.push(classDescriptor); classStack.push(classDescriptor);
String base = nameStack.peek(); nameStack.push(name);
if (classDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
nameStack.push(base.isEmpty() ? classDescriptor.getName().getName() : base + '/' + classDescriptor.getName());
}
else {
nameStack.push(base + '$' + classDescriptor.getName());
}
recordName(classDescriptor, JvmClassName.byInternalName(nameStack.peek()));
super.visitClass(klass); super.visitClass(klass);
nameStack.pop(); nameStack.pop();
classStack.pop(); classStack.pop();
} }
private String getName(ClassDescriptor classDescriptor) {
String base = nameStack.peek();
return classDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor ? base.isEmpty() ? classDescriptor.getName()
.getName() : base + '/' + classDescriptor.getName() : base + '$' + classDescriptor.getName();
}
@Override @Override
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) { public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, expression.getObjectDeclaration()); ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, expression.getObjectDeclaration());
@@ -385,8 +420,10 @@ public class ClosureAnnotator {
super.visitObjectLiteralExpression(expression); super.visitObjectLiteralExpression(expression);
return; return;
} }
recordAnonymousClass(expression.getObjectDeclaration());
recordEnclosing(classDescriptor); final String name = inventAnonymousClassName(expression.getObjectDeclaration());
recordClosure(expression.getObjectDeclaration(), classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), false);
classStack.push(classDescriptor); classStack.push(classDescriptor);
nameStack.push(classNameForClassDescriptor(classDescriptor).getInternalName()); nameStack.push(classNameForClassDescriptor(classDescriptor).getInternalName());
super.visitObjectLiteralExpression(expression); super.visitObjectLiteralExpression(expression);
@@ -400,11 +437,13 @@ public class ClosureAnnotator {
(FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression); (FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression);
// working around a problem with shallow analysis // working around a problem with shallow analysis
if (functionDescriptor == null) return; if (functionDescriptor == null) return;
JvmClassName name = recordAnonymousClass(expression);
String name = inventAnonymousClassName(expression);
ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor); ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor);
recordEnclosing(classDescriptor); recordClosure(expression, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), true);
classStack.push(classDescriptor); classStack.push(classDescriptor);
nameStack.push(name.getInternalName()); nameStack.push(name);
super.visitFunctionLiteralExpression(expression); super.visitFunctionLiteralExpression(expression);
nameStack.pop(); nameStack.pop();
classStack.pop(); classStack.pop();
@@ -442,26 +481,16 @@ public class ClosureAnnotator {
nameStack.pop(); nameStack.pop();
} }
else { else {
JvmClassName name = recordAnonymousClass(function); String name = inventAnonymousClassName(function);
ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor); ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor);
recordEnclosing(classDescriptor); recordClosure(function, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), true);
classStack.push(classDescriptor); classStack.push(classDescriptor);
nameStack.push(name.getInternalName()); nameStack.push(name);
super.visitNamedFunction(function); super.visitNamedFunction(function);
nameStack.pop(); nameStack.pop();
classStack.pop(); classStack.pop();
} }
} }
} }
private void recordName(@NotNull ClassDescriptor classDescriptor, @NotNull JvmClassName name) {
JvmClassName old = classNamesForClassDescriptor.put(classDescriptor, name);
if (old != null) {
throw new IllegalStateException("rewrite at key " + classDescriptor);
}
}
public JvmClassName classNameForClassDescriptor(@NotNull ClassDescriptor classDescriptor) {
return classNamesForClassDescriptor.get(classDescriptor);
}
} }
@@ -0,0 +1,544 @@
/*
* Copyright 2010-2012 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.context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.jetbrains.jet.codegen.JetTypeMapper.OBJECT_TYPE;
/*
* @author max
* @author alex.tkachman
*/
public abstract class CodegenContext {
public static final CodegenContext STATIC =
new CodegenContext(new FakeDescriptorForStaticContext(), OwnerKind.NAMESPACE, null, null, null, null) {
@Override
public boolean isStatic() {
return true;
}
@Override
public String toString() {
return "ROOT";
}
};
private static final StackValue local1 = StackValue.local(1, OBJECT_TYPE);
@NotNull
private final DeclarationDescriptor contextDescriptor;
private final OwnerKind contextKind;
@Nullable
private final CodegenContext parentContext;
private final ClassDescriptor thisDescriptor;
public final MutableClosure closure;
HashMap<DeclarationDescriptor, DeclarationDescriptor> accessors;
protected StackValue outerExpression;
private final LocalLookup enclosingLocalLookup;
public CodegenContext(
@NotNull DeclarationDescriptor contextDescriptor,
OwnerKind contextKind,
@Nullable CodegenContext parentContext,
@Nullable MutableClosure closure,
@Nullable ClassDescriptor thisDescriptor,
@Nullable LocalLookup expressionCodegen
) {
this.contextDescriptor = contextDescriptor;
this.contextKind = contextKind;
this.parentContext = parentContext;
this.closure = closure;
this.thisDescriptor = thisDescriptor;
this.enclosingLocalLookup = expressionCodegen;
}
@NotNull
public final ClassDescriptor getThisDescriptor() {
if (thisDescriptor == null) {
throw new UnsupportedOperationException();
}
return thisDescriptor;
}
public final boolean hasThisDescriptor() {
return thisDescriptor != null;
}
public DeclarationDescriptor getClassOrNamespaceDescriptor() {
CodegenContext c = this;
while (true) {
assert c != null;
DeclarationDescriptor contextDescriptor = c.getContextDescriptor();
if (!(contextDescriptor instanceof ClassDescriptor) && !(contextDescriptor instanceof NamespaceDescriptor)) {
c = c.getParentContext();
}
else {
return contextDescriptor;
}
}
}
public CallableDescriptor getReceiverDescriptor() {
return null;
}
public StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter) {
if (outerExpression == null) {
if (ignoreNoOuter) {
return null;
}
else {
throw new UnsupportedOperationException();
}
}
closure.setCaptureThis();
return prefix != null ? StackValue.composed(prefix, outerExpression) : outerExpression;
}
@NotNull
public DeclarationDescriptor getContextDescriptor() {
return contextDescriptor;
}
public OwnerKind getContextKind() {
return contextKind;
}
public CodegenContext intoNamespace(NamespaceDescriptor descriptor) {
return new NamespaceContext(descriptor, this, null);
}
public CodegenContext intoNamespacePart(String delegateTo, NamespaceDescriptor descriptor) {
return new NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo));
}
public CodegenContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
return new ClassContext(state.getInjector().getJetTypeMapper(), descriptor, kind, this, null);
}
public CodegenContext intoAnonymousClass(
ClassDescriptor descriptor,
ExpressionCodegen expressionCodegen
) {
final JetTypeMapper typeMapper = expressionCodegen.getState().getInjector().getJetTypeMapper();
return new AnonymousClassContext(typeMapper, descriptor, OwnerKind.IMPLEMENTATION, this,
expressionCodegen);
}
public MethodContext intoFunction(FunctionDescriptor descriptor) {
return new MethodContext(descriptor, getContextKind(), this);
}
public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) {
if (descriptor == null) {
descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.<AnnotationDescriptor>emptyList(), true)
.initialize(Collections.<TypeParameterDescriptor>emptyList(), Collections.<ValueParameterDescriptor>emptyList(),
Visibilities.PUBLIC);
}
return new ConstructorContext(descriptor, getContextKind(), this);
}
public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) {
return new ScriptContext(script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
}
public CodegenContext intoClosure(
FunctionDescriptor funDescriptor,
ExpressionCodegen expressionCodegen
) {
final JetTypeMapper typeMapper = expressionCodegen.getState().getInjector().getJetTypeMapper();
return new ClosureContext(typeMapper, funDescriptor,
typeMapper.getClosureAnnotator().classDescriptorForFunctionDescriptor(funDescriptor),
this, expressionCodegen);
}
public FrameMap prepareFrame(JetTypeMapper mapper) {
FrameMap frameMap = new FrameMap();
if (getContextKind() != OwnerKind.NAMESPACE) {
frameMap.enterTemp(OBJECT_TYPE); // 0 slot for this
}
CallableDescriptor receiverDescriptor = getReceiverDescriptor();
if (receiverDescriptor != null) {
Type type = mapper.mapType(receiverDescriptor.getReceiverParameter().getType(), MapTypeMode.VALUE);
frameMap.enterTemp(type); // Next slot for receiver
}
return frameMap;
}
@Nullable
public CodegenContext getParentContext() {
return parentContext;
}
public ClassDescriptor getEnclosingClass() {
CodegenContext cur = getParentContext();
while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) {
cur = cur.getParentContext();
}
return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor();
}
public DeclarationDescriptor getAccessor(DeclarationDescriptor descriptor) {
if (accessors == null) {
accessors = new HashMap<DeclarationDescriptor, DeclarationDescriptor>();
}
descriptor = descriptor.getOriginal();
DeclarationDescriptor accessor = accessors.get(descriptor);
if (accessor != null) {
return accessor;
}
if (descriptor instanceof SimpleFunctionDescriptor) {
accessor = new AccessorForFunctionDescriptor(descriptor, contextDescriptor, accessors.size());
}
else if (descriptor instanceof PropertyDescriptor) {
accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessors.size());
}
else {
throw new UnsupportedOperationException();
}
accessors.put(descriptor, accessor);
return accessor;
}
public StackValue getReceiverExpression(JetTypeMapper typeMapper) {
assert getReceiverDescriptor() != null;
Type asmType = typeMapper.mapType(getReceiverDescriptor().getReceiverParameter().getType(), MapTypeMode.VALUE);
return hasThisDescriptor() ? StackValue.local(1, asmType) : StackValue.local(0, asmType);
}
public abstract boolean isStatic();
public void copyAccessors(Map<DeclarationDescriptor, DeclarationDescriptor> accessors) {
if (accessors != null) {
if (this.accessors == null) {
this.accessors = new HashMap<DeclarationDescriptor, DeclarationDescriptor>();
}
this.accessors.putAll(accessors);
}
}
protected void initOuterExpression(JetTypeMapper typeMapper, ClassDescriptor classDescriptor) {
final ClassDescriptor enclosingClass = getEnclosingClass();
outerExpression = enclosingClass != null
? StackValue
.field(typeMapper.mapType(enclosingClass.getDefaultType(), MapTypeMode.VALUE), typeMapper.getJvmClassName(
classDescriptor), CodegenUtil.THIS$0,
false)
: null;
}
public StackValue lookupInContext(DeclarationDescriptor d, StackValue result, GenerationState state, boolean ignoreNoOuter) {
final MutableClosure top = closure;
if (top != null) {
EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
if (answer != null) {
StackValue innerValue = answer.getInnerValue();
return result == null ? innerValue : StackValue.composed(result, innerValue);
}
for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
if (aCase.isCase(d, state)) {
StackValue innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure);
if (innerValue == null) {
break;
}
else {
return result == null ? innerValue : StackValue.composed(result, innerValue);
}
}
}
StackValue outer = getOuterExpression(null, ignoreNoOuter);
result = result == null ? outer : StackValue.composed(result, outer);
}
return parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
}
@NotNull
public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() {
return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors;
}
private static class FakeDescriptorForStaticContext implements DeclarationDescriptor {
@NotNull
@Override
public DeclarationDescriptor getOriginal() {
throw new IllegalStateException();
}
@Override
public DeclarationDescriptor getContainingDeclaration() {
throw new IllegalStateException();
}
@Override
public DeclarationDescriptor substitute(TypeSubstitutor substitutor) {
throw new IllegalStateException();
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
throw new IllegalStateException();
}
@Override
public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
throw new IllegalStateException();
}
@Override
public List<AnnotationDescriptor> getAnnotations() {
throw new IllegalStateException();
}
@NotNull
@Override
public Name getName() {
throw new IllegalStateException();
}
}
private abstract static class ReceiverContext extends CodegenContext {
final CallableDescriptor receiverDescriptor;
public ReceiverContext(
CallableDescriptor contextDescriptor,
OwnerKind contextKind,
CodegenContext parentContext,
@Nullable MutableClosure closure,
ClassDescriptor thisDescriptor,
@Nullable LocalLookup localLookup
) {
super(contextDescriptor, contextKind, parentContext, closure, thisDescriptor, localLookup);
receiverDescriptor = contextDescriptor.getReceiverParameter().exists() ? contextDescriptor : null;
}
@Override
public CallableDescriptor getReceiverDescriptor() {
return receiverDescriptor;
}
}
public static class MethodContext extends ReceiverContext {
public MethodContext(
@NotNull FunctionDescriptor contextType,
OwnerKind contextKind,
CodegenContext parentContext
) {
super(contextType instanceof PropertyAccessorDescriptor
? ((PropertyAccessorDescriptor) contextType).getCorrespondingProperty()
: contextType, contextKind, parentContext, null,
parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null);
}
@Override
public StackValue lookupInContext(DeclarationDescriptor d, StackValue result, GenerationState state, boolean ignoreNoOuter) {
if (getContextDescriptor() == d) {
return StackValue.local(0, JetTypeMapper.OBJECT_TYPE);
}
//noinspection ConstantConditions
return getParentContext().lookupInContext(d, result, state, ignoreNoOuter);
}
@Override
public boolean isStatic() {
//noinspection ConstantConditions
return getParentContext().isStatic();
}
@Override
public StackValue getOuterExpression(StackValue prefix, boolean ignoreNoOuter) {
//noinspection ConstantConditions
return getParentContext().getOuterExpression(prefix, false);
}
@Override
public String toString() {
return "Method: " + getContextDescriptor();
}
}
public static class ConstructorContext extends MethodContext {
public ConstructorContext(
ConstructorDescriptor contextDescriptor,
OwnerKind kind,
CodegenContext parent
) {
super(contextDescriptor, kind, parent);
final ClassDescriptor type = getEnclosingClass();
outerExpression = type != null ? local1 : null;
}
@Override
public StackValue getOuterExpression(StackValue prefix, boolean ignoreNoOuter) {
return outerExpression;
}
@Override
public String toString() {
return "Constructor: " + getContextDescriptor().getName();
}
}
public static class ScriptContext extends CodegenContext {
@NotNull
private final ScriptDescriptor scriptDescriptor;
public ScriptContext(
@NotNull ScriptDescriptor scriptDescriptor,
@NotNull ClassDescriptor contextDescriptor,
@NotNull OwnerKind contextKind,
@Nullable CodegenContext parentContext,
@Nullable MutableClosure closure
) {
super(contextDescriptor, contextKind, parentContext, closure, contextDescriptor, null);
this.scriptDescriptor = scriptDescriptor;
}
@NotNull
public ScriptDescriptor getScriptDescriptor() {
return scriptDescriptor;
}
@Override
public boolean isStatic() {
return true;
}
}
public static class ClassContext extends CodegenContext {
public ClassContext(
JetTypeMapper typeMapper,
ClassDescriptor contextDescriptor,
OwnerKind contextKind,
CodegenContext parentContext,
LocalLookup localLookup
) {
super(contextDescriptor, contextKind, parentContext, (MutableClosure) typeMapper.getCalculatedClosure(contextDescriptor),
contextDescriptor,
localLookup);
initOuterExpression(typeMapper, contextDescriptor);
}
@Override
public boolean isStatic() {
return false;
}
}
private static class AnonymousClassContext extends CodegenContext {
public AnonymousClassContext(
JetTypeMapper typeMapper,
ClassDescriptor contextDescriptor,
OwnerKind contextKind,
CodegenContext parentContext,
LocalLookup localLookup
) {
super(contextDescriptor, contextKind, parentContext, (MutableClosure) typeMapper.getCalculatedClosure(contextDescriptor),
contextDescriptor,
localLookup);
initOuterExpression(typeMapper, contextDescriptor);
}
@Override
public boolean isStatic() {
return false;
}
@Override
public String toString() {
return "Anonymous: " + getThisDescriptor();
}
}
private static class ClosureContext extends ReceiverContext {
private final ClassDescriptor classDescriptor;
public ClosureContext(
JetTypeMapper typeMapper,
FunctionDescriptor contextDescriptor,
ClassDescriptor classDescriptor,
CodegenContext parentContext,
LocalLookup localLookup
) {
super(contextDescriptor, OwnerKind.IMPLEMENTATION, parentContext,
(MutableClosure) typeMapper.getCalculatedClosure(classDescriptor), classDescriptor, localLookup);
this.classDescriptor = classDescriptor;
initOuterExpression(typeMapper, classDescriptor);
}
@NotNull
@Override
public DeclarationDescriptor getContextDescriptor() {
return classDescriptor;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public String toString() {
return "Closure: " + classDescriptor;
}
}
public static class NamespaceContext extends CodegenContext {
public NamespaceContext(NamespaceDescriptor contextDescriptor, CodegenContext parent, OwnerKind kind) {
super(contextDescriptor, kind != null ? kind : OwnerKind.NAMESPACE, parent, null, null, null);
}
@Override
public boolean isStatic() {
return true;
}
@Override
public String toString() {
return "Namespace: " + getContextDescriptor().getName();
}
}
}
@@ -17,19 +17,23 @@
/* /*
* @author max * @author max
*/ */
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen.context;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
public class EnclosedValueDescriptor { public final class EnclosedValueDescriptor {
private final DeclarationDescriptor descriptor; private final DeclarationDescriptor descriptor;
private final StackValue innerValue; private final StackValue innerValue;
private final StackValue outerValue; private final Type type;
public EnclosedValueDescriptor(DeclarationDescriptor descriptor, StackValue innerValue, StackValue outerValue) { public EnclosedValueDescriptor(DeclarationDescriptor descriptor, StackValue innerValue, Type type) {
this.descriptor = descriptor; this.descriptor = descriptor;
this.innerValue = innerValue; this.innerValue = innerValue;
this.outerValue = outerValue; this.type = type;
} }
public DeclarationDescriptor getDescriptor() { public DeclarationDescriptor getDescriptor() {
@@ -40,7 +44,18 @@ public class EnclosedValueDescriptor {
return innerValue; return innerValue;
} }
public StackValue getOuterValue() { public Type getType() {
return outerValue; return type;
}
public StackValue getOuterValue(ExpressionCodegen expressionCodegen) {
final GenerationState state = expressionCodegen.getState();
for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
if (aCase.isCase(descriptor, state)) {
return aCase.outerValue(this, expressionCodegen);
}
}
throw new IllegalStateException();
} }
} }
@@ -0,0 +1,136 @@
/*
* Copyright 2010-2012 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.context;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.types.JetType;
/**
* @author alex.tkachman
*/
public interface LocalLookup {
boolean lookupLocal(DeclarationDescriptor descriptor);
enum LocalLookupCase {
VAR {
@Override
public boolean isCase(DeclarationDescriptor d, GenerationState state) {
return (d instanceof VariableDescriptor) && !(d instanceof PropertyDescriptor);
}
@Override
public StackValue innerValue(DeclarationDescriptor d, LocalLookup localLookup, GenerationState state, MutableClosure closure) {
VariableDescriptor vd = (VariableDescriptor) d;
final boolean idx = localLookup != null && localLookup.lookupLocal(vd);
if (!idx) return null;
final Type sharedVarType = state.getInjector().getJetTypeMapper().getSharedVarType(vd);
Type localType = state.getInjector().getJetTypeMapper().mapType(vd.getType(), MapTypeMode.VALUE);
final Type type = sharedVarType != null ? sharedVarType : localType;
final String fieldName = "$" + vd.getName();
StackValue innerValue = sharedVarType != null
? StackValue.fieldForSharedVar(localType, closure.getClassName(), fieldName)
: StackValue.field(type, closure.getClassName(), fieldName, false);
closure.recordField(fieldName, type);
closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, type));
return innerValue;
}
},
LOCAL_NAMED_FUNCTION {
@Override
public boolean isCase(DeclarationDescriptor d, GenerationState state) {
return CodegenUtil.isNamedFun(d, state.getBindingContext()) && (d.getContainingDeclaration() instanceof FunctionDescriptor);
}
@Override
public StackValue innerValue(DeclarationDescriptor d, LocalLookup localLookup, GenerationState state, MutableClosure closure) {
FunctionDescriptor vd = (FunctionDescriptor) d;
final boolean idx = localLookup.lookupLocal(vd);
if (!idx) return null;
JetElement expression = (JetElement) BindingContextUtils.callableDescriptorToDeclaration(state.getBindingContext(), vd);
JvmClassName cn = state.getInjector().getJetTypeMapper().getClosureAnnotator().classNameForAnonymousClass(expression);
Type localType = cn.getAsmType();
final String fieldName = "$" + vd.getName();
StackValue innerValue = StackValue.field(localType, closure.getClassName(), fieldName, false);
closure.recordField(fieldName, localType);
closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, localType));
return innerValue;
}
},
RECEIVER {
@Override
public boolean isCase(DeclarationDescriptor d, GenerationState state) {
return d instanceof FunctionDescriptor;
}
@Override
public StackValue innerValue(
DeclarationDescriptor d,
LocalLookup enclosingLocalLookup,
GenerationState state,
MutableClosure closure
) {
if (closure.getEnclosingReceiverDescriptor() != d) return null;
final JetType receiverType = ((CallableDescriptor) d).getReceiverParameter().getType();
Type type = state.getInjector().getJetTypeMapper().mapType(receiverType, MapTypeMode.VALUE);
StackValue innerValue = StackValue.field(type, closure.getClassName(), CodegenUtil.RECEIVER$0, false);
closure.setCaptureReceiver();
return innerValue;
}
@Override
public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
CallableDescriptor descriptor = (FunctionDescriptor) d.getDescriptor();
return StackValue.local(descriptor.getExpectedThisObject().exists() ? 1 : 0, d.getType());
}
};
public abstract boolean isCase(DeclarationDescriptor d, GenerationState state);
public abstract StackValue innerValue(
DeclarationDescriptor d,
LocalLookup localLookup,
GenerationState state,
MutableClosure closure
);
public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) {
final int idx = expressionCodegen.lookupLocalIndex(d.getDescriptor());
assert idx != -1;
return StackValue.local(idx, d.getType());
}
}
}
@@ -0,0 +1,130 @@
/*
* Copyright 2010-2012 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.context;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import java.util.*;
/**
* @author alex.tkachman
*/
public final class MutableClosure implements CalculatedClosure {
private final JetDelegatorToSuperCall superCall;
private final ClassDescriptor enclosingClass;
private final CallableDescriptor enclosingReceiverDescriptor;
private final JvmClassName name;
private boolean captureThis;
private boolean captureReceiver;
private Map<DeclarationDescriptor, EnclosedValueDescriptor> captureVariables;
private List<Pair<String, Type>> recordedFields;
MutableClosure(
JetDelegatorToSuperCall superCall,
ClassDescriptor enclosingClass,
JvmClassName className,
CallableDescriptor enclosingReceiverDescriptor
) {
this.superCall = superCall;
this.enclosingClass = enclosingClass;
this.enclosingReceiverDescriptor = enclosingReceiverDescriptor;
this.name = className;
}
@Nullable
@Override
public ClassDescriptor getEnclosingClass() {
return enclosingClass;
}
@NotNull
@Override
public JvmClassName getClassName() {
return name;
}
@Override
public JetDelegatorToSuperCall getSuperCall() {
return superCall;
}
@Override
public ClassDescriptor getCaptureThis() {
return captureThis ? enclosingClass : null;
}
public void setCaptureThis() {
this.captureThis = true;
}
@Override
public ClassifierDescriptor getCaptureReceiver() {
return captureReceiver
? enclosingReceiverDescriptor.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor()
: null;
}
public void setCaptureReceiver() {
if (enclosingReceiverDescriptor == null) {
throw new IllegalStateException();
}
this.captureReceiver = true;
}
@NotNull
@Override
public Map<DeclarationDescriptor, EnclosedValueDescriptor> getCaptureVariables() {
return captureVariables != null ? captureVariables : Collections.<DeclarationDescriptor, EnclosedValueDescriptor>emptyMap();
}
@NotNull
@Override
public List<Pair<String, Type>> getRecordedFields() {
return recordedFields != null ? recordedFields : Collections.<Pair<String, Type>>emptyList();
}
public void recordField(String name, Type type) {
if (recordedFields == null) {
recordedFields = new LinkedList<Pair<String, Type>>();
}
recordedFields.add(new Pair<String, Type>(name, type));
}
public void captureVariable(EnclosedValueDescriptor value) {
if (captureVariables == null) {
captureVariables = new HashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
}
captureVariables.put(value.getDescriptor(), value);
}
public CallableDescriptor getEnclosingReceiverDescriptor() {
return enclosingReceiverDescriptor;
}
}
@@ -18,13 +18,15 @@ package org.jetbrains.jet.codegen.signature;
/** /**
* @author Stepan Koltsov * @author Stepan Koltsov
* @author alex.tkachman
*/ */
public enum JvmMethodParameterKind { public enum JvmMethodParameterKind {
VALUE, VALUE,
THIS, THIS,
THIS0, OUTER,
RECEIVER, RECEIVER,
SHARED_VAR, SHARED_VAR,
ENUM_NAME, ENUM_NAME,
ENUM_ORDINAL, ENUM_ORDINAL,
SUPER_CALL_PARAM
} }
@@ -23,7 +23,7 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.BuiltinToJavaTypesMapping; import org.jetbrains.jet.codegen.BuiltinToJavaTypesMapping;
import org.jetbrains.jet.codegen.ClassBuilderMode; import org.jetbrains.jet.codegen.ClassBuilderMode;
import org.jetbrains.jet.codegen.ClosureAnnotator; import org.jetbrains.jet.codegen.context.ClosureAnnotator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
@@ -31,7 +31,7 @@ import org.jetbrains.jet.codegen.ScriptCodegen;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.MemberCodegen; import org.jetbrains.jet.codegen.MemberCodegen;
import org.jetbrains.jet.codegen.ClosureAnnotator; import org.jetbrains.jet.codegen.context.ClosureAnnotator;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
@@ -28,30 +28,36 @@ public class ArrayGenTest extends CodegenTestCase {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
} }
public void testKt238 () throws Exception { public void testKt238() throws Exception {
blackBoxFile("regressions/kt238.jet"); blackBoxFile("regressions/kt238.jet");
} }
public void testKt326 () throws Exception { public void testKt326() throws Exception {
// blackBoxFile("regressions/kt326.jet"); // blackBoxFile("regressions/kt326.jet");
// System.out.println(generateToText()); // System.out.println(generateToText());
} }
public void testKt779 () throws Exception { public void testKt779() throws Exception {
blackBoxFile("regressions/kt779.jet"); blackBoxFile("regressions/kt779.jet");
// System.out.println(generateToText()); // System.out.println(generateToText());
} }
public void testCreateMultiInt () throws Exception { public void testCreateMultiInt() throws Exception {
loadText("fun foo() = Array<Array<Int>> (5, { Array<Int>(it, {239}) })"); loadText("fun foo() = Array<Array<Int>> (5, { Array<Int>(it, {239}) })");
Method foo = generateFunction(); Method foo = generateFunction();
Integer[][] invoke = (Integer[][]) foo.invoke(null); try {
assertEquals(invoke[2].length, 2); Integer[][] invoke = (Integer[][]) foo.invoke(null);
assertEquals(invoke[4].length, 4); assertEquals(invoke[2].length, 2);
assertEquals(invoke[4][2].intValue(), 239); assertEquals(invoke[4].length, 4);
assertEquals(invoke[4][2].intValue(), 239);
}
catch (Throwable e) {
System.out.println(generateToText());
throw ((e instanceof RuntimeException)) ? (RuntimeException) e : new RuntimeException(e);
}
} }
public void testCreateMultiIntNullable () throws Exception { public void testCreateMultiIntNullable() throws Exception {
loadText("fun foo() = Array<Array<Int?>> (5, { arrayOfNulls<Int>(it) })"); loadText("fun foo() = Array<Array<Int?>> (5, { arrayOfNulls<Int>(it) })");
Method foo = generateFunction(); Method foo = generateFunction();
Integer[][] invoke = (Integer[][]) foo.invoke(null); Integer[][] invoke = (Integer[][]) foo.invoke(null);
@@ -59,7 +65,7 @@ public class ArrayGenTest extends CodegenTestCase {
assertEquals(invoke[4].length, 4); assertEquals(invoke[4].length, 4);
} }
public void testCreateMultiString () throws Exception { public void testCreateMultiString() throws Exception {
loadText("fun foo() = Array<Array<String>> (5, { Array<String>(0,{\"\"}) })"); loadText("fun foo() = Array<Array<String>> (5, { Array<String>(0,{\"\"}) })");
Method foo = generateFunction(); Method foo = generateFunction();
Object invoke = foo.invoke(null); Object invoke = foo.invoke(null);
@@ -67,16 +73,16 @@ public class ArrayGenTest extends CodegenTestCase {
assertTrue(invoke instanceof Object[]); assertTrue(invoke instanceof Object[]);
} }
public void testCreateMultiGenerics () throws Exception { public void testCreateMultiGenerics() throws Exception {
// loadText("class L<T>() { val a = Array<T?>(5) } fun foo() = L<Int>.a"); // loadText("class L<T>() { val a = Array<T?>(5) } fun foo() = L<Int>.a");
// System.out.println(generateToText()); // System.out.println(generateToText());
// Method foo = generateFunction(); // Method foo = generateFunction();
// Object invoke = foo.invoke(null); // Object invoke = foo.invoke(null);
// System.out.println(invoke.getClass()); // System.out.println(invoke.getClass());
// assertTrue(invoke.getClass() == Object[].class); // assertTrue(invoke.getClass() == Object[].class);
} }
public void testIntGenerics () throws Exception { public void testIntGenerics() throws Exception {
loadText("class L<T>(var a : T) {} fun foo() = L<Int>(5).a"); loadText("class L<T>(var a : T) {} fun foo() = L<Int>(5).a");
//System.out.println(generateToText()); //System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
@@ -85,221 +91,222 @@ public class ArrayGenTest extends CodegenTestCase {
assertTrue(invoke instanceof Integer); assertTrue(invoke instanceof Integer);
} }
public void testIterator () throws Exception { public void testIterator() throws Exception {
loadText("fun box() { val x = Array<Int>(5, { it } ).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = Array<Int>(5, { it } ).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIterator () throws Exception { public void testPrimitiveIterator() throws Exception {
loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.nextByte()) } }"); loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.nextByte()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIteratorByte () throws Exception { public void testPrimitiveIteratorByte() throws Exception {
loadText("fun box() { for(x in ByteArray(5)) { java.lang.System.out?.println(x) } }"); loadText("fun box() { for(x in ByteArray(5)) { java.lang.System.out?.println(x) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIteratorShort () throws Exception { public void testPrimitiveIteratorShort() throws Exception {
loadText("fun box() { for(x in ShortArray(5)) { java.lang.System.out?.println(x) } }"); loadText("fun box() { for(x in ShortArray(5)) { java.lang.System.out?.println(x) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIteratorInt () throws Exception { public void testPrimitiveIteratorInt() throws Exception {
loadText("fun box() { for(x in IntArray(5)) { java.lang.System.out?.println(x) } }"); loadText("fun box() { for(x in IntArray(5)) { java.lang.System.out?.println(x) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIteratorLong () throws Exception { public void testPrimitiveIteratorLong() throws Exception {
loadText("fun box() { for(x in LongArray(5)) { java.lang.System.out?.println(x) } }"); loadText("fun box() { for(x in LongArray(5)) { java.lang.System.out?.println(x) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIteratorFloat () throws Exception { public void testPrimitiveIteratorFloat() throws Exception {
loadText("fun box() { for(x in FloatArray(5)) { java.lang.System.out?.println(x) } }"); loadText("fun box() { for(x in FloatArray(5)) { java.lang.System.out?.println(x) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIteratorDouble () throws Exception { public void testPrimitiveIteratorDouble() throws Exception {
loadText("fun box() { for(x in DoubleArray(5)) { java.lang.System.out?.println(x) } }"); loadText("fun box() { for(x in DoubleArray(5)) { java.lang.System.out?.println(x) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIteratorChar () throws Exception { public void testPrimitiveIteratorChar() throws Exception {
loadText("fun box() { for(x in CharArray(5)) { java.lang.System.out?.println(x) } }"); loadText("fun box() { for(x in CharArray(5)) { java.lang.System.out?.println(x) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testPrimitiveIteratorBoolean () throws Exception { public void testPrimitiveIteratorBoolean() throws Exception {
loadText("fun box() { for(x in BooleanArray(5)) { java.lang.System.out?.println(x) } }"); loadText("fun box() { for(x in BooleanArray(5)) { java.lang.System.out?.println(x) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testLongIterator () throws Exception { public void testLongIterator() throws Exception {
loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.nextLong()) } }"); loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.nextLong()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testCharIterator () throws Exception { public void testCharIterator() throws Exception {
loadText("fun box() { val x = CharArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = CharArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testByteIterator () throws Exception { public void testByteIterator() throws Exception {
loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testShortIterator () throws Exception { public void testShortIterator() throws Exception {
loadText("fun box() { val x = ShortArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = ShortArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testIntIterator () throws Exception { public void testIntIterator() throws Exception {
loadText("fun box() { val x = IntArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = IntArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testLongIterator2 () throws Exception { public void testLongIterator2() throws Exception {
loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testFloatIterator () throws Exception { public void testFloatIterator() throws Exception {
loadText("fun box() { val x = FloatArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = FloatArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testDoubleIterator () throws Exception { public void testDoubleIterator() throws Exception {
loadText("fun box() { val x = ShortArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = ShortArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testBooleanIterator () throws Exception { public void testBooleanIterator() throws Exception {
loadText("fun box() { val x = BooleanArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = BooleanArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testArrayIndices () throws Exception { public void testArrayIndices() throws Exception {
loadText("fun box() { val x = Array<Int>(5, {it}).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText(
// System.out.println(generateToText()); "fun box() { val x = Array<Int>(5, {it}).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testCharIndices () throws Exception { public void testCharIndices() throws Exception {
loadText("fun box() { val x = CharArray(5).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); loadText("fun box() { val x = CharArray(5).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
foo.invoke(null); foo.invoke(null);
} }
public void testCollectionPlusAssign () throws Exception { public void testCollectionPlusAssign() throws Exception {
blackBoxFile("regressions/kt33.jet"); blackBoxFile("regressions/kt33.jet");
} }
public void testArrayPlusAssign () throws Exception { public void testArrayPlusAssign() throws Exception {
loadText("fun box() : Int { val s = IntArray(1); s [0] = 5; s[0] += 7; return s[0] }"); loadText("fun box() : Int { val s = IntArray(1); s [0] = 5; s[0] += 7; return s[0] }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction(); Method foo = generateFunction();
assertTrue((Integer)foo.invoke(null) == 12); assertTrue((Integer) foo.invoke(null) == 12);
} }
public void testCollectionAssignGetMultiIndex () throws Exception { public void testCollectionAssignGetMultiIndex() throws Exception {
loadText("import java.util.ArrayList\n" + loadText("import java.util.ArrayList\n" +
"fun box() : String { val s = ArrayList<String>(1); s.add(\"\"); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[2,-2] }\n" + "fun box() : String { val s = ArrayList<String>(1); s.add(\"\"); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[2,-2] }\n" +
"fun ArrayList<String>.get(index1: Int, index2 : Int) = this[index1+index2]!!\n" + "fun ArrayList<String>.get(index1: Int, index2 : Int) = this[index1+index2]!!\n" +
"fun ArrayList<String>.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n"); "fun ArrayList<String>.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction("box");
assertTrue(foo.invoke(null).equals("57"));
}
public void testArrayGetAssignMultiIndex () throws Exception {
loadText(
"fun box() : String? { val s = Array<String>(1,{ \"\" }); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[-3,3] }\n" +
"fun Array<String>.get(index1: Int, index2 : Int) = this[index1+index2]\n" +
"fun Array<String>.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }");
// System.out.println(generateToText());
Method foo = generateFunction("box"); Method foo = generateFunction("box");
assertTrue(foo.invoke(null).equals("57")); assertTrue(foo.invoke(null).equals("57"));
} }
public void testCollectionGetMultiIndex () throws Exception { public void testArrayGetAssignMultiIndex() throws Exception {
loadText("import java.util.ArrayList\n" +
"fun box() : String { val s = ArrayList<String>(1); s.add(\"\"); s [1, -1] = \"5\"; return s[2, -2] }\n" +
"fun ArrayList<String>.get(index1: Int, index2 : Int) = this[index1+index2]!!\n" +
"fun ArrayList<String>.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n");
// System.out.println(generateToText());
Method foo = generateFunction("box");
assertTrue(foo.invoke(null).equals("5"));
}
public void testArrayGetMultiIndex () throws Exception {
loadText( loadText(
"fun box() : String? { val s = Array<String>(1,{ \"\" }); s [1, -1] = \"5\"; return s[-2, 2] }\n" + "fun box() : String? { val s = Array<String>(1,{ \"\" }); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[-3,3] }\n" +
"fun Array<String>.get(index1: Int, index2 : Int) = this[index1+index2]\n" + "fun Array<String>.get(index1: Int, index2 : Int) = this[index1+index2]\n" +
"fun Array<String>.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }"); "fun Array<String>.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }");
// System.out.println(generateToText()); // System.out.println(generateToText());
Method foo = generateFunction("box");
assertTrue(foo.invoke(null).equals("57"));
}
public void testCollectionGetMultiIndex() throws Exception {
loadText("import java.util.ArrayList\n" +
"fun box() : String { val s = ArrayList<String>(1); s.add(\"\"); s [1, -1] = \"5\"; return s[2, -2] }\n" +
"fun ArrayList<String>.get(index1: Int, index2 : Int) = this[index1+index2]!!\n" +
"fun ArrayList<String>.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n");
// System.out.println(generateToText());
Method foo = generateFunction("box"); Method foo = generateFunction("box");
assertTrue(foo.invoke(null).equals("5")); assertTrue(foo.invoke(null).equals("5"));
} }
public void testMap () throws Exception { public void testArrayGetMultiIndex() throws Exception {
loadText( loadText(
"fun box() : Int? { val s = java.util.HashMap<String,Int?>(); s[\"239\"] = 239; return s[\"239\"] }\n" + "fun box() : String? { val s = Array<String>(1,{ \"\" }); s [1, -1] = \"5\"; return s[-2, 2] }\n" +
"fun java.util.HashMap<String,Int?>.set(index: String, elem: Int?) { this.put(index, elem) }"); "fun Array<String>.get(index1: Int, index2 : Int) = this[index1+index2]\n" +
// System.out.println(generateToText()); "fun Array<String>.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }");
// System.out.println(generateToText());
Method foo = generateFunction("box"); Method foo = generateFunction("box");
assertTrue((Integer)foo.invoke(null) == 239); assertTrue(foo.invoke(null).equals("5"));
} }
public void testLongDouble () throws Exception { public void testMap() throws Exception {
loadText( loadText(
"fun box() : Int { var l = IntArray(1); l[0.toLong()] = 4; l[0.toLong()] += 6; return l[0.toLong()];}\n" + "fun box() : Int? { val s = java.util.HashMap<String,Int?>(); s[\"239\"] = 239; return s[\"239\"] }\n" +
"fun IntArray.set(index: Long, elem: Int) { this[index.toInt()] = elem }\n" + "fun java.util.HashMap<String,Int?>.set(index: String, elem: Int?) { this.put(index, elem) }");
"fun IntArray.get(index: Long) = this[index.toInt()]"); // System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction("box"); Method foo = generateFunction("box");
assertTrue((Integer)foo.invoke(null) == 10); assertTrue((Integer) foo.invoke(null) == 239);
}
public void testLongDouble() throws Exception {
loadText(
"fun box() : Int { var l = IntArray(1); l[0.toLong()] = 4; l[0.toLong()] += 6; return l[0.toLong()];}\n" +
"fun IntArray.set(index: Long, elem: Int) { this[index.toInt()] = elem }\n" +
"fun IntArray.get(index: Long) = this[index.toInt()]");
// System.out.println(generateToText());
Method foo = generateFunction("box");
assertTrue((Integer) foo.invoke(null) == 10);
} }
public void testKt503() { public void testKt503() {
@@ -308,7 +315,7 @@ public class ArrayGenTest extends CodegenTestCase {
public void testKt602() { public void testKt602() {
blackBoxFile("regressions/kt602.jet"); blackBoxFile("regressions/kt602.jet");
// System.out.println(generateToText()); // System.out.println(generateToText());
} }
public void testKt950() { public void testKt950() {
@@ -317,12 +324,12 @@ public class ArrayGenTest extends CodegenTestCase {
public void testKt594() throws Exception { public void testKt594() throws Exception {
loadFile("regressions/kt594.jet"); loadFile("regressions/kt594.jet");
// System.out.println(generateToText()); // System.out.println(generateToText());
blackBox(); blackBox();
} }
public void testNonNullArray() throws Exception { public void testNonNullArray() throws Exception {
blackBoxFile("classes/nonnullarray.jet"); blackBoxFile("classes/nonnullarray.jet");
// System.out.println(generateToText()); // System.out.println(generateToText());
} }
} }
@@ -332,7 +332,7 @@ public class ClassGenTest extends CodegenTestCase {
} }
public void testSelfCreate() throws Exception { public void testSelfCreate() throws Exception {
createEnvironmentWithFullJdk(); createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
blackBoxFile("classes/selfcreate.kt"); blackBoxFile("classes/selfcreate.kt");
} }
@@ -16,15 +16,9 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.CompileCompilerDependenciesTest;
import org.jetbrains.jet.ConfigurationKind; import org.jetbrains.jet.ConfigurationKind;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.TestJdkKind;
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
import java.io.File; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -89,6 +83,19 @@ public class FunctionGenTest extends CodegenTestCase {
assertFalse((Boolean) foo.invoke(null, "mama")); assertFalse((Boolean) foo.invoke(null, "mama"));
} }
public void testNoRefToOuter() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
loadText("class A() { fun f() : ()->String { val s = \"OK\"; return { -> s } } }");
// System.out.println(generateToText());
Class foo = generateClass("A");
final Object obj = foo.newInstance();
final Method f = foo.getMethod("f");
final Object closure = f.invoke(obj);
final Class<? extends Object> aClass = closure.getClass();
final Field[] fields = aClass.getFields();
assertEquals(1, fields.length);
assertEquals("$s", fields[0].getName());
}
public void testAnyEquals() throws InvocationTargetException, IllegalAccessException { public void testAnyEquals() throws InvocationTargetException, IllegalAccessException {
loadText("fun foo(x: Any) = x.equals(\"lala\")"); loadText("fun foo(x: Any) = x.equals(\"lala\")");
// System.out.println(generateToText()); // System.out.println(generateToText());
@@ -115,6 +122,7 @@ public class FunctionGenTest extends CodegenTestCase {
public void testKt1199() { public void testKt1199() {
blackBoxFile("regressions/kt1199.kt"); blackBoxFile("regressions/kt1199.kt");
System.out.println(generateToText());
} }
public void testFunction() throws InvocationTargetException, IllegalAccessException { public void testFunction() throws InvocationTargetException, IllegalAccessException {
@@ -33,7 +33,7 @@ public class LocalClassGenTest extends CodegenTestCase {
} }
public void testWithClosure() { public void testWithClosure() {
//blackBoxFile("localcls/withclosure.kt"); blackBoxFile("localcls/withclosure.kt");
} }
public void testEnum() { public void testEnum() {
@@ -18,6 +18,7 @@ package org.jetbrains.jet.di;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import org.jetbrains.jet.codegen.*; import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.codegen.context.ClosureAnnotator;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.jet.lang.BuiltinsScopeExtensionMode; import org.jetbrains.jet.lang.BuiltinsScopeExtensionMode;
import org.jetbrains.jet.lang.ModuleConfiguration; import org.jetbrains.jet.lang.ModuleConfiguration;
@@ -163,15 +164,15 @@ public class AllInjectorsGenerator {
generator.generate("compiler/tests", "org.jetbrains.jet.di", "InjectorForTests"); generator.generate("compiler/tests", "org.jetbrains.jet.di", "InjectorForTests");
} }
private static void generateInjectorForJavaSemanticServices() throws IOException { private static void generateInjectorForJavaSemanticServices() throws IOException {
DependencyInjectorGenerator generator = new DependencyInjectorGenerator(false); DependencyInjectorGenerator generator = new DependencyInjectorGenerator(false);
// Fields // Fields
generator.addPublicField(JavaSemanticServices.class); generator.addPublicField(JavaSemanticServices.class);
generator.addPublicField(JavaDescriptorResolver.class); generator.addPublicField(JavaDescriptorResolver.class);
generator.addField(true, BindingTrace.class, null, generator.addField(true, BindingTrace.class, null,
new GivenExpression("new org.jetbrains.jet.lang.resolve.BindingTraceContext()")); new GivenExpression("new org.jetbrains.jet.lang.resolve.BindingTraceContext()"));
generator.addField(JavaBridgeConfiguration.class); generator.addField(JavaBridgeConfiguration.class);
generator.addPublicField(PsiClassFinderImpl.class); generator.addPublicField(PsiClassFinderImpl.class);
generator.addField(false, ModuleDescriptor.class, null, generator.addField(false, ModuleDescriptor.class, null,
@@ -181,7 +182,7 @@ public class AllInjectorsGenerator {
// Parameters // Parameters
generator.addPublicParameter(Project.class); generator.addPublicParameter(Project.class);
generator.generate("compiler/frontend.java/src", "org.jetbrains.jet.di", "InjectorForJavaSemanticServices"); generator.generate("compiler/frontend.java/src", "org.jetbrains.jet.di", "InjectorForJavaSemanticServices");
} }
@@ -226,5 +227,4 @@ public class AllInjectorsGenerator {
generator.addPublicParameter(BodiesResolveContext.class); generator.addPublicParameter(BodiesResolveContext.class);
generator.generate("compiler/frontend/src", "org.jetbrains.jet.di", "InjectorForBodyResolve"); generator.generate("compiler/frontend/src", "org.jetbrains.jet.di", "InjectorForBodyResolve");
} }
} }