object literals shared vars
This commit is contained in:
@@ -40,10 +40,10 @@ public abstract class ClassBodyCodegen {
|
||||
public void generate() {
|
||||
generateDeclaration();
|
||||
|
||||
generateSyntheticParts();
|
||||
|
||||
generateClassBody();
|
||||
|
||||
generateSyntheticParts();
|
||||
|
||||
generateStaticInitializer();
|
||||
|
||||
v.visitEnd();
|
||||
|
||||
@@ -4,8 +4,6 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
@@ -25,7 +23,7 @@ public class ClassCodegen {
|
||||
|
||||
generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
|
||||
|
||||
final ClassContext contextForInners = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION);
|
||||
final ClassContext contextForInners = parentContext.intoClass(null, descriptor, OwnerKind.IMPLEMENTATION);
|
||||
for (JetDeclaration declaration : aClass.getDeclarations()) {
|
||||
if (declaration instanceof JetClass && !(declaration instanceof JetEnumEntry)) {
|
||||
generate(contextForInners, (JetClass) declaration);
|
||||
@@ -36,11 +34,11 @@ public class ClassCodegen {
|
||||
private void generateImplementation(ClassContext parentContext, JetClassOrObject aClass, OwnerKind kind) {
|
||||
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
|
||||
ClassVisitor v = state.forClassImplementation(descriptor);
|
||||
new ImplementationBodyCodegen(aClass, parentContext.intoClass(descriptor, kind), v, state).generate();
|
||||
new ImplementationBodyCodegen(aClass, parentContext.intoClass(null, descriptor, kind), v, state).generate();
|
||||
|
||||
if(aClass instanceof JetClass && ((JetClass)aClass).isTrait()) {
|
||||
v = state.forTraitImplementation(descriptor);
|
||||
new TraitImplBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL), v, state).generate();
|
||||
new TraitImplBodyCodegen(aClass, parentContext.intoClass(null, descriptor, OwnerKind.TRAIT_IMPL), v, state).generate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
@@ -14,18 +11,22 @@ import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/*
|
||||
* @author max
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class ClassContext {
|
||||
public static final ClassContext STATIC = new ClassContext(null, OwnerKind.NAMESPACE, null, null, null);
|
||||
private final DeclarationDescriptor contextType;
|
||||
private final OwnerKind contextKind;
|
||||
private final StackValue thisExpression;
|
||||
private final ClassContext parentContext;
|
||||
private final ClosureCodegen closure;
|
||||
public final FunctionOrClosureCodegen closure;
|
||||
private boolean thisWasUsed = false;
|
||||
|
||||
HashMap<JetType,Integer> typeInfoConstants;
|
||||
|
||||
public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression, ClassContext parentContext, ClosureCodegen closureCodegen) {
|
||||
public ClassContext(DeclarationDescriptor contextType, OwnerKind contextKind, StackValue thisExpression, ClassContext parentContext, FunctionOrClosureCodegen closureCodegen) {
|
||||
this.contextType = contextType;
|
||||
this.contextKind = contextKind;
|
||||
this.thisExpression = thisExpression;
|
||||
@@ -60,11 +61,11 @@ public class ClassContext {
|
||||
return new ClassContext(descriptor, OwnerKind.NAMESPACE, null, this, null);
|
||||
}
|
||||
|
||||
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind) {
|
||||
public ClassContext intoClass(FunctionOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind) {
|
||||
final StackValue thisValue;
|
||||
thisValue = StackValue.local(0, JetTypeMapper.TYPE_OBJECT);
|
||||
|
||||
return new ClassContext(descriptor, kind, thisValue, this, null);
|
||||
return new ClassContext(descriptor, kind, thisValue, this, closure);
|
||||
}
|
||||
|
||||
public ClassContext intoFunction(FunctionDescriptor descriptor) {
|
||||
@@ -140,7 +141,7 @@ public class ClassContext {
|
||||
}
|
||||
|
||||
public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v) {
|
||||
final ClosureCodegen top = closure;
|
||||
final FunctionOrClosureCodegen top = closure;
|
||||
if (top != null) {
|
||||
final StackValue answer = top.lookupInContext(d);
|
||||
if (answer != null) return answer;
|
||||
|
||||
@@ -26,19 +26,10 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ClosureCodegen {
|
||||
public final GenerationState state;
|
||||
private final ExpressionCodegen exprContext;
|
||||
private final ClassContext context;
|
||||
private ClassVisitor cv = null;
|
||||
public String name = null;
|
||||
|
||||
private Map<DeclarationDescriptor, EnclosedValueDescriptor> closure = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
|
||||
public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
|
||||
public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, ClassContext context) {
|
||||
this.state = state;
|
||||
this.exprContext = exprContext;
|
||||
this.context = context;
|
||||
super(exprContext, context, state);
|
||||
}
|
||||
|
||||
public static Method erasedInvokeSignature(FunctionDescriptor fd) {
|
||||
@@ -57,33 +48,6 @@ public class ClosureCodegen {
|
||||
return state.getTypeMapper().mapSignature("invoke", fd);
|
||||
}
|
||||
|
||||
public StackValue lookupInContext(DeclarationDescriptor d) {
|
||||
if (d instanceof VariableDescriptor) {
|
||||
VariableDescriptor vd = (VariableDescriptor) d;
|
||||
|
||||
EnclosedValueDescriptor answer = closure.get(vd);
|
||||
if (answer != null) return answer.getInnerValue();
|
||||
|
||||
final int idx = exprContext.lookupLocal(vd);
|
||||
if (idx < 0) return null;
|
||||
|
||||
final Type sharedVarType = exprContext.getSharedVarType(vd);
|
||||
Type localType = state.getTypeMapper().mapType(vd.getOutType());
|
||||
final Type type = sharedVarType != null ? sharedVarType : localType;
|
||||
|
||||
StackValue outerValue = StackValue.local(idx, type);
|
||||
final String fieldName = "$" + (closure.size() + 1); // + "$" + vd.getName();
|
||||
StackValue innerValue = sharedVarType != null ? StackValue.fieldForSharedVar(localType, name, fieldName) : StackValue.field(type, name, fieldName, false);
|
||||
cv.visitField(Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null);
|
||||
answer = new EnclosedValueDescriptor(d, innerValue, outerValue);
|
||||
closure.put(d, answer);
|
||||
|
||||
return innerValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public GeneratedAnonymousClassDescriptor gen(JetFunctionLiteralExpression fun) {
|
||||
final Pair<String, ClassVisitor> nameAndVisitor = state.forAnonymousSubclass(fun);
|
||||
|
||||
|
||||
@@ -566,14 +566,27 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
@Override
|
||||
public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) {
|
||||
GeneratedAnonymousClassDescriptor descriptor = state.generateObjectLiteral(expression, this, context);
|
||||
Type type = Type.getObjectType(descriptor.getClassname());
|
||||
FunctionOrClosureCodegen closureCodegen = new FunctionOrClosureCodegen(this, context, state);
|
||||
GeneratedAnonymousClassDescriptor closure = state.generateObjectLiteral(expression, closureCodegen);
|
||||
Type type = Type.getObjectType(closure.getClassname());
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
String jvmDescriptor = descriptor.getConstructor().getDescriptor().replace("(","(" + typeMapper.jetImplementationType((ClassDescriptor) contextType()));
|
||||
v.invokespecial(descriptor.getClassname(), "<init>", jvmDescriptor);
|
||||
return StackValue.onStack(type);
|
||||
final List<Type> consArgTypes = new LinkedList<Type>(Arrays.asList(closure.getConstructor().getArgumentTypes()));
|
||||
|
||||
if (consArgTypes.size() > 0) {
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
|
||||
for (DeclarationDescriptor descriptor : closureCodegen.closure.keySet()) {
|
||||
final Type sharedVarType = getSharedVarType(descriptor);
|
||||
consArgTypes.add(sharedVarType != null ? sharedVarType : state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType()));
|
||||
final EnclosedValueDescriptor valueDescriptor = closureCodegen.closure.get(descriptor);
|
||||
valueDescriptor.getOuterValue().put(sharedVarType, v);
|
||||
}
|
||||
|
||||
Method cons = new Method("<init>", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()]));
|
||||
v.invokespecial(closure.getClassname(), "<init>", cons.getDescriptor());
|
||||
return StackValue.onStack(Type.getObjectType(closure.getClassname()));
|
||||
}
|
||||
|
||||
Type getSharedVarType(DeclarationDescriptor variableDescriptor) {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class FunctionOrClosureCodegen {
|
||||
public final GenerationState state;
|
||||
protected final ExpressionCodegen exprContext;
|
||||
protected final ClassContext context;
|
||||
protected ClassVisitor cv = null;
|
||||
public String name = null;
|
||||
protected Map<DeclarationDescriptor, EnclosedValueDescriptor> closure = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
|
||||
|
||||
public FunctionOrClosureCodegen(ExpressionCodegen exprContext, ClassContext context, GenerationState state) {
|
||||
this.exprContext = exprContext;
|
||||
this.context = context;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public StackValue lookupInContext(DeclarationDescriptor d) {
|
||||
if (d instanceof VariableDescriptor) {
|
||||
VariableDescriptor vd = (VariableDescriptor) d;
|
||||
|
||||
EnclosedValueDescriptor answer = closure.get(vd);
|
||||
if (answer != null) return answer.getInnerValue();
|
||||
|
||||
final int idx = exprContext.lookupLocal(vd);
|
||||
if (idx < 0) return null;
|
||||
|
||||
final Type sharedVarType = exprContext.getSharedVarType(vd);
|
||||
Type localType = state.getTypeMapper().mapType(vd.getOutType());
|
||||
final Type type = sharedVarType != null ? sharedVarType : localType;
|
||||
|
||||
StackValue outerValue = StackValue.local(idx, type);
|
||||
final String fieldName = "$" + (closure.size() + 1); // + "$" + vd.getName();
|
||||
StackValue innerValue = sharedVarType != null ? StackValue.fieldForSharedVar(localType, name, fieldName) : StackValue.field(type, name, fieldName, false);
|
||||
|
||||
cv.visitField(Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null);
|
||||
|
||||
answer = new EnclosedValueDescriptor(d, innerValue, outerValue);
|
||||
closure.put(d, answer);
|
||||
|
||||
return innerValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
@@ -120,13 +121,19 @@ public class GenerationState {
|
||||
}
|
||||
}
|
||||
|
||||
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen context, ClassContext classContext) {
|
||||
Pair<String, ClassVisitor> nameAndVisitor = forAnonymousSubclass(literal.getObjectDeclaration());
|
||||
public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, FunctionOrClosureCodegen closure) {
|
||||
JetObjectDeclaration objectDeclaration = literal.getObjectDeclaration();
|
||||
Pair<String, ClassVisitor> nameAndVisitor = forAnonymousSubclass(objectDeclaration);
|
||||
|
||||
final ClassContext objectContext = classContext.intoClass(getBindingContext().get(BindingContext.CLASS, literal.getObjectDeclaration()), OwnerKind.IMPLEMENTATION);
|
||||
closure.cv = nameAndVisitor.getSecond();
|
||||
closure.name = nameAndVisitor.getFirst();
|
||||
final ClassContext objectContext = closure.context.intoClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION);
|
||||
|
||||
new ImplementationBodyCodegen(literal.getObjectDeclaration(), objectContext, nameAndVisitor.getSecond(), this).generate();
|
||||
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, new Method("<init>", "()V"), false);
|
||||
new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate();
|
||||
|
||||
ConstructorDescriptor constructorDescriptor = closure.state.getBindingContext().get(BindingContext.CONSTRUCTOR, objectDeclaration);
|
||||
CallableMethod callableMethod = closure.state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
||||
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, callableMethod.getSignature(), false);
|
||||
}
|
||||
|
||||
public static void prepareAnonymousClasses(JetElement aClass, final JetTypeMapper typeMapper) {
|
||||
|
||||
@@ -225,6 +225,22 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
callableMethod = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, kind);
|
||||
method = callableMethod.getSignature();
|
||||
}
|
||||
|
||||
int firstClosureIndex = -1;
|
||||
if(context.closure != null) {
|
||||
final List<Type> consArgTypes = new LinkedList<Type>(Arrays.asList(method.getArgumentTypes()));
|
||||
|
||||
firstClosureIndex = consArgTypes.size()+1;
|
||||
|
||||
Map<DeclarationDescriptor, EnclosedValueDescriptor> closure = context.closure.closure;
|
||||
for (DeclarationDescriptor descriptor : closure.keySet()) {
|
||||
final Type sharedVarType = context.closure.exprContext.getSharedVarType(descriptor);
|
||||
consArgTypes.add(sharedVarType != null ? sharedVarType : state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType()));
|
||||
}
|
||||
|
||||
method = new Method("<init>", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()]));
|
||||
}
|
||||
|
||||
int flags = Opcodes.ACC_PUBLIC; // TODO
|
||||
final MethodVisitor mv = v.visitMethod(flags, "<init>", method.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
@@ -300,7 +316,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
iv.putfield(classname, delegateField, fieldDesc);
|
||||
|
||||
JetClass superClass = (JetClass) state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor);
|
||||
final ClassContext delegateContext = context.intoClass(superClassDescriptor,
|
||||
final ClassContext delegateContext = context.intoClass(null, superClassDescriptor,
|
||||
new OwnerKind.DelegateKind(StackValue.field(fieldType, classname, delegateField, false),
|
||||
JetTypeMapper.jvmNameForInterface(superClassDescriptor)));
|
||||
generateDelegates(superClass, delegateContext, overridden);
|
||||
@@ -322,6 +338,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
generateTypeInfoInitializer(frameMap.getFirstTypeParameter(), frameMap.getTypeParameterCount(), iv);
|
||||
}
|
||||
|
||||
if(context.closure != null) {
|
||||
Map<DeclarationDescriptor, EnclosedValueDescriptor> closure = context.closure.closure;
|
||||
int k = 0;
|
||||
for (DeclarationDescriptor varDescr : closure.keySet()) {
|
||||
final Type sharedVarType = context.closure.exprContext.getSharedVarType(varDescr);
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
iv.load(firstClosureIndex + k, StackValue.refType(sharedVarType));
|
||||
iv.putfield(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$" + (k+1), sharedVarType.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
generateInitializers(codegen, iv);
|
||||
|
||||
generateTraitMethods(codegen);
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
class C() {
|
||||
val child = object {
|
||||
fun toString(): String = "child"
|
||||
class C(x: Int, val y : Int) {
|
||||
fun initChild(x: Int) : java.lang.Object {
|
||||
return object : java.lang.Object() {
|
||||
override fun toString(): String? {
|
||||
x = x + y
|
||||
return "child" + x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val child = initChild(x)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
return if (c.child.toString() == "child") "OK" else "fail"
|
||||
val c = C(10,3)
|
||||
return if (c.child.toString() == "child13" && c.child.toString() == "child16" && c.child.toString() == "child19") "OK" else "fail"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/*
|
||||
fun s0() : Boolean {
|
||||
val y = "222"
|
||||
val foo = {
|
||||
@@ -159,8 +160,22 @@ fun t11(x: Int) : Int {
|
||||
}
|
||||
return x
|
||||
}
|
||||
*/
|
||||
fun t12(x: Int) : Int {
|
||||
var y = x
|
||||
val runnable = object : Runnable {
|
||||
override fun run () {
|
||||
y = y + 1
|
||||
}
|
||||
}
|
||||
while(y < 100) {
|
||||
runnable.run()
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
/*
|
||||
if (!s0()) return "fail"
|
||||
if (!s1()) return "fail"
|
||||
if (!t1()) return "fail"
|
||||
@@ -174,6 +189,8 @@ fun box(): String {
|
||||
if (!t9(0)) return "fail"
|
||||
if (!t10()) return "fail"
|
||||
if (t11(1) != 104) return "fail"
|
||||
*/
|
||||
if (t12(0) != 100) return "fail"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -10,6 +10,7 @@ public class ObjectGenTest extends CodegenTestCase {
|
||||
|
||||
public void testObjectLiteral() throws Exception {
|
||||
blackBoxFile("objects/objectLiteral.jet");
|
||||
System.out.println(generateToText());
|
||||
}
|
||||
|
||||
public void testMethodOnObject() throws Exception {
|
||||
|
||||
@@ -19,7 +19,7 @@ public class PropertyGenTest extends CodegenTestCase {
|
||||
final Class aClass = loadImplementationClass(generateClassesInFile(), "PrivateVal");
|
||||
final Field[] fields = aClass.getDeclaredFields();
|
||||
assertEquals(2, fields.length); // $typeInfo, prop
|
||||
final Field field = fields[1];
|
||||
final Field field = fields[0];
|
||||
assertEquals("prop", field.getName());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user