提交 ada54665 编写于 作者: A Alex Tkachman

closure shared vars

上级 7831fc3d
...@@ -146,7 +146,15 @@ public class ClassContext { ...@@ -146,7 +146,15 @@ public class ClassContext {
if (answer != null) return answer; if (answer != null) return answer;
final StackValue thisContext = getThisExpression(); final StackValue thisContext = getThisExpression();
thisContext.put(thisContext.type, v); if(thisContext instanceof StackValue.Local) {
}
else if(thisContext instanceof StackValue.InstanceField) {
StackValue.InstanceField instanceField = (StackValue.InstanceField) thisContext;
v.getfield(instanceField.owner, instanceField.name, instanceField.type.getDescriptor());
}
else {
throw new UnsupportedOperationException();
}
} }
return parentContext != null ? parentContext.lookupInContext(d, v) : null; return parentContext != null ? parentContext.lookupInContext(d, v) : null;
......
...@@ -67,11 +67,13 @@ public class ClosureCodegen { ...@@ -67,11 +67,13 @@ public class ClosureCodegen {
final int idx = exprContext.lookupLocal(vd); final int idx = exprContext.lookupLocal(vd);
if (idx < 0) return null; if (idx < 0) return null;
final Type type = state.getTypeMapper().mapType(vd.getOutType()); 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); StackValue outerValue = StackValue.local(idx, type);
final String fieldName = "$" + (closure.size() + 1); final String fieldName = "$" + (closure.size() + 1); // + "$" + vd.getName();
StackValue innerValue = StackValue.field(type, name, fieldName, false); 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); cv.visitField(Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null);
answer = new EnclosedValueDescriptor(d, innerValue, outerValue); answer = new EnclosedValueDescriptor(d, innerValue, outerValue);
closure.put(d, answer); closure.put(d, answer);
...@@ -120,7 +122,7 @@ public class ClosureCodegen { ...@@ -120,7 +122,7 @@ public class ClosureCodegen {
final Method constructor = generateConstructor(funClass, captureThis, funDescriptor.getReturnType()); final Method constructor = generateConstructor(funClass, captureThis, funDescriptor.getReturnType());
if (captureThis) { if (captureThis) {
cv.visitField(Opcodes.ACC_PRIVATE, "this$0", enclosingType.getDescriptor(), null, null); cv.visitField(0, "this$0", enclosingType.getDescriptor(), null, null);
} }
cv.visitEnd(); cv.visitEnd();
...@@ -192,7 +194,9 @@ public class ClosureCodegen { ...@@ -192,7 +194,9 @@ public class ClosureCodegen {
} }
for (DeclarationDescriptor descriptor : closure.keySet()) { for (DeclarationDescriptor descriptor : closure.keySet()) {
argTypes[i++] = state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType()); final Type sharedVarType = exprContext.getSharedVarType(descriptor);
final Type type = sharedVarType != null ? sharedVarType : state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType());
argTypes[i++] = type;
} }
final Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); final Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
......
...@@ -551,7 +551,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { ...@@ -551,7 +551,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
final Method cons = closure.getConstructor(); final Method cons = closure.getConstructor();
if (closure.isCaptureThis()) { if (closure.isCaptureThis()) {
thisToStack(); v.load(0, JetTypeMapper.TYPE_OBJECT);
} }
for (int i = 0; i < closure.getArgs().size(); i++) { for (int i = 0; i < closure.getArgs().size(); i++) {
...@@ -576,6 +576,20 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { ...@@ -576,6 +576,20 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return StackValue.onStack(type); return StackValue.onStack(type);
} }
Type getSharedVarType(DeclarationDescriptor variableDescriptor) {
if(!(variableDescriptor instanceof VariableDescriptor))
return null;
Boolean aBoolean = bindingContext.get(BindingContext.MUST_BE_WRAPPED_IN_A_REF, (VariableDescriptor) variableDescriptor);
if (aBoolean != null && aBoolean) {
JetType outType = ((VariableDescriptor) variableDescriptor).getOutType();
return StackValue.sharedTypeForType(typeMapper.mapType(outType));
}
else {
return null;
}
}
private StackValue generateBlock(List<JetElement> statements) { private StackValue generateBlock(List<JetElement> statements) {
Label blockStart = new Label(); Label blockStart = new Label();
v.mark(blockStart); v.mark(blockStart);
...@@ -584,7 +598,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { ...@@ -584,7 +598,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (statement instanceof JetProperty) { if (statement instanceof JetProperty) {
final VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, statement); final VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, statement);
assert variableDescriptor != null; assert variableDescriptor != null;
final Type type = typeMapper.mapType(variableDescriptor.getOutType());
final Type sharedVarType = getSharedVarType(variableDescriptor);
final Type type = sharedVarType != null ? sharedVarType : typeMapper.mapType(variableDescriptor.getOutType());
myMap.enter(variableDescriptor, type.getSize()); myMap.enter(variableDescriptor, type.getSize());
} }
} }
...@@ -608,10 +624,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { ...@@ -608,10 +624,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
JetProperty var = (JetProperty) statement; JetProperty var = (JetProperty) statement;
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var); VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var);
assert variableDescriptor != null; assert variableDescriptor != null;
Type outType = typeMapper.mapType(variableDescriptor.getOutType());
int index = myMap.leave(variableDescriptor); int index = myMap.leave(variableDescriptor);
v.visitLocalVariable(var.getName(), outType.getDescriptor(), null, blockStart, blockEnd, index);
final Type sharedVarType = getSharedVarType(variableDescriptor);
final Type type = sharedVarType != null ? sharedVarType : typeMapper.mapType(variableDescriptor.getOutType());
if(sharedVarType != null) {
v.aconst(null);
v.store(index, JetTypeMapper.TYPE_OBJECT);
}
v.visitLocalVariable(var.getName(), type.getDescriptor(), null, blockStart, blockEnd, index);
} }
} }
...@@ -699,8 +722,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { ...@@ -699,8 +722,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
else { else {
int index = lookupLocal(descriptor); int index = lookupLocal(descriptor);
if (index >= 0) { if (index >= 0) {
Type sharedVarType = getSharedVarType(descriptor);
final JetType outType = ((VariableDescriptor) descriptor).getOutType(); final JetType outType = ((VariableDescriptor) descriptor).getOutType();
return StackValue.local(index, typeMapper.mapType(outType)); if(sharedVarType != null) {
return StackValue.shared(index, typeMapper.mapType(outType));
}
else {
return StackValue.local(index, typeMapper.mapType(outType));
}
} }
else if (descriptor instanceof PropertyDescriptor) { else if (descriptor instanceof PropertyDescriptor) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
...@@ -785,6 +814,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { ...@@ -785,6 +814,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (value == null) { if (value == null) {
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor); throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
} }
if(value instanceof StackValue.FieldForSharedVar) {
StackValue.FieldForSharedVar fieldForSharedVar = (StackValue.FieldForSharedVar) value;
Type sharedType = StackValue.sharedTypeForType(value.type);
v.visitFieldInsn(Opcodes.GETFIELD, fieldForSharedVar.owner, fieldForSharedVar.name, sharedType.getDescriptor());
}
return value; return value;
} }
} }
...@@ -1617,12 +1652,27 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> { ...@@ -1617,12 +1652,27 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
assert index >= 0; assert index >= 0;
final Type sharedVarType = getSharedVarType(variableDescriptor);
assert variableDescriptor != null;
Type varType = typeMapper.mapType(variableDescriptor.getOutType());
if(sharedVarType != null) {
v.anew(sharedVarType);
v.dup();
v.invokespecial(sharedVarType.getInternalName(), "<init>", "()V");
v.store(index, JetTypeMapper.TYPE_OBJECT);
}
JetExpression initializer = property.getInitializer(); JetExpression initializer = property.getInitializer();
if (initializer != null) { if (initializer != null) {
assert variableDescriptor != null; if(sharedVarType == null) {
Type type = typeMapper.mapType(variableDescriptor.getOutType()); gen(initializer, varType);
gen(initializer, type); v.store(index, varType);
v.store(index, type); }
else {
v.load(index, JetTypeMapper.TYPE_OBJECT);
gen(initializer, varType);
v.putfield(sharedVarType.getInternalName(), "ref", sharedVarType == JetTypeMapper.TYPE_SHARED_VAR ? "Ljava/lang/Object;" : varType.getDescriptor());
}
} }
return StackValue.none(); return StackValue.none();
} }
......
...@@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen; ...@@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen;
import gnu.trove.TObjectIntHashMap; import gnu.trove.TObjectIntHashMap;
import gnu.trove.TObjectIntIterator; import gnu.trove.TObjectIntIterator;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
......
...@@ -98,6 +98,23 @@ public class FunctionCodegen { ...@@ -98,6 +98,23 @@ public class FunctionCodegen {
iv.areturn(jvmSignature.getReturnType()); iv.areturn(jvmSignature.getReturnType());
} }
else { else {
for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i);
Type sharedVarType = codegen.getSharedVarType(parameter);
Type localVarType = state.getTypeMapper().mapType(parameter.getOutType());
if(sharedVarType != null) {
int index = frameMap.getIndex(parameter);
mv.visitTypeInsn(Opcodes.NEW, sharedVarType.getInternalName());
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, sharedVarType.getInternalName(), "<init>", "()V");
mv.visitVarInsn(localVarType.getOpcode(Opcodes.ILOAD), index);
mv.visitFieldInsn(Opcodes.PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor());
mv.visitVarInsn(sharedVarType.getOpcode(Opcodes.ISTORE), index);
}
}
codegen.returnExpression(bodyExpressions); codegen.returnExpression(bodyExpressions);
} }
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
......
...@@ -59,6 +59,15 @@ public class JetTypeMapper { ...@@ -59,6 +59,15 @@ public class JetTypeMapper {
public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1");
public static final Type TYPE_ITERATOR = Type.getObjectType("jet/Iterator"); public static final Type TYPE_ITERATOR = Type.getObjectType("jet/Iterator");
public static final Type TYPE_INT_RANGE = Type.getObjectType("jet/IntRange"); public static final Type TYPE_INT_RANGE = Type.getObjectType("jet/IntRange");
public static final Type TYPE_SHARED_VAR = Type.getObjectType("jet/refs/SharedVar$Object");
public static final Type TYPE_SHARED_INT = Type.getObjectType("jet/refs/SharedVar$Int");
public static final Type TYPE_SHARED_DOUBLE = Type.getObjectType("jet/refs/SharedVar$Double");
public static final Type TYPE_SHARED_FLOAT = Type.getObjectType("jet/refs/SharedVar$Float");
public static final Type TYPE_SHARED_BYTE = Type.getObjectType("jet/refs/SharedVar$Byte");
public static final Type TYPE_SHARED_SHORT = Type.getObjectType("jet/refs/SharedVar$Short");
public static final Type TYPE_SHARED_CHAR = Type.getObjectType("jet/refs/SharedVar$Char");
public static final Type TYPE_SHARED_LONG = Type.getObjectType("jet/refs/SharedVar$Long");
public static final Type TYPE_SHARED_BOOLEAN = Type.getObjectType("jet/refs/SharedVar$Boolean");
public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) {
this.standardLibrary = standardLibrary; this.standardLibrary = standardLibrary;
......
...@@ -11,6 +11,7 @@ import org.objectweb.asm.commons.Method; ...@@ -11,6 +11,7 @@ import org.objectweb.asm.commons.Method;
/** /**
* @author yole * @author yole
* @author alex.tkachman
*/ */
public abstract class StackValue { public abstract class StackValue {
public final Type type; public final Type type;
...@@ -59,6 +60,10 @@ public abstract class StackValue { ...@@ -59,6 +60,10 @@ public abstract class StackValue {
return new Local(index, type); return new Local(index, type);
} }
public static StackValue shared(int index, Type type) {
return new Shared(index, type);
}
public static StackValue onStack(Type type) { public static StackValue onStack(Type type) {
return type == Type.VOID_TYPE ? none() : new OnStack(type); return type == Type.VOID_TYPE ? none() : new OnStack(type);
} }
...@@ -225,7 +230,11 @@ public abstract class StackValue { ...@@ -225,7 +230,11 @@ public abstract class StackValue {
public static StackValue none() { public static StackValue none() {
return None.INSTANCE; return None.INSTANCE;
} }
public static StackValue fieldForSharedVar(Type type, String name, String fieldName) {
return new FieldForSharedVar(type, name, fieldName);
}
private static class None extends StackValue { private static class None extends StackValue {
public static None INSTANCE = new None(); public static None INSTANCE = new None();
private None() { private None() {
...@@ -496,9 +505,9 @@ public abstract class StackValue { ...@@ -496,9 +505,9 @@ public abstract class StackValue {
} }
private static class Field extends StackValue { static class Field extends StackValue {
private final String owner; final String owner;
private final String name; final String name;
private final boolean isStatic; private final boolean isStatic;
public Field(Type type, String owner, String name, boolean isStatic) { public Field(Type type, String owner, String name, boolean isStatic) {
...@@ -531,9 +540,9 @@ public abstract class StackValue { ...@@ -531,9 +540,9 @@ public abstract class StackValue {
} }
} }
private static class InstanceField extends StackValue { static class InstanceField extends StackValue {
private final String owner; final String owner;
private final String name; final String name;
public InstanceField(Type type, String owner, String name) { public InstanceField(Type type, String owner, String name) {
super(type); super(type);
...@@ -625,4 +634,106 @@ public abstract class StackValue { ...@@ -625,4 +634,106 @@ public abstract class StackValue {
generator.gen(expression, type); generator.gen(expression, type);
} }
} }
public static class Shared extends StackValue {
private final int index;
public Shared(int index, Type type) {
super(type);
this.index = index;
}
@Override
public void put(Type type, InstructionAdapter v) {
v.load(index, JetTypeMapper.TYPE_OBJECT);
Type refType = refType(this.type);
Type sharedType = sharedTypeForType(this.type);
v.visitFieldInsn(Opcodes.GETFIELD, sharedType.getInternalName(), "ref", refType.getDescriptor());
StackValue.onStack(refType).coerce(this.type, v);
StackValue.onStack(this.type).coerce(type, v);
}
@Override
public void store(InstructionAdapter v) {
v.load(index, JetTypeMapper.TYPE_OBJECT);
v.swap();
Type refType = refType(this.type);
Type sharedType = sharedTypeForType(this.type);
v.visitFieldInsn(Opcodes.PUTFIELD, sharedType.getInternalName(), "ref", refType.getDescriptor());
}
}
public static Type sharedTypeForType(Type type) {
switch(type.getSort()) {
case Type.OBJECT:
case Type.ARRAY:
return JetTypeMapper.TYPE_SHARED_VAR;
case Type.BYTE:
return JetTypeMapper.TYPE_SHARED_BYTE;
case Type.SHORT:
return JetTypeMapper.TYPE_SHARED_SHORT;
case Type.CHAR:
return JetTypeMapper.TYPE_SHARED_CHAR;
case Type.INT:
return JetTypeMapper.TYPE_SHARED_INT;
case Type.BOOLEAN:
return JetTypeMapper.TYPE_SHARED_BOOLEAN;
case Type.FLOAT:
return JetTypeMapper.TYPE_SHARED_FLOAT;
case Type.DOUBLE:
return JetTypeMapper.TYPE_SHARED_DOUBLE;
default:
throw new UnsupportedOperationException();
}
}
public static Type refType(Type type) {
if(type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY)
return JetTypeMapper.TYPE_OBJECT;
return type;
}
static class FieldForSharedVar extends StackValue {
final String owner;
final String name;
public FieldForSharedVar(Type type, String owner, String name) {
super(type);
this.owner = owner;
this.name = name;
}
@Override
public void dupReceiver(InstructionAdapter v, int below) {
if (below == 1) {
v.dupX1();
}
else {
v.dup();
}
}
@Override
public void put(Type type, InstructionAdapter v) {
Type sharedType = sharedTypeForType(this.type);
Type refType = refType(this.type);
v.visitFieldInsn(Opcodes.GETFIELD, sharedType.getInternalName(), "ref", refType.getDescriptor());
StackValue.onStack(refType).coerce(this.type, v);
StackValue.onStack(this.type).coerce(type, v);
}
@Override
public void store(InstructionAdapter v) {
v.visitFieldInsn(Opcodes.PUTFIELD, sharedTypeForType(type).getInternalName(), "ref", refType(type).getDescriptor());
}
}
} }
fun box() : String { fun box() : String {
val cl = 39 val cl = 39
return if (sum(200, { cl }) == 239) "OK" else "FAIL" return if (sum(200, { val m = { val r = { cl }; r() }; m() }) == 239) "OK" else "FAIL"
} }
fun sum(arg:Int, f : fun () : Int) : Int { fun sum(arg:Int, f : fun () : Int) : Int {
......
fun s0() : Boolean {
val y = "222"
val foo = {
val bar = { y }
bar ()
}
return foo() == "222"
}
fun s1() : Boolean {
var x = "222"
val foo = {
val bar = {
x = "aaa"
}
bar ()
}
foo()
return x == "aaa"
}
fun t1() : Boolean {
var x = "111"
val y = x + "22"
val foo = {
x = x + "45" + y
x = x.substring(3)
x += "aaa"
()
}
foo()
x += "bbb"
System.out?.println(x)
return x == "4511122aaabbb"
}
fun t2() : Boolean {
var x = 111
val y = x + 22
val foo = {
x = x + 5 + y
x += 5
x++
()
}
foo()
x -= 55
System.out?.println(x)
return x == 200
}
fun t3() : Boolean {
var x = true
val foo = {
x = false
()
}
foo()
return !x
}
fun t4() : Boolean {
var x = 100.flt
val y = x + 22
val foo = {
x = x + 200.flt + y
x += 18
()
}
foo()
System.out?.println(x)
return x == 440.flt
}
fun t5() : Boolean {
var x = 100.dbl
val y = x + 22
val foo = {
x = x + 200.dbl + y
x -= 22
()
}
foo()
System.out?.println(x)
return x == 400.dbl
}
fun t6() : Boolean {
var x = 20.byt
val y = x + 22
val foo = {
x = (x + 20.byt + y).byt
x += 2
x--
()
}
foo()
System.out?.println(x)
return x == 83.byt
}
fun t7() : Boolean {
var x : Char = 'a'
val foo = {
x = 'b'
()
}
foo()
System.out?.println(x)
return x == 'b'
}
fun t8() : Boolean {
var x = 20.sht
val foo = {
val bar = {
x = 30.sht
()
}
bar()
()
}
foo()
return x == 30.sht
}
fun t9(x: Int) : Boolean {
while(x < 100) {
x++
}
return x == 100
}
fun t10() : Boolean {
var y = 1
val foo = {
val bar = {
y = y + 1
}
bar()
}
foo()
return y == 2
}
fun t11(x: Int) : Int {
val foo = {
x = x + 1
val bar = {
x = x + 1
x += 3
}
bar()
}
while(x < 100) {
foo()
}
return x
}
fun box(): String {
if (!s0()) return "fail"
if (!s1()) return "fail"
if (!t1()) return "fail"
if (!t2()) return "fail"
if (!t3()) return "fail"
if (!t4()) return "fail"
if (!t5()) return "fail"
if (!t6()) return "fail"
if (!t7()) return "fail"
if (!t8()) return "fail"
if (!t9(0)) return "fail"
if (!t10()) return "fail"
if (t11(1) != 104) return "fail"
return "OK"
}
\ No newline at end of file
...@@ -190,4 +190,10 @@ public class ClassGenTest extends CodegenTestCase { ...@@ -190,4 +190,10 @@ public class ClassGenTest extends CodegenTestCase {
blackBoxFile("regressions/kt343.jet"); blackBoxFile("regressions/kt343.jet");
System.out.println(generateToText()); System.out.println(generateToText());
} }
public void testKt344 () throws Exception {
loadFile("regressions/kt344.jet");
System.out.println(generateToText());
blackBox();
}
} }
...@@ -27,6 +27,7 @@ public class ClosuresGenTest extends CodegenTestCase { ...@@ -27,6 +27,7 @@ public class ClosuresGenTest extends CodegenTestCase {
public void testEnclosingLocalVariable() throws Exception { public void testEnclosingLocalVariable() throws Exception {
blackBoxFile("classes/enclosingLocalVariable.jet"); blackBoxFile("classes/enclosingLocalVariable.jet");
System.out.println(generateToText());
} }
public void testDoubleEnclosedLocalVariable() throws Exception { public void testDoubleEnclosedLocalVariable() throws Exception {
......
package jet.refs;
public final class SharedVar {
public static final class Object<T> {
public T ref;
}
public static final class Byte {
public byte ref;
}
public static final class Short {
public short ref;
}
public static final class Int {
public int ref;
}
public static final class Long {
public long ref;
}
public static final class Float {
public float ref;
}
public static final class Double {
public double ref;
}
public static final class Char {
public char ref;
}
public static final class Boolean {
public boolean ref;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册