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.Type;
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.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.*;
@@ -125,7 +125,7 @@ public class ClassBuilderFactories {
return super.getCommonSuperClass(type1, type2);
}
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";
}
}
@@ -16,6 +16,7 @@
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.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.*;
@@ -30,14 +31,14 @@ import java.util.Map;
*/
public class ClassCodegen {
private GenerationState state;
private JetTypeMapper jetTypeMapper;
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private JetTypeMapper jetTypeMapper;
@Inject
public void setState(GenerationState state) {
this.state = state;
}
@SuppressWarnings("UnusedParameters")
@Inject
public void setJetTypeMapper(JetTypeMapper jetTypeMapper) {
this.jetTypeMapper = jetTypeMapper;
@@ -48,13 +49,13 @@ public class ClassCodegen {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
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) {
// 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
// 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()) {
@@ -72,7 +73,7 @@ public class ClassCodegen {
}
if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES) {
generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.accessors, classBuilder);
generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder);
}
classBuilder.done();
@@ -86,13 +87,14 @@ public class ClassCodegen {
ClassBuilder classBuilder
) {
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);
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate();
if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
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();
traitBuilder.done();
}
@@ -22,15 +22,16 @@ package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Label;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.asm4.signature.SignatureWriter;
import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
import org.jetbrains.jet.codegen.context.CalculatedClosure;
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.lang.descriptors.*;
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.BindingContextUtils;
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.types.JetType;
@@ -48,81 +48,42 @@ import java.util.List;
import static org.jetbrains.asm4.Opcodes.*;
public class ClosureCodegen extends ObjectOrClosureCodegen {
public class ClosureCodegen {
private final BindingContext bindingContext;
private final ClosureAnnotator closureAnnotator;
private final JetTypeMapper typeMapper;
public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, CodegenContext context) {
super(exprContext, context, state);
Method constructor;
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();
typeMapper = this.state.getInjector().getJetTypeMapper();
typeMapper = state.getInjector().getJetTypeMapper();
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 FunctionDescriptor funDescriptor = bindingContext.get(BindingContext.FUNCTION, fun);
cv = nameAndVisitor.getSecond();
ClassBuilder cv = nameAndVisitor.getSecond();
name = nameAndVisitor.getFirst();
SignatureWriter signatureWriter = new SignatureWriter();
assert funDescriptor != null;
final List<ValueParameterDescriptor> parameters = funDescriptor.getValueParameters();
final JvmClassName funClass = getInternalClassName(funDescriptor);
final JvmClassName funClass = CodegenUtil.getInternalClassName(funDescriptor);
signatureWriter.visitClassType(funClass.getInternalName());
for (ValueParameterDescriptor parameter : parameters) {
appendType(signatureWriter, parameter.getType(), '=');
@@ -143,46 +104,27 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
generateBridge(name.getInternalName(), funDescriptor, fun, cv);
captureThis = generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun);
generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun, context, expressionCodegen);
final ClassDescriptor enclosingClass = context.getEnclosingClass();
if (enclosingClass == null) {
captureThis = null;
constructor = generateConstructor(funClass, fun, cv, closure);
if (CodegenUtil.isConst(closure)) {
generateConstInstance(fun, cv);
}
final Method constructor = generateConstructor(funClass, fun, funDescriptor);
if (captureThis != null) {
cv.newField(fun, ACC_FINAL, "this$0", typeMapper.mapType(enclosingClass.getDefaultType(), MapTypeMode.IMPL).getDescriptor(),
null, null);
}
if (isConst()) {
generateConstInstance(fun);
}
CodegenUtil.generateClosureFields(closure, cv, state.getInjector().getJetTypeMapper());
cv.done();
final GeneratedAnonymousClassDescriptor answer =
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;
return this;
}
private void generateConstInstance(PsiElement fun) {
private void generateConstInstance(PsiElement fun, ClassBuilder cv) {
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) {
StubCodegen.generateStubCode(mv);
}
@@ -206,21 +148,29 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
}
}
private ClassDescriptor generateBody(FunctionDescriptor funDescriptor, ClassBuilder cv, JetDeclarationWithBody body) {
ClassDescriptor function =
closureAnnotator.classDescriptorForFunctionDescriptor(funDescriptor);
private ClassDescriptor generateBody(
FunctionDescriptor funDescriptor,
ClassBuilder cv,
JetDeclarationWithBody body,
CodegenContext context,
ExpressionCodegen expressionCodegen
) {
final CodegenContexts.ClosureContext closureContext = context.intoClosure(
funDescriptor, function, this, typeMapper);
final CodegenContext closureContext = context.intoClosure(funDescriptor, expressionCodegen);
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
JvmMethodSignature jvmMethodSignature = invokeSignature(funDescriptor);
JvmMethodSignature jvmMethodSignature = typeMapper.invokeSignature(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) {
final JvmMethodSignature bridge = erasedInvokeSignature(funDescriptor);
final Method delegate = invokeSignature(funDescriptor).getAsmMethod();
private void generateBridge(
String className,
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())) {
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>>();
boolean putFieldForMyself = calculateConstructorParameters(funDescriptor, args);
calculateConstructorParameters(args, state, closure);
final Type[] argTypes = nameAnTypeListToTypeArray(args);
@@ -293,14 +248,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
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);
FunctionCodegen.endVisit(iv, "constructor", fun);
@@ -308,22 +255,24 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
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) {
final Type type = typeMapper.mapType(context.getThisDescriptor().getDefaultType(), MapTypeMode.VALUE);
args.add(new Pair<String, Type>("this$0", type));
final Type type = typeMapper.mapType(captureThis.getDefaultType(), MapTypeMode.VALUE);
args.add(new Pair<String, Type>(CodegenUtil.THIS$0, type));
}
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
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.keySet()) {
if (descriptor == funDescriptor) {
putFieldForMyself = true;
}
else if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
final Type sharedVarType = typeMapper.getSharedVarType(descriptor);
final Type type = sharedVarType != null
@@ -343,7 +292,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
assert captureReceiver != null;
}
}
return putFieldForMyself;
}
private static Type[] nameAnTypeListToTypeArray(List<Pair<String, Type>> args) {
@@ -354,17 +302,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
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) {
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;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
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.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Random;
import java.util.*;
import static org.jetbrains.asm4.Opcodes.*;
/**
* @author abreslav
* @author alex.tkachman
*/
public class CodegenUtil {
public static final String RECEIVER$0 = "receiver$0";
public static final String THIS$0 = "this$0";
private CodegenUtil() {
}
@@ -83,6 +91,14 @@ public class CodegenUtil {
!(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) {
PsiElement psiElement = BindingContextUtils.descriptorToDeclaration(bindingContext, fd);
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) {
InstructionAdapter instructionAdapter = new InstructionAdapter(mv);
instructionAdapter.anew(Type.getObjectType(exception));
instructionAdapter.dup();
instructionAdapter.aconst(message);
instructionAdapter.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
instructionAdapter.athrow();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.anew(Type.getObjectType(exception));
iv.dup();
iv.aconst(message);
iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
iv.athrow();
}
public static void generateMethodThrow(MethodVisitor mv, String exception, String message) {
@@ -140,4 +156,92 @@ public class CodegenUtil {
mv.visitMaxs(-1, -1);
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.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.ValueParameterDescriptor;
@@ -32,23 +33,25 @@ import java.util.List;
public class ConstructorFrameMap extends FrameMap {
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
if (descriptor != null) {
if (hasThis0) {
myOuterThisIndex = enterTemp(JetTypeMapper.OBJECT_TYPE); // outer class instance
final List<JvmMethodParameterSignature> parameterTypes = callableMethod.getSignature().getKotlinParameterTypes();
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();
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
? descriptor.getValueParameters()
: Collections.<ValueParameterDescriptor>emptyList();
@@ -33,6 +33,7 @@ import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.context.*;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature;
import org.jetbrains.jet.lang.descriptors.*;
@@ -63,7 +64,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull;
* @author yole
* @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_TYPE_CAST_EXCEPTION = "jet/TypeCastException";
@@ -78,7 +79,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private final Type returnType;
private final BindingContext bindingContext;
private final CodegenContext context;
final CodegenContext context;
private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>();
private final Collection<String> localVariableNames = new HashSet<String>();
@@ -136,6 +137,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
this.context = context;
}
public GenerationState getState() {
return state;
}
StackValue castToRequiredTypeOfInterfaceIfNeeded(StackValue inner, DeclarationDescriptor provided, @Nullable ClassDescriptor required) {
if (required == null) {
return inner;
@@ -218,14 +223,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private StackValue visitClassOrObject(JetClassOrObject 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);
closure.cv = nameAndVisitor.getSecond();
closure.name = nameAndVisitor.getFirst();
final CodegenContext objectContext = closure.context.intoAnonymousClass(
closure, descriptor, OwnerKind.IMPLEMENTATION,
typeMapper);
final CodegenContext objectContext = context.intoAnonymousClass(descriptor, this);
new ImplementationBodyCodegen(declaration, objectContext, nameAndVisitor.getSecond(), state).generate();
return StackValue.none();
@@ -394,13 +396,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return StackValue.none();
}
generateForInIterable(expression, loopRangeType);
generateForInIterable(expression);
return StackValue.none();
}
}
@SuppressWarnings("ConstantConditions")
private void generateForInIterable(JetForExpression expression, Type loopRangeType) {
private void generateForInIterable(JetForExpression expression) {
generateForLoop(expression.getBody(), new IteratorForLoopGenerator(expression));
}
@@ -410,9 +412,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
private interface ForLoopGenerator {
void beforeLoop();
void conditionAndJump(@NotNull Label loopExit);
void beforeBody();
void afterBody();
void afterLoop();
}
@@ -457,6 +463,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@NotNull
private JetType getElementType(JetForExpression forExpression) {
JetExpression loopRange = forExpression.getLoopRange();
assert loopRange != null;
ResolvedCall<FunctionDescriptor> nextCall = getNotNull(bindingContext,
LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
"No next() function " + DiagnosticUtils.atLocation(loopRange));
@@ -470,7 +477,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (loopParameter != null) {
// E e = tmp<iterator>.next()
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);
leaveVariableTasks.add(new Runnable() {
@Override
@@ -510,7 +517,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
for (JetMultiDeclarationEntry variableDeclaration : entries) {
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);
leaveVariableTasks.add(new Runnable() {
@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();
Call call = makeFakeCall(new TransientReceiver(elementType));
invokeFunction(call, StackValue.local(tmpParameterIndex, asmElementType), resolvedCall);
@@ -554,9 +562,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
super(forExpression);
JetExpression loopRange = forExpression.getLoopRange();
assert loopRange != null;
this.iteratorCall = getNotNull(bindingContext,
LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange,
"No .iterator() function " + DiagnosticUtils.atLocation(loopRange));
LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange,
"No .iterator() function " + DiagnosticUtils.atLocation(loopRange));
JetType iteratorType = iteratorCall.getResultingDescriptor().getReturnType();
assert iteratorType != null;
@@ -583,10 +592,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
// tmp<iterator>.hasNext()
JetExpression loopRange = forExpression.getLoopRange();
ResolvedCall<FunctionDescriptor> hasNextCall = getNotNull(bindingContext,
@SuppressWarnings("ConstantConditions") ResolvedCall<FunctionDescriptor> hasNextCall = getNotNull(bindingContext,
LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, 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);
JetType type = hasNextCall.getResultingDescriptor().getReturnType();
@@ -599,9 +608,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
protected void assignToLoopParameter(int parameterIndex) {
Call fakeCall =
@SuppressWarnings("ConstantConditions") Call fakeCall =
makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
invokeFunction(fakeCall, StackValue.local(iteratorVarIndex, asmTypeForIterator), nextCall);
//noinspection ConstantConditions
v.store(parameterIndex, asmType(nextCall.getResultingDescriptor().getReturnType()));
}
@@ -763,7 +773,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
protected void generatePrologue() {
myIndexVar = lookupLocal(parameterDescriptor);
myIndexVar = lookupLocalIndex(parameterDescriptor);
myCountVar = myFrameMap.enterTemp(Type.INT_TYPE);
myDeltaVar = myFrameMap.enterTemp(Type.INT_TYPE);
if (isIntRangeExpr(expression.getLoopRange())) {
@@ -977,7 +987,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
StackValue closure = genClosure(function);
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
int index = myFrameMap.getIndex(descriptor);
int index = lookupLocalIndex(descriptor);
closure.put(OBJECT_TYPE, v);
v.store(index, OBJECT_TYPE);
return StackValue.none();
@@ -996,89 +1006,90 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
private StackValue genClosure(JetExpression expression) {
ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context);
final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression);
final FunctionDescriptor descriptor = bindingContext.get(BindingContext.FUNCTION, expression);
final ClosureAnnotator closureAnnotator = state.getInjector().getClosureAnnotator();
final ClassDescriptor classDescriptor = closureAnnotator.classDescriptorForFunctionDescriptor(descriptor);
final CalculatedClosure closure = closureAnnotator.getCalculatedClosure(classDescriptor);
if (closureCodegen.isConst()) {
v.invokestatic(closure.getClassname().getInternalName(), "$getInstance", "()" + closure.getClassname().getDescriptor());
ClosureCodegen closureCodegen = new ClosureCodegen(state, (MutableClosure) closure).gen(expression, context, this);
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 {
v.anew(closure.getClassname().getAsmType());
v.anew(asmType);
v.dup();
final Method cons = closure.getConstructor();
int k = 0;
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());
final Method cons = closureCodegen.constructor;
pushClosureOnStack(closure, false);
v.invokespecial(internalName, "<init>", cons.getDescriptor());
}
return StackValue.onStack(closure.getClassname().getAsmType());
return StackValue.onStack(asmType);
}
@Override
public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) {
ObjectOrClosureCodegen closureCodegen = new ObjectOrClosureCodegen(this, context, state);
GeneratedAnonymousClassDescriptor closure = state.generateObjectLiteral(expression, closureCodegen);
Type type = closure.getClassname().getAsmType();
CalculatedClosure closure = state.generateObjectLiteral(expression, this);
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.dup();
final List<Type> consArgTypes = new LinkedList<Type>(Arrays.asList(closure.getConstructor().getArgumentTypes()));
final Method cons = constructor.getSignature().getAsmMethod();
if (consArgTypes.size() > 0) {
v.load(0, OBJECT_TYPE);
}
pushClosureOnStack(closure, false);
if (closureCodegen.captureReceiver != null) {
final Type asmType = typeMapper.mapType(closureCodegen.captureReceiver.getDefaultType(), MapTypeMode.IMPL);
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) {
final JetDelegatorToSuperCall superCall = closure.getSuperCall();
if (superCall != null) {
ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET,
closureCodegen.superCall
superCall
.getCalleeExpression()
.getConstructorReferenceExpression());
assert superConstructor != null;
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor,
typeMapper.hasThis0(superConstructor.getContainingDeclaration()));
CallableMethod superCallable = typeMapper
.mapToCallableMethod(superConstructor, typeMapper.getCalculatedClosure(superConstructor.getContainingDeclaration()));
Type[] argumentTypes = superCallable.getSignature().getAsmMethod().getArgumentTypes();
Collections.addAll(consArgTypes, argumentTypes);
ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, closureCodegen.superCall.getCalleeExpression());
ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, superCall.getCalleeExpression());
assert resolvedCall != null;
pushMethodArguments(resolvedCall, Arrays.asList(argumentTypes));
}
Method cons = new Method("<init>", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()]));
v.invokespecial(closure.getClassname().getInternalName(), "<init>", cons.getDescriptor());
return StackValue.onStack(closure.getClassname().getAsmType());
v.invokespecial(name.getInternalName(), "<init>", cons.getDescriptor());
return StackValue.onStack(type);
}
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) {
@@ -1301,7 +1312,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
}
int index = lookupLocal(descriptor);
int index = lookupLocalIndex(descriptor);
if (index >= 0) {
return stackValueForLocal(descriptor, index);
}
@@ -1379,7 +1390,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
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 instanceof StackValue.Composed) {
@@ -1445,39 +1456,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
}
public int lookupLocal(DeclarationDescriptor descriptor) {
return myFrameMap.getIndex(descriptor);
@Override
public boolean lookupLocal(DeclarationDescriptor descriptor) {
return lookupLocalIndex(descriptor) != -1;
}
public void invokeFunctionNoParams(FunctionDescriptor functionDescriptor, Type expectedType, InstructionAdapter v) {
DeclarationDescriptor containingDeclaration = functionDescriptor.getOriginal().getContainingDeclaration();
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 int lookupLocalIndex(DeclarationDescriptor descriptor) {
return myFrameMap.getIndex(descriptor);
}
public StackValue.Property intermediateValueForProperty(
@@ -1499,7 +1484,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
boolean isInsideClass = !isFakeOverride &&
(((containingDeclaration == null && !context.hasThisDescriptor() ||
context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) ||
(context.getParentContext() instanceof CodegenContexts.NamespaceContext) &&
(context.getParentContext() instanceof CodegenContext.NamespaceContext) &&
context.getParentContext().getContextDescriptor() == containingDeclaration)
&& contextKind() != OwnerKind.TRAIT_IMPL);
Method getter = null;
@@ -1681,7 +1666,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (enclosed != context.getThisDescriptor()) {
CodegenContext c = context;
//noinspection ConstantConditions
while (!(c instanceof CodegenContexts.ClassContext) ||
while (!(c instanceof CodegenContext.ClassContext) ||
!DescriptorUtils.isSubclass(c.getThisDescriptor(), enclosed)) {
c = c.getParentContext();
assert c != null;
@@ -1761,7 +1746,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
//}
if (isCallAsFunctionObject(fd)) {
SimpleFunctionDescriptor invoke = CodegenUtil.createInvoke(fd);
callableMethod = ClosureCodegen.asCallableMethod(invoke, typeMapper);
callableMethod = typeMapper.asCallableMethod(invoke);
}
else {
callableMethod = typeMapper.mapToCallableMethod(fd, superCall, OwnerKind.IMPLEMENTATION);
@@ -1895,14 +1880,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
private StackValue generateReceiver(DeclarationDescriptor provided) {
assert context instanceof CodegenContexts.ReceiverContext;
CodegenContexts.ReceiverContext cur = (CodegenContexts.ReceiverContext) context;
if (cur.getReceiverDescriptor() == provided) {
StackValue result = cur.getReceiverExpression(typeMapper);
if (context.getReceiverDescriptor() == provided) {
StackValue result = context.getReceiverExpression(typeMapper);
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);
}
@@ -1910,12 +1893,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
CodegenContext cur = context;
StackValue result = StackValue.local(0, OBJECT_TYPE);
while (cur != null) {
if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext)) {
if (cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext)) {
cur = cur.getParentContext();
}
if (cur instanceof CodegenContexts.ScriptContext) {
CodegenContexts.ScriptContext scriptContext = (CodegenContexts.ScriptContext) cur;
if (cur instanceof CodegenContext.ScriptContext) {
CodegenContext.ScriptContext scriptContext = (CodegenContext.ScriptContext) cur;
JvmClassName currentScriptClassName =
state.getInjector().getClosureAnnotator().classNameForScriptDescriptor(scriptContext.getScriptDescriptor());
@@ -1933,9 +1916,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
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();
}
assert cur != null;
@@ -1953,7 +1936,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
Type type = asmType(calleeContainingClass.getDefaultType());
StackValue result = StackValue.local(0, type);
while (cur != null) {
if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext)) {
if (cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext)) {
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();
}
assert cur != null;
@@ -2125,7 +2108,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (typeMapper.isVarCapturedInClosure(declarationDescriptor)) {
return -1;
}
return lookupLocal(declarationDescriptor);
return lookupLocalIndex(declarationDescriptor);
}
@Override
@@ -2220,7 +2203,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
private StackValue generateIn(JetBinaryExpression expression) {
JetExpression expr = expression.getLeft();
boolean inverted = expression.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN;
if (isIntRangeExpr(expression.getRight())) {
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) {
int functionLocalIndex = myFrameMap.getIndex(op);
int functionLocalIndex = lookupLocalIndex(op);
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 =
bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
@@ -2840,7 +2822,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
return;
}
int index = lookupLocal(variableDescriptor);
int index = lookupLocalIndex(variableDescriptor);
if (index < 0) {
throw new IllegalStateException("Local variable not found for " + variableDescriptor);
@@ -2894,15 +2876,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.anew(type);
v.dup();
// TODO typechecker must verify that we're the outer class of the instance being created
//noinspection ConstantConditions
if (!receiver.type.equals(Type.VOID_TYPE)) {
receiver.put(receiver.type, v);
}
final ClassDescriptor classDescriptor = ((ConstructorDescriptor) constructorDescriptor).getContainingDeclaration();
CallableMethod method = 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());
}
}
@@ -3089,10 +3069,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor);
}
else {
if (descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor) {
if (descriptor instanceof CallableDescriptor) {
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;
Type descriptorType = asmType(descriptor.getType());
myFrameMap.enter(descriptor, descriptorType);
int index = lookupLocal(descriptor);
int index = lookupLocalIndex(descriptor);
v.store(index, descriptorType);
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);
expressionToMatch.dupReceiver(v);
expressionToMatch.put(varType, v);
final int varIndex = myFrameMap.getIndex(variableDescriptor);
final int varIndex = lookupLocalIndex(variableDescriptor);
v.store(varIndex, varType);
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() {
return context.getContextDescriptor().toString();
}
}
@@ -25,6 +25,7 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter;
@@ -74,7 +75,7 @@ public class FunctionCodegen {
@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();
generatedMethod(bodyExpression, jvmMethod, needJetAnnotations, propertyTypeSignature, funContext, functionDescriptor, f);
@@ -84,7 +85,7 @@ public class FunctionCodegen {
JetExpression bodyExpressions,
JvmMethodSignature jvmSignature,
boolean needJetAnnotations, @Nullable String propertyTypeSignature,
CodegenContexts.MethodContext context,
CodegenContext.MethodContext context,
FunctionDescriptor functionDescriptor,
JetDeclarationWithBody fun
) {
@@ -334,7 +335,6 @@ public class FunctionCodegen {
}
endVisit(mv, null, fun);
mv.visitEnd();
generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor, kind);
}
@@ -417,7 +417,7 @@ public class FunctionCodegen {
}
static void generateDefaultIfNeeded(
CodegenContexts.MethodContext owner,
CodegenContext.MethodContext owner,
GenerationState state,
ClassBuilder v,
Method jvmSignature,
@@ -477,7 +477,7 @@ public class FunctionCodegen {
}
private static void generateDefaultImpl(
CodegenContexts.MethodContext owner,
CodegenContext.MethodContext owner,
GenerationState state,
Method jvmSignature,
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.asm4.commons.Method;
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.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -56,7 +57,6 @@ public class GenerationState {
// out parameter
private Method scriptConstructorMethod;
private final BindingContext bindingContext;
private final JetTypeMapper typeMapper;
public GenerationState(Project project, ClassBuilderFactory builderFactory, AnalyzeExhaust analyzeExhaust, List<JetFile> files) {
@@ -75,7 +75,6 @@ public class GenerationState {
this.injector = new InjectorForJvmCodegen(
bindingContext,
this.files, builtinToJavaTypesMapping, builderFactory.getClassBuilderMode(), this, builderFactory, project);
typeMapper = injector.getJetTypeMapper();
}
private void markUsed() {
@@ -195,25 +194,20 @@ public class GenerationState {
codegen.generate(errorHandler, progress);
}
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ObjectOrClosureCodegen closure) {
public CalculatedClosure generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen expressionCodegen) {
JetObjectDeclaration objectDeclaration = literal.getObjectDeclaration();
Pair<JvmClassName, ClassBuilder> nameAndVisitor = forAnonymousSubclass(objectDeclaration);
closure.cv = nameAndVisitor.getSecond();
closure.name = nameAndVisitor.getFirst();
final CodegenContext objectContext = closure.context.intoAnonymousClass(
closure, bindingContext.get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION,
typeMapper);
final ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, objectDeclaration);
assert classDescriptor != null;
final CalculatedClosure closure = getInjector().getClosureAnnotator().getCalculatedClosure(classDescriptor);
final CodegenContext objectContext = expressionCodegen.context.intoAnonymousClass(classDescriptor, expressionCodegen);
new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate();
ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, objectDeclaration);
assert constructorDescriptor != null;
CallableMethod callableMethod = typeMapper.mapToCallableMethod(
constructorDescriptor,
typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, callableMethod.getSignature().getAsmMethod(),
objectContext.outerWasUsed, null);
return closure;
}
public String createText() {
@@ -26,6 +26,9 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.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.kotlin.JetMethodAnnotationWriter;
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.BindingContextUtils;
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.java.JdkNames;
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());
assert superType != null;
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
assert superClassDescriptor != null;
if (!CodegenUtil.isInterface(superClassDescriptor)) {
superClassType = superType;
assert superClassDescriptor != null;
superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName();
superCall = specifier;
}
@@ -338,6 +342,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateAccessors();
generateEnumMethods();
CodegenUtil.generateClosureFields(context.closure, v, state.getInjector().getJetTypeMapper());
}
private void generateEnumMethods() {
@@ -373,10 +379,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateAccessors() {
if (context.accessors != null) {
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : context.accessors.entrySet()) {
genAccessor(entry);
}
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : context.getAccessors().entrySet()) {
genAccessor(entry);
}
}
@@ -551,73 +555,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass);
CodegenContexts.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper);
final CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor);
JvmMethodSignature constructorMethod;
CallableMethod callableMethod;
boolean hasThis0 = typeMapper.hasThis0(descriptor);
if (constructorDescriptor == null) {
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false);
lookupConstructorExpressionsInClosureIfPresent(constructorContext);
signatureWriter.writeFormalTypeParametersStart();
signatureWriter.writeFormalTypeParametersEnd();
MutableClosure closure = context.closure;
boolean hasThis0 = closure != null && closure.getCaptureThis() != null;
signatureWriter.writeParametersStart();
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);
}
final CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure);
final JvmMethodSignature constructorMethod = callableMethod.getSignature();
assert constructorDescriptor != null;
int flags = JetTypeMapper.getAccessModifiers(constructorDescriptor, 0);
@@ -643,18 +589,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return;
}
generatePrimiryConstructorImpl(constructorDescriptor, constructorContext, constructorMethod, callableMethod, hasThis0, closure,
firstSuperArgument, mv);
generatePrimiryConstructorImpl(constructorDescriptor, constructorContext, constructorMethod, callableMethod, hasThis0, closure, mv);
}
private void generatePrimiryConstructorImpl(
ConstructorDescriptor constructorDescriptor,
CodegenContexts.ConstructorContext constructorContext,
CodegenContext.ConstructorContext constructorContext,
JvmMethodSignature constructorMethod,
CallableMethod callableMethod,
boolean hasThis0,
ObjectOrClosureCodegen closure,
int firstSuperArgument,
MutableClosure closure,
MethodVisitor mv
) {
mv.visitCode();
@@ -663,7 +607,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
? constructorDescriptor.getValueParameters()
: Collections.<ValueParameterDescriptor>emptyList();
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, hasThis0);
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor);
final InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, constructorContext, state);
@@ -678,38 +622,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
genSuperCallToDelegatorToSuperClass(iv);
}
else {
ConstructorDescriptor constructorDescriptor1 = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET,
((JetDelegatorToSuperCall) superCall)
.getCalleeExpression()
.getConstructorReferenceExpression());
generateDelegatorToConstructorCall(iv, codegen, (JetDelegatorToSuperCall) superCall, constructorDescriptor1, frameMap,
firstSuperArgument);
generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, frameMap);
}
final ClassDescriptor outerDescriptor = typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor);
final boolean hasOuterThis = typeMapper.hasThis0(descriptor) && outerDescriptor != null;
if (hasOuterThis) {
final Type type = typeMapper.mapType(outerDescriptor.getDefaultType(), MapTypeMode.VALUE);
if (hasThis0) {
final Type type = typeMapper
.mapType(typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor).getDefaultType(), MapTypeMode.VALUE);
String interfaceDesc = type.getDescriptor();
final String fieldName = "this$0";
v.newField(myClass, ACC_FINAL, fieldName, interfaceDesc, null, null);
iv.load(0, classType);
iv.load(frameMap.getOuterThisIndex(), type);
iv.putfield(classname.getInternalName(), fieldName, interfaceDesc);
iv.putfield(classname.getInternalName(), CodegenUtil.THIS$0, interfaceDesc);
}
if (closure != null) {
int k = hasOuterThis ? 2 : 1;
if (closure.captureReceiver != null) {
int k = hasThis0 ? 2 : 1;
final String internalName = typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName();
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) {
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.putfield(typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName(), "receiver$0",
asmType.getDescriptor());
iv.putfield(internalName, CodegenUtil.RECEIVER$0, asmType.getDescriptor());
k += asmType.getSize();
}
for (DeclarationDescriptor varDescr : closure.closure.keySet()) {
for (DeclarationDescriptor varDescr : closure.getCaptureVariables().keySet()) {
if (varDescr instanceof VariableDescriptor && !(varDescr instanceof PropertyDescriptor)) {
Type sharedVarType = typeMapper.getSharedVarType(varDescr);
if (sharedVarType == null) {
@@ -718,7 +655,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.load(0, JetTypeMapper.OBJECT_TYPE);
iv.load(k, StackValue.refType(sharedVarType));
k += StackValue.refType(sharedVarType).getSize();
iv.putfield(typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName(),
iv.putfield(internalName,
"$" + varDescr.getName(), sharedVarType.getDescriptor());
}
}
@@ -847,37 +784,30 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
.getDefaultType(),
MapTypeMode.IMPL)
.getInternalName()),
state.getInjector().getJetTypeMapper());
state);
generateDelegates(superClass, delegateContext, field);
}
private int addClosureToConstructorParameters(
boolean hasThis0,
ObjectOrClosureCodegen closure,
MutableClosure closure,
List<JvmMethodParameterSignature> consArgTypes
) {
int insert = 0;
if (closure != null) {
if (closure.captureThis != null) {
if (!hasThis0) {
consArgTypes.add(insert,
new JvmMethodParameterSignature(Type.getObjectType(context.getThisDescriptor().getName().getName()),
"", JvmMethodParameterKind.THIS0));
}
if (closure.getCaptureThis() != null) {
consArgTypes.add(insert,
new JvmMethodParameterSignature(Type.getObjectType(context.getThisDescriptor().getName().getName()),
"", JvmMethodParameterKind.OUTER));
insert++;
}
else {
if (hasThis0) {
insert++;
}
}
if (closure.captureReceiver != null) {
final Type asmType = typeMapper.mapType(closure.captureReceiver.getDefaultType(), MapTypeMode.IMPL);
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) {
final Type asmType = typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.IMPL);
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)) {
final Type sharedVarType = typeMapper.getSharedVarType(descriptor);
final Type type;
@@ -891,30 +821,64 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
consArgTypes.add(insert++, new JvmMethodParameterSignature(type, "", JvmMethodParameterKind.SHARED_VAR));
}
else if (descriptor instanceof FunctionDescriptor) {
assert closure.captureReceiver != null;
assert captureReceiver != null;
}
}
}
return insert;
}
private void lookupDelegateExpressionInClosureIfPresent() {
if (context.closure != null) {
for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
if (specifier != superCall && specifier instanceof JetDelegatorByExpressionSpecifier) {
private void lookupConstructorExpressionsInClosureIfPresent(final CodegenContext.ConstructorContext constructorContext) {
final JetVisitorVoid visitor = new JetVisitorVoid() {
@Override
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();
assert delegateExpression != null;
delegateExpression.accept(new JetVisitorVoid() {
@Override
public void visitJetElement(JetElement e) {
e.acceptChildren(this);
}
@Override
public void visitSimpleNameExpression(JetSimpleNameExpression expr) {
context.closure.lookupInContext(bindingContext.get(BindingContext.REFERENCE_TARGET, expr), null);
}
});
delegateExpression.accept(visitor);
}
}
else {
if (superCall instanceof JetDelegatorToSuperCall) {
final JetValueArgumentList argumentList = ((JetDelegatorToSuperCall) superCall).getValueArgumentList();
if (argumentList != null) {
argumentList.accept(visitor);
}
}
}
}
@@ -1059,48 +1023,63 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateDelegatorToConstructorCall(
InstructionAdapter iv, ExpressionCodegen codegen, JetCallElement constructorCall,
InstructionAdapter iv, ExpressionCodegen codegen,
ConstructorDescriptor constructorDescriptor,
ConstructorFrameMap frameMap, int firstSuperArgument
ConstructorFrameMap frameMap
) {
ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
iv.load(0, OBJECT_TYPE);
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);
}
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) {
iv.load(frameMap.getOuterThisIndex(),
typeMapper.mapType(((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), MapTypeMode.IMPL));
}
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure);
CallableMethod method = typeMapper
.mapToCallableMethod(constructorDescriptor, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
final ResolvedCall<? extends CallableDescriptor> resolvedCall =
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 &&
superCall instanceof JetDelegatorToSuperCall &&
((JetObjectDeclaration) myClass).isObjectLiteral()) {
ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET,
((JetDelegatorToSuperCall) superCall)
.getCalleeExpression()
.getConstructorReferenceExpression());
assert superConstructor != null;
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor,
typeMapper.hasThis0(superConstructor.getContainingDeclaration()));
int nextVar = firstSuperArgument + 1;
int nextVar = findFirstSuperArgument(method);
for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) {
iv.load(nextVar, t);
nextVar += t.getSize();
}
method.invoke(codegen.v);
superCallable.invoke(codegen.v);
}
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
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
if (declaration instanceof JetClassObject) {
@@ -1171,7 +1150,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
.get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression());
assert constructorDescriptor != null;
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, typeMapper
.hasThis0(constructorDescriptor.getContainingDeclaration()));
.getCalculatedClosure(constructorDescriptor.getContainingDeclaration()));
codegen.invokeMethodWithArguments(method, superCall, StackValue.none());
}
else {
@@ -1206,7 +1185,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
Type type = typeMapper.mapType(jetType, MapTypeMode.VALUE);
if (skipDefaultValue(propertyDescriptor, value, type)) continue;
}
iv.load(0, JetTypeMapper.OBJECT_TYPE);
iv.load(0, OBJECT_TYPE);
Type type = codegen.expressionType(initializer);
if (jetType.isNullable()) {
type = JetTypeMapper.boxType(type);
@@ -21,12 +21,13 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type;
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.codegen.signature.JvmPropertyAccessorSignature;
import org.jetbrains.jet.codegen.context.CalculatedClosure;
import org.jetbrains.jet.codegen.context.ClosureAnnotator;
import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor;
import org.jetbrains.jet.codegen.signature.*;
import org.jetbrains.jet.lang.descriptors.*;
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.JetObjectDeclaration;
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 javax.inject.Inject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import static org.jetbrains.asm4.Opcodes.*;
@@ -103,7 +101,12 @@ public class JetTypeMapper {
}
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() {
@@ -856,22 +859,27 @@ public class JetTypeMapper {
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);
List<ValueParameterDescriptor> parameters = descriptor.getOriginal().getValueParameters();
// constructor type parmeters are fake
writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter);
signatureWriter.writeParametersStart();
ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (hasThis0) {
signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0);
mapType(closureAnnotator.getEclosingClassDescriptor(containingDeclaration).getDefaultType(), signatureWriter,
MapTypeMode.VALUE);
final ClassDescriptor captureThis = closure != null ? closure.getCaptureThis() : null;
if (captureThis != null) {
signatureWriter.writeParameterType(JvmMethodParameterKind.OUTER);
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();
}
@@ -884,7 +892,46 @@ public class JetTypeMapper {
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);
mapType(parameter.getType(), signatureWriter, MapTypeMode.VALUE);
signatureWriter.writeParameterTypeEnd();
@@ -925,8 +972,8 @@ public class JetTypeMapper {
return signatureWriter.makeJvmMethodSignature("<init>");
}
public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, boolean hasThis0) {
final JvmMethodSignature method = mapConstructorSignature(descriptor, hasThis0);
public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, CalculatedClosure closure) {
final JvmMethodSignature method = mapConstructorSignature(descriptor, closure);
JetType defaultType = descriptor.getContainingDeclaration().getDefaultType();
Type mapped = mapType(defaultType, MapTypeMode.IMPL);
if (mapped.getSort() != Type.OBJECT) {
@@ -999,4 +1046,23 @@ public class JetTypeMapper {
return Boolean.TRUE.equals(bindingContext.get(BindingContext.CAPTURED_IN_CLOSURE, variableDescriptor)) &&
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;
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.JetProperty;
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.Type;
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.PropertyDescriptor;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
@@ -122,19 +123,19 @@ public class NamespaceCodegen {
NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file);
for (JetDeclaration declaration : file.getDeclarations()) {
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(
(JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
}
else if (declaration instanceof JetNamedFunction) {
if (!multiFile) {
final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper());
final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
state.getInjector().getMemberCodegen().generateFunctionOrProperty(
(JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
}
}
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);
}
else if (declaration instanceof JetScript) {
@@ -170,13 +171,13 @@ public class NamespaceCodegen {
if (declaration instanceof JetNamedFunction) {
{
final CodegenContext context =
CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper());
CodegenContext.STATIC.intoNamespace(descriptor);
state.getInjector().getMemberCodegen()
.generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, builder);
}
{
final CodegenContext context =
CodegenContexts.STATIC.intoNamespacePart(className, descriptor, state.getInjector().getJetTypeMapper());
CodegenContext.STATIC.intoNamespacePart(className, descriptor);
state.getInjector().getMemberCodegen()
.generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
}
@@ -232,7 +233,7 @@ public class NamespaceCodegen {
mv.visitCode();
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 (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.Type;
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.kotlin.JetMethodAnnotationWriter;
import org.jetbrains.jet.lang.descriptors.*;
@@ -23,6 +23,8 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Opcodes;
import org.jetbrains.asm4.Type;
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.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
@@ -99,9 +101,9 @@ public class ScriptCodegen {
assert scriptDescriptor != null;
ClassDescriptor classDescriptorForScript = closureAnnotator.classDescriptorForScriptDescriptor(scriptDescriptor);
CodegenContexts.ScriptContext context =
(CodegenContexts.ScriptContext) CodegenContexts.STATIC
.intoScript(scriptDescriptor, classDescriptorForScript, state.getInjector().getJetTypeMapper());
CodegenContext.ScriptContext context =
(CodegenContext.ScriptContext) CodegenContext.STATIC
.intoScript(scriptDescriptor, classDescriptorForScript);
JvmClassName className = closureAnnotator.classNameForClassDescriptor(classDescriptorForScript);
@@ -117,7 +119,7 @@ public class ScriptCodegen {
genMembers(scriptDeclaration, context, classBuilder);
genFieldsForParameters(scriptDescriptor, classBuilder);
genConstructor(scriptDeclaration, scriptDescriptor, classDescriptorForScript, classBuilder,
context.intoFunction(scriptDescriptor.getScriptCodeDescriptor(), state.getInjector().getJetTypeMapper()),
context.intoFunction(scriptDescriptor.getScriptCodeDescriptor()),
earlierScripts);
classBuilder.done();
@@ -17,6 +17,7 @@
package org.jetbrains.jet.codegen;
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.ClassKind;
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.
*/
package org.jetbrains.jet.codegen;
package org.jetbrains.jet.codegen.context;
import com.intellij.util.containers.MultiMap;
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.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
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.JvmClassName;
import org.jetbrains.jet.lang.resolve.name.FqName;
@@ -36,15 +39,11 @@ import java.util.*;
* @author alex.tkachman
*/
public class ClosureAnnotator {
private final Map<ClassDescriptor, JvmClassName> classNamesForClassDescriptor = new HashMap<ClassDescriptor, JvmClassName>();
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
private final Map<ClassDescriptor, CalculatedClosure> closuresForClassDescriptor = new HashMap<ClassDescriptor, CalculatedClosure>();
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 Map<DeclarationDescriptor, ClassDescriptorImpl> classesForFunctions =
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> namespaceName2Files = MultiMap.create();
@@ -76,7 +75,7 @@ public class ClosureAnnotator {
int arity = funDescriptor.getValueParameters().size();
classDescriptor = new ClassDescriptorImpl(
funDescriptor,
funDescriptor.getContainingDeclaration(),
Collections.<AnnotationDescriptor>emptyList(),
Modality.FINAL,
Name.special("<closure>"));
@@ -107,7 +106,6 @@ public class ClosureAnnotator {
Collections.<AnnotationDescriptor>emptyList(),
Modality.FINAL,
Name.special("<script-" + className + ">"));
recordName(classDescriptor, className);
classDescriptor.initialize(
false,
Collections.<TypeParameterDescriptor>emptyList(),
@@ -116,6 +114,8 @@ public class ClosureAnnotator {
Collections.<ConstructorDescriptor>emptySet(),
null);
recordClosure(null, classDescriptor, null, className, false);
ClassDescriptorImpl oldDescriptor = classesForFunctions.put(scriptDescriptor, classDescriptor);
if (oldDescriptor != null) {
throw new IllegalStateException("Rewrite at key " + scriptDescriptor + " for class");
@@ -150,7 +150,8 @@ public class ClosureAnnotator {
@NotNull
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) {
@@ -213,65 +214,90 @@ public class ClosureAnnotator {
return classNameForClassDescriptor(descriptor);
}
public ClassDescriptor getEclosingClassDescriptor(ClassDescriptor descriptor) {
return enclosing.get(descriptor);
public JvmClassName classNameForClassDescriptor(ClassDescriptor descriptor) {
final CalculatedClosure closure = closuresForClassDescriptor.get(descriptor);
return closure == null ? null : closure.getClassName();
}
public boolean hasThis0(ClassDescriptor classDescriptor) {
if (classDescriptor.getKind() == ClassKind.ENUM_CLASS
|| classDescriptor.getKind() == ClassKind.ENUM_ENTRY
|| classDescriptor.getKind() == ClassKind.CLASS_OBJECT) {
public ClassDescriptor getEclosingClassDescriptor(ClassDescriptor descriptor) {
final CalculatedClosure closure = closuresForClassDescriptor.get(descriptor);
return closure == null ? null : closure.getEnclosingClass();
}
public boolean canHaveOuter(ClassDescriptor classDescriptor) {
if (DescriptorUtils.isClassObject(classDescriptor)) {
return false;
}
if (classDescriptor.getKind() == ClassKind.ENUM_CLASS || classDescriptor.getKind() == ClassKind.ENUM_ENTRY) {
return false;
}
ClassDescriptor other = enclosing.get(classDescriptor);
return other != null;
return getEclosingClassDescriptor(classDescriptor) != null;
}
public boolean enumEntryNeedSubclass(JetEnumEntry enumEntry) {
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, enumEntry);
return enumEntryNeedSubclass.get(descriptor);
return Boolean.TRUE.equals(enumEntryNeedSubclass.get(bindingContext.get(BindingContext.CLASS, enumEntry)));
}
public boolean enumEntryNeedSubclass(ClassDescriptor enumEntry) {
Boolean aBoolean = enumEntryNeedSubclass.get(enumEntry);
return aBoolean != null && aBoolean;
return Boolean.TRUE.equals(enumEntryNeedSubclass.get(enumEntry));
}
public void recordLocalClass(ClassDescriptor descriptor, LocalClassClosureCodegen codegen) {
LocalClassClosureCodegen put = localClassCodegenForClass.put(descriptor, codegen);
assert put == null;
public CalculatedClosure getCalculatedClosure(@NotNull ClassDescriptor descriptor) {
//noinspection SuspiciousMethodCalls
return closuresForClassDescriptor.get(descriptor.getOriginal());
}
private class MyJetVisitorVoid extends JetVisitorVoid {
private final LinkedList<ClassDescriptor> classStack = new LinkedList<ClassDescriptor>();
private final LinkedList<String> nameStack = new LinkedList<String>();
private void recordClosure(
@Nullable JetElement element,
ClassDescriptor classDescriptor,
@Nullable ClassDescriptor enclosing,
JvmClassName name,
boolean functionLiteral
) {
final JetDelegatorToSuperCall superCall = CodegenUtil.findSuperCall(element, bindingContext);
private void recordEnclosing(ClassDescriptor classDescriptor) {
if (classStack.size() > 0) {
ClassDescriptor put = enclosing.put(classDescriptor, classStack.peek());
assert put == null;
CallableDescriptor enclosingReceiver = null;
if (classDescriptor.getContainingDeclaration() instanceof CallableDescriptor) {
enclosingReceiver = (CallableDescriptor) classDescriptor.getContainingDeclaration();
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();
Integer cnt = anonymousSubclassesCount.get(top);
if (cnt == null) {
cnt = 0;
}
JvmClassName name = JvmClassName.byInternalName(top + "$" + (cnt + 1));
String name = top + "$" + (cnt + 1);
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, declaration);
if (descriptor == null) {
if (declaration instanceof JetFunctionLiteralExpression || declaration instanceof JetNamedFunction) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.FUNCTION, declaration);
assert declarationDescriptor instanceof FunctionDescriptor;
descriptor = classDescriptorForFunctionDescriptor((FunctionDescriptor) declarationDescriptor);
}
else if (declaration instanceof JetObjectLiteralExpression) {
descriptor =
bindingContext.get(BindingContext.CLASS, ((JetObjectLiteralExpression) declaration).getObjectDeclaration());
assert descriptor != null;
if (declaration instanceof JetFunctionLiteralExpression ||
declaration instanceof JetNamedFunction ||
declaration instanceof JetObjectLiteralExpression) {
}
else {
throw new IllegalStateException(
@@ -279,20 +305,11 @@ public class ClosureAnnotator {
declaration.getClass().getName());
}
}
recordName(descriptor, name);
anonymousSubclassesCount.put(top, cnt + 1);
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
public void visitJetElement(JetElement element) {
super.visitJetElement(element);
@@ -302,6 +319,8 @@ public class ClosureAnnotator {
@Override
public void visitJetFile(JetFile file) {
if (file.isScript()) {
//noinspection ConstantConditions
classStack.push(classDescriptorForScriptDescriptor(bindingContext.get(BindingContext.SCRIPT, file.getScript())));
//noinspection ConstantConditions
nameStack.push(classNameForScriptPsi(file.getScript()).getInternalName());
}
@@ -310,21 +329,39 @@ public class ClosureAnnotator {
}
file.acceptChildren(this);
nameStack.pop();
if (file.isScript()) {
classStack.pop();
}
}
@Override
public void visitEnumEntry(JetEnumEntry enumEntry) {
ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, enumEntry);
enumEntryNeedSubclass.put(descriptor, !enumEntry.getDeclarations().isEmpty());
super.visitEnumEntry(enumEntry);
assert descriptor != null;
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
public void visitClassObject(JetClassObject classObject) {
JvmClassName name = recordClassObject(classObject);
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration());
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);
nameStack.push(name.getInternalName());
super.visitClassObject(classObject);
@@ -341,16 +378,12 @@ public class ClosureAnnotator {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, declaration);
// working around a problem with shallow analysis
if (classDescriptor == null) return;
recordEnclosing(classDescriptor);
String name = getName(classDescriptor);
recordClosure(declaration, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), false);
classStack.push(classDescriptor);
String base = nameStack.peek();
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()));
nameStack.push(name);
super.visitObjectDeclaration(declaration);
nameStack.pop();
classStack.pop();
@@ -362,21 +395,23 @@ public class ClosureAnnotator {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, klass);
// working around a problem with shallow analysis
if (classDescriptor == null) return;
recordEnclosing(classDescriptor);
String name = getName(classDescriptor);
recordClosure(klass, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), false);
classStack.push(classDescriptor);
String base = nameStack.peek();
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()));
nameStack.push(name);
super.visitClass(klass);
nameStack.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
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, expression.getObjectDeclaration());
@@ -385,8 +420,10 @@ public class ClosureAnnotator {
super.visitObjectLiteralExpression(expression);
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);
nameStack.push(classNameForClassDescriptor(classDescriptor).getInternalName());
super.visitObjectLiteralExpression(expression);
@@ -400,11 +437,13 @@ public class ClosureAnnotator {
(FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression);
// working around a problem with shallow analysis
if (functionDescriptor == null) return;
JvmClassName name = recordAnonymousClass(expression);
String name = inventAnonymousClassName(expression);
ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor);
recordEnclosing(classDescriptor);
recordClosure(expression, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), true);
classStack.push(classDescriptor);
nameStack.push(name.getInternalName());
nameStack.push(name);
super.visitFunctionLiteralExpression(expression);
nameStack.pop();
classStack.pop();
@@ -442,26 +481,16 @@ public class ClosureAnnotator {
nameStack.pop();
}
else {
JvmClassName name = recordAnonymousClass(function);
String name = inventAnonymousClassName(function);
ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor);
recordEnclosing(classDescriptor);
recordClosure(function, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), true);
classStack.push(classDescriptor);
nameStack.push(name.getInternalName());
nameStack.push(name);
super.visitNamedFunction(function);
nameStack.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
*/
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;
public class EnclosedValueDescriptor {
public final class EnclosedValueDescriptor {
private final DeclarationDescriptor descriptor;
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.innerValue = innerValue;
this.outerValue = outerValue;
this.type = type;
}
public DeclarationDescriptor getDescriptor() {
@@ -40,7 +44,18 @@ public class EnclosedValueDescriptor {
return innerValue;
}
public StackValue getOuterValue() {
return outerValue;
public Type getType() {
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 alex.tkachman
*/
public enum JvmMethodParameterKind {
VALUE,
THIS,
THIS0,
OUTER,
RECEIVER,
SHARED_VAR,
ENUM_NAME,
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.BuiltinToJavaTypesMapping;
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 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.ClassFileFactory;
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 javax.annotation.PreDestroy;
@@ -28,30 +28,36 @@ public class ArrayGenTest extends CodegenTestCase {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
}
public void testKt238 () throws Exception {
public void testKt238() throws Exception {
blackBoxFile("regressions/kt238.jet");
}
public void testKt326 () throws Exception {
// blackBoxFile("regressions/kt326.jet");
// System.out.println(generateToText());
public void testKt326() throws Exception {
// blackBoxFile("regressions/kt326.jet");
// System.out.println(generateToText());
}
public void testKt779 () throws Exception {
public void testKt779() throws Exception {
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}) })");
Method foo = generateFunction();
Integer[][] invoke = (Integer[][]) foo.invoke(null);
assertEquals(invoke[2].length, 2);
assertEquals(invoke[4].length, 4);
assertEquals(invoke[4][2].intValue(), 239);
try {
Integer[][] invoke = (Integer[][]) foo.invoke(null);
assertEquals(invoke[2].length, 2);
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) })");
Method foo = generateFunction();
Integer[][] invoke = (Integer[][]) foo.invoke(null);
@@ -59,7 +65,7 @@ public class ArrayGenTest extends CodegenTestCase {
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,{\"\"}) })");
Method foo = generateFunction();
Object invoke = foo.invoke(null);
@@ -67,16 +73,16 @@ public class ArrayGenTest extends CodegenTestCase {
assertTrue(invoke instanceof Object[]);
}
public void testCreateMultiGenerics () throws Exception {
// loadText("class L<T>() { val a = Array<T?>(5) } fun foo() = L<Int>.a");
// System.out.println(generateToText());
// Method foo = generateFunction();
// Object invoke = foo.invoke(null);
// System.out.println(invoke.getClass());
// assertTrue(invoke.getClass() == Object[].class);
public void testCreateMultiGenerics() throws Exception {
// loadText("class L<T>() { val a = Array<T?>(5) } fun foo() = L<Int>.a");
// System.out.println(generateToText());
// Method foo = generateFunction();
// Object invoke = foo.invoke(null);
// System.out.println(invoke.getClass());
// 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");
//System.out.println(generateToText());
Method foo = generateFunction();
@@ -85,221 +91,222 @@ public class ArrayGenTest extends CodegenTestCase {
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
foo.invoke(null);
}
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()) } }");
// System.out.println(generateToText());
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()) } }");
// System.out.println(generateToText());
Method foo = generateFunction();
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()) } }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
foo.invoke(null);
}
public void testCollectionPlusAssign () throws Exception {
public void testCollectionPlusAssign() throws Exception {
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] }");
// System.out.println(generateToText());
// System.out.println(generateToText());
Method foo = generateFunction();
assertTrue((Integer)foo.invoke(null) == 12);
assertTrue((Integer) foo.invoke(null) == 12);
}
public void testCollectionAssignGetMultiIndex () throws Exception {
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 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("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());
public void testCollectionAssignGetMultiIndex() throws Exception {
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 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("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");
assertTrue(foo.invoke(null).equals("5"));
}
public void testArrayGetMultiIndex () throws Exception {
public void testArrayGetAssignMultiIndex() throws Exception {
loadText(
"fun box() : String? { val s = Array<String>(1,{ \"\" }); s [1, -1] = \"5\"; return s[-2, 2] }\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());
"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");
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");
assertTrue(foo.invoke(null).equals("5"));
}
public void testMap () throws Exception {
public void testArrayGetMultiIndex() throws Exception {
loadText(
"fun box() : Int? { val s = java.util.HashMap<String,Int?>(); s[\"239\"] = 239; return s[\"239\"] }\n" +
"fun java.util.HashMap<String,Int?>.set(index: String, elem: Int?) { this.put(index, elem) }");
// System.out.println(generateToText());
"fun box() : String? { val s = Array<String>(1,{ \"\" }); s [1, -1] = \"5\"; return s[-2, 2] }\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");
assertTrue((Integer)foo.invoke(null) == 239);
assertTrue(foo.invoke(null).equals("5"));
}
public void testLongDouble () throws Exception {
public void testMap() 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());
"fun box() : Int? { val s = java.util.HashMap<String,Int?>(); s[\"239\"] = 239; return s[\"239\"] }\n" +
"fun java.util.HashMap<String,Int?>.set(index: String, elem: Int?) { this.put(index, elem) }");
// System.out.println(generateToText());
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() {
@@ -308,7 +315,7 @@ public class ArrayGenTest extends CodegenTestCase {
public void testKt602() {
blackBoxFile("regressions/kt602.jet");
// System.out.println(generateToText());
// System.out.println(generateToText());
}
public void testKt950() {
@@ -317,12 +324,12 @@ public class ArrayGenTest extends CodegenTestCase {
public void testKt594() throws Exception {
loadFile("regressions/kt594.jet");
// System.out.println(generateToText());
// System.out.println(generateToText());
blackBox();
}
public void testNonNullArray() throws Exception {
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 {
createEnvironmentWithFullJdk();
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
blackBoxFile("classes/selfcreate.kt");
}
@@ -16,15 +16,9 @@
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.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.Method;
@@ -89,6 +83,19 @@ public class FunctionGenTest extends CodegenTestCase {
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 {
loadText("fun foo(x: Any) = x.equals(\"lala\")");
// System.out.println(generateToText());
@@ -115,6 +122,7 @@ public class FunctionGenTest extends CodegenTestCase {
public void testKt1199() {
blackBoxFile("regressions/kt1199.kt");
System.out.println(generateToText());
}
public void testFunction() throws InvocationTargetException, IllegalAccessException {
@@ -33,7 +33,7 @@ public class LocalClassGenTest extends CodegenTestCase {
}
public void testWithClosure() {
//blackBoxFile("localcls/withclosure.kt");
blackBoxFile("localcls/withclosure.kt");
}
public void testEnum() {
@@ -18,6 +18,7 @@ package org.jetbrains.jet.di;
import com.intellij.openapi.project.Project;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.codegen.context.ClosureAnnotator;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.jet.lang.BuiltinsScopeExtensionMode;
import org.jetbrains.jet.lang.ModuleConfiguration;
@@ -163,15 +164,15 @@ public class AllInjectorsGenerator {
generator.generate("compiler/tests", "org.jetbrains.jet.di", "InjectorForTests");
}
private static void generateInjectorForJavaSemanticServices() throws IOException {
DependencyInjectorGenerator generator = new DependencyInjectorGenerator(false);
// Fields
generator.addPublicField(JavaSemanticServices.class);
generator.addPublicField(JavaDescriptorResolver.class);
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.addPublicField(PsiClassFinderImpl.class);
generator.addField(false, ModuleDescriptor.class, null,
@@ -181,7 +182,7 @@ public class AllInjectorsGenerator {
// Parameters
generator.addPublicParameter(Project.class);
generator.generate("compiler/frontend.java/src", "org.jetbrains.jet.di", "InjectorForJavaSemanticServices");
}
@@ -226,5 +227,4 @@ public class AllInjectorsGenerator {
generator.addPublicParameter(BodiesResolveContext.class);
generator.generate("compiler/frontend/src", "org.jetbrains.jet.di", "InjectorForBodyResolve");
}
}