closure shared vars

This commit is contained in:
Alex Tkachman
2011-10-15 13:05:10 +02:00
parent 7831fc3dc1
commit ada54665db
12 changed files with 448 additions and 23 deletions
@@ -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());
}
}
}