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

closure shared vars

上级 7831fc3d
......@@ -146,7 +146,15 @@ public class ClassContext {
if (answer != null) return answer;
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;
......
......@@ -67,11 +67,13 @@ public class ClosureCodegen {
final int idx = exprContext.lookupLocal(vd);
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);
final String fieldName = "$" + (closure.size() + 1);
StackValue innerValue = StackValue.field(type, name, fieldName, false);
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);
......@@ -120,7 +122,7 @@ public class ClosureCodegen {
final Method constructor = generateConstructor(funClass, captureThis, funDescriptor.getReturnType());
if (captureThis) {
cv.visitField(Opcodes.ACC_PRIVATE, "this$0", enclosingType.getDescriptor(), null, null);
cv.visitField(0, "this$0", enclosingType.getDescriptor(), null, null);
}
cv.visitEnd();
......@@ -192,7 +194,9 @@ public class ClosureCodegen {
}
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);
......
......@@ -551,7 +551,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
final Method cons = closure.getConstructor();
if (closure.isCaptureThis()) {
thisToStack();
v.load(0, JetTypeMapper.TYPE_OBJECT);
}
for (int i = 0; i < closure.getArgs().size(); i++) {
......@@ -576,6 +576,20 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
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) {
Label blockStart = new Label();
v.mark(blockStart);
......@@ -584,7 +598,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (statement instanceof JetProperty) {
final VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, statement);
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());
}
}
......@@ -608,10 +624,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
JetProperty var = (JetProperty) statement;
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var);
assert variableDescriptor != null;
Type outType = typeMapper.mapType(variableDescriptor.getOutType());
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> {
else {
int index = lookupLocal(descriptor);
if (index >= 0) {
Type sharedVarType = getSharedVarType(descriptor);
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) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
......@@ -785,6 +814,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (value == null) {
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;
}
}
......@@ -1617,12 +1652,27 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
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();
if (initializer != null) {
assert variableDescriptor != null;
Type type = typeMapper.mapType(variableDescriptor.getOutType());
gen(initializer, type);
v.store(index, type);
if(sharedVarType == null) {
gen(initializer, varType);
v.store(index, varType);
}
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();
}
......
......@@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen;
import gnu.trove.TObjectIntHashMap;
import gnu.trove.TObjectIntIterator;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.ArrayList;
import java.util.List;
......
......@@ -98,6 +98,23 @@ public class FunctionCodegen {
iv.areturn(jvmSignature.getReturnType());
}
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);
}
mv.visitMaxs(0, 0);
......
......@@ -59,6 +59,15 @@ public class JetTypeMapper {
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_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) {
this.standardLibrary = standardLibrary;
......
......@@ -11,6 +11,7 @@ import org.objectweb.asm.commons.Method;
/**
* @author yole
* @author alex.tkachman
*/
public abstract class StackValue {
public final Type type;
......@@ -59,6 +60,10 @@ public abstract class StackValue {
return new Local(index, type);
}
public static StackValue shared(int index, Type type) {
return new Shared(index, type);
}
public static StackValue onStack(Type type) {
return type == Type.VOID_TYPE ? none() : new OnStack(type);
}
......@@ -225,7 +230,11 @@ public abstract class StackValue {
public static StackValue none() {
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 {
public static None INSTANCE = new None();
private None() {
......@@ -496,9 +505,9 @@ public abstract class StackValue {
}
private static class Field extends StackValue {
private final String owner;
private final String name;
static class Field extends StackValue {
final String owner;
final String name;
private final boolean isStatic;
public Field(Type type, String owner, String name, boolean isStatic) {
......@@ -531,9 +540,9 @@ public abstract class StackValue {
}
}
private static class InstanceField extends StackValue {
private final String owner;
private final String name;
static class InstanceField extends StackValue {
final String owner;
final String name;
public InstanceField(Type type, String owner, String name) {
super(type);
......@@ -625,4 +634,106 @@ public abstract class StackValue {
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 {
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 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 {
blackBoxFile("regressions/kt343.jet");
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 {
public void testEnclosingLocalVariable() throws Exception {
blackBoxFile("classes/enclosingLocalVariable.jet");
System.out.println(generateToText());
}
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.
先完成此消息的编辑!
想要评论请 注册