work in progress on extra type info in bytecode

This commit is contained in:
Alex Tkachman
2011-12-06 09:25:59 +02:00
parent 627c2186e9
commit 36c0ab6642
11 changed files with 211 additions and 36 deletions
@@ -124,15 +124,17 @@ public abstract class CodegenContext {
return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName); return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName);
} }
public FrameMap prepareFrame() { public FrameMap prepareFrame(JetTypeMapper mapper) {
FrameMap frameMap = new FrameMap(); FrameMap frameMap = new FrameMap();
if (getContextKind() != OwnerKind.NAMESPACE) { if (getContextKind() != OwnerKind.NAMESPACE) {
frameMap.enterTemp(); // 0 slot for this frameMap.enterTemp(); // 0 slot for this
} }
if (getReceiverDescriptor() != null) { CallableDescriptor receiverDescriptor = getReceiverDescriptor();
frameMap.enterTemp(); // Next slot for fake this if (receiverDescriptor != null) {
Type type = mapper.mapType(receiverDescriptor.getReceiverParameter().getType());
frameMap.enterTemp(type.getSize()); // Next slot for fake this
} }
return frameMap; return frameMap;
@@ -4,6 +4,7 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.resolve.DescriptorRenderer; import org.jetbrains.jet.resolve.DescriptorRenderer;
import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
@@ -26,17 +27,19 @@ public class FunctionCodegen {
private final CodegenContext owner; private final CodegenContext owner;
private final ClassBuilder v; private final ClassBuilder v;
private final GenerationState state; private final GenerationState state;
private final JetTypeMapper typeMapper;
public FunctionCodegen(CodegenContext owner, ClassBuilder v, GenerationState state) { public FunctionCodegen(CodegenContext owner, ClassBuilder v, GenerationState state) {
this.owner = owner; this.owner = owner;
this.v = v; this.v = v;
this.state = state; this.state = state;
typeMapper = state.getTypeMapper();
} }
public void gen(JetNamedFunction f) { public void gen(JetNamedFunction f) {
final FunctionDescriptor functionDescriptor = state.getBindingContext().get(BindingContext.FUNCTION, f); final FunctionDescriptor functionDescriptor = state.getBindingContext().get(BindingContext.FUNCTION, f);
assert functionDescriptor != null; assert functionDescriptor != null;
Method method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false, owner.getContextKind()).getSignature(); Method method = typeMapper.mapToCallableMethod(functionDescriptor, false, owner.getContextKind()).getSignature();
generateMethod(f, method, functionDescriptor); generateMethod(f, method, functionDescriptor);
} }
@@ -59,21 +62,57 @@ public class FunctionCodegen {
OwnerKind kind = context.getContextKind(); OwnerKind kind = context.getContextKind();
ReceiverDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject();
ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
if (kind != OwnerKind.TRAIT_IMPL || bodyExpressions != null) { if (kind != OwnerKind.TRAIT_IMPL || bodyExpressions != null) {
boolean isStatic = kind == OwnerKind.NAMESPACE;
if (isStatic || kind == OwnerKind.TRAIT_IMPL)
flags |= ACC_STATIC;
boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL; boolean isAbstract = !isStatic && !(kind == OwnerKind.TRAIT_IMPL) && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration()));
if (isStatic) flags |= ACC_STATIC;
boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration()));
if (isAbstract) flags |= ACC_ABSTRACT; if (isAbstract) flags |= ACC_ABSTRACT;
final MethodVisitor mv = v.newMethod(fun, flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); final MethodVisitor mv = v.newMethod(fun, flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
if(kind != OwnerKind.TRAIT_IMPL && v.generateCode()) { if(v.generateCode()) {
int start = functionDescriptor.getReceiverParameter().exists() ? 1 : 0; int start = 0;
if(kind != OwnerKind.TRAIT_IMPL) {
AnnotationVisitor av = mv.visitAnnotation("Ljet/typeinfo/JetMethod;", true);
if(functionDescriptor.getReturnType().isNullable()) {
av.visit("nullableReturnType", true);
}
av.visitEnd();
}
if(kind == OwnerKind.TRAIT_IMPL) {
AnnotationVisitor av = mv.visitParameterAnnotation(start++, "Ljet/typeinfo/JetParameter;", true);
av.visit("value", "this$self");
av.visitEnd();
}
if(receiverParameter.exists()) {
AnnotationVisitor av = mv.visitParameterAnnotation(start++, "Ljet/typeinfo/JetParameter;", true);
av.visit("value", "this$receiver");
if(receiverParameter.getType().isNullable()) {
av.visit("nullable", true);
}
av.visitEnd();
}
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
AnnotationVisitor av = mv.visitParameterAnnotation(start++, "Ljet/typeinfo/JetTypeParameter;", true);
av.visit("value", typeParameterDescriptor.getName());
av.visitEnd();
}
for(int i = 0; i != paramDescrs.size(); ++i) { for(int i = 0; i != paramDescrs.size(); ++i) {
AnnotationVisitor annotationVisitor = mv.visitParameterAnnotation(i + start, "Ljet/typeinfo/JetParameterName;", true); AnnotationVisitor av = mv.visitParameterAnnotation(i + start, "Ljet/typeinfo/JetParameter;", true);
annotationVisitor.visit("value", paramDescrs.get(i).getName()); ValueParameterDescriptor parameterDescriptor = paramDescrs.get(i);
annotationVisitor.visitEnd(); av.visit("value", parameterDescriptor.getName());
if(parameterDescriptor.hasDefaultValue()) {
av.visit("hasDefaultValue", true);
}
if(parameterDescriptor.getOutType().isNullable()) {
av.visit("nullable", true);
}
av.visitEnd();
} }
} }
if (!isAbstract && v.generateCode()) { if (!isAbstract && v.generateCode()) {
@@ -82,12 +121,18 @@ public class FunctionCodegen {
Label methodBegin = new Label(); Label methodBegin = new Label();
mv.visitLabel(methodBegin); mv.visitLabel(methodBegin);
FrameMap frameMap = context.prepareFrame(); FrameMap frameMap = context.prepareFrame(typeMapper);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state);
Type[] argTypes = jvmSignature.getArgumentTypes(); Type[] argTypes = jvmSignature.getArgumentTypes();
int add = functionDescriptor.getReceiverParameter().exists() ? state.getTypeMapper().mapType(functionDescriptor.getReceiverParameter().getType()).getSize() : 0; int add = 0;
if(kind == OwnerKind.TRAIT_IMPL)
add++;
if(receiverParameter.exists())
add++;
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
int slot = frameMap.enterTemp(); int slot = frameMap.enterTemp();
@@ -114,9 +159,9 @@ public class FunctionCodegen {
} }
else { else {
for (ValueParameterDescriptor parameter : paramDescrs) { for (ValueParameterDescriptor parameter : paramDescrs) {
Type sharedVarType = state.getTypeMapper().getSharedVarType(parameter); Type sharedVarType = typeMapper.getSharedVarType(parameter);
Type localVarType = state.getTypeMapper().mapType(parameter.getOutType());
if (sharedVarType != null) { if (sharedVarType != null) {
Type localVarType = typeMapper.mapType(parameter.getOutType());
int index = frameMap.getIndex(parameter); int index = frameMap.getIndex(parameter);
mv.visitTypeInsn(NEW, sharedVarType.getInternalName()); mv.visitTypeInsn(NEW, sharedVarType.getInternalName());
mv.visitInsn(DUP); mv.visitInsn(DUP);
@@ -134,13 +179,30 @@ public class FunctionCodegen {
Label methodEnd = new Label(); Label methodEnd = new Label();
mv.visitLabel(methodEnd); mv.visitLabel(methodEnd);
// http://youtrack.jetbrains.net/issue/KT-746 int k = 0;
// Fill LocalVariableTable with method parameter names
for (int i = 0; i < paramDescrs.size(); i++) { if(expectedThisObject.exists()) {
ValueParameterDescriptor parameter = paramDescrs.get(i); Type type = typeMapper.mapType(expectedThisObject.getType());
Type type = state.getTypeMapper().mapType(parameter.getOutType());
// TODO: specify signature // TODO: specify signature
mv.visitLocalVariable(parameter.getName(), type.getDescriptor(), null, methodBegin, methodEnd, i + add); mv.visitLocalVariable("this", type.getDescriptor(), null, methodBegin, methodEnd, k++);
}
if(receiverParameter.exists()) {
Type type = typeMapper.mapType(receiverParameter.getType());
// TODO: specify signature
mv.visitLocalVariable("this$receiver", type.getDescriptor(), null, methodBegin, methodEnd, k);
k += type.getSize();
}
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
mv.visitLocalVariable(typeParameterDescriptor.getName(), JetTypeMapper.TYPE_TYPEINFO.getDescriptor(), null, methodBegin, methodEnd, k++);
}
for (ValueParameterDescriptor parameter : paramDescrs) {
Type type = typeMapper.mapType(parameter.getOutType());
// TODO: specify signature
mv.visitLocalVariable(parameter.getName(), type.getDescriptor(), null, methodBegin, methodEnd, k);
k += type.getSize();
} }
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
@@ -210,7 +272,7 @@ public class FunctionCodegen {
if (v.generateCode()) { if (v.generateCode()) {
mv.visitCode(); mv.visitCode();
FrameMap frameMap = owner.prepareFrame(); FrameMap frameMap = owner.prepareFrame(state.getTypeMapper());
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), owner, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), owner, state);
@@ -348,9 +348,6 @@ public class JetTypeMapper {
final JetType receiverType = !receiverTypeRef.exists() ? null : receiverTypeRef.getType(); final JetType receiverType = !receiverTypeRef.exists() ? null : receiverTypeRef.getType();
final List<ValueParameterDescriptor> parameters = f.getValueParameters(); final List<ValueParameterDescriptor> parameters = f.getValueParameters();
List<Type> parameterTypes = new ArrayList<Type>(); List<Type> parameterTypes = new ArrayList<Type>();
if (receiverType != null) {
parameterTypes.add(mapType(receiverType));
}
if(kind == OwnerKind.TRAIT_IMPL) { if(kind == OwnerKind.TRAIT_IMPL) {
ClassDescriptor containingDeclaration = (ClassDescriptor) f.getContainingDeclaration(); ClassDescriptor containingDeclaration = (ClassDescriptor) f.getContainingDeclaration();
JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext); JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext);
@@ -362,6 +359,9 @@ public class JetTypeMapper {
valueParameterTypes.add(type); valueParameterTypes.add(type);
parameterTypes.add(type); parameterTypes.add(type);
} }
if (receiverType != null) {
parameterTypes.add(mapType(receiverType));
}
for (TypeParameterDescriptor parameterDescriptor : f.getTypeParameters()) { for (TypeParameterDescriptor parameterDescriptor : f.getTypeParameters()) {
if(parameterDescriptor.isReified()) { if(parameterDescriptor.isReified()) {
parameterTypes.add(TYPE_TYPEINFO); parameterTypes.add(TYPE_TYPEINFO);
@@ -10,6 +10,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.lang.types.Variance;
import org.objectweb.asm.Type;
import java.util.List; import java.util.List;
@@ -17,6 +18,9 @@ import java.util.List;
* @author alex.tkachman * @author alex.tkachman
*/ */
public class SignatureUtil { public class SignatureUtil {
private SignatureUtil() {
}
public static String classToSignature(JetClass type, BindingContext bindingContext, JetTypeMapper typeMapper) { public static String classToSignature(JetClass type, BindingContext bindingContext, JetTypeMapper typeMapper) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
genTypeParams(type, sb); genTypeParams(type, sb);
@@ -33,7 +37,7 @@ public class SignatureUtil {
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if(descriptor instanceof ClassDescriptor) { if(descriptor instanceof ClassDescriptor) {
JetType defaultType = ((ClassDescriptor) descriptor).getDefaultType(); JetType defaultType = ((ClassDescriptor) descriptor).getDefaultType();
org.objectweb.asm.Type type = typeMapper.mapType(defaultType, OwnerKind.IMPLEMENTATION); Type type = typeMapper.mapType(defaultType, OwnerKind.IMPLEMENTATION);
if(JetTypeMapper.isPrimitive(type)) { if(JetTypeMapper.isPrimitive(type)) {
type = JetTypeMapper.boxType(type); type = JetTypeMapper.boxType(type);
} }
+27
View File
@@ -0,0 +1,27 @@
package jet.typeinfo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for method
*
* The fact of receiver presence must be deducted from presence of 'this$receiver' parameter
*
* @author alex.tkachman
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JetMethod {
/**
* @return type projections or empty
*/
JetTypeProjection[] returnTypeProjections() default {};
/**
* @return is this type returnTypeNullable
*/
boolean nullableReturnType() default false;
}
+35
View File
@@ -0,0 +1,35 @@
package jet.typeinfo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for parameters
*
* @author alex.tkachman
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface JetParameter {
/**
* @return name of parameter
*/
String name ();
/**
* @return type projections or empty
*/
JetTypeProjection[] typeProjections() default {};
/**
* @return is this type nullable
*/
boolean nullable () default false;
/**
* @return if this parameter has default value
*/
boolean hasDefaultValue () default false;
}
@@ -0,0 +1,20 @@
package jet.typeinfo;
/**
* @author alex.tkachman
*/
public @interface JetTypeDescriptor{
//
// case of type parameter
//
String varName() default "";
boolean reified () default true;
TypeInfoVariance variance() default TypeInfoVariance.INVARIANT;
int [] upperBounds() default {};
//
// case of real type
//
Class javaClass() default Object.class;
JetTypeProjection [] projections() default {};
}
@@ -6,10 +6,15 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Annotation for parameters
*
* @author alex.tkachman * @author alex.tkachman
*/ */
@Target({ElementType.PARAMETER}) @Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface JetParameterName { public @interface JetTypeParameter {
String value (); /**
* @return name of parameter
*/
String name();
} }
@@ -0,0 +1,20 @@
package jet.typeinfo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author alex.tkachman
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface JetTypeProjection {
/**
* @return variance of the type
*/
TypeInfoVariance variance();
/**
* @return index of the class in the per class table of JetTypeDescriptor
*/
int typeDescriptorIndex();
}
+4 -4
View File
@@ -60,7 +60,7 @@ public abstract class TypeInfo<T> implements JetObject {
// @NotNull // @NotNull
@Override @Override
public TypeInfoVariance getVariance() { public TypeInfoVariance getVariance() {
return TypeInfoVariance.IN_VARIANCE; return TypeInfoVariance.IN;
} }
}; };
} }
@@ -70,7 +70,7 @@ public abstract class TypeInfo<T> implements JetObject {
// @NotNull // @NotNull
@Override @Override
public TypeInfoVariance getVariance() { public TypeInfoVariance getVariance() {
return TypeInfoVariance.OUT_VARIANCE; return TypeInfoVariance.OUT;
} }
}; };
} }
@@ -606,11 +606,11 @@ public abstract class TypeInfo<T> implements JetObject {
private TypeInfoVariance parseVariance() { private TypeInfoVariance parseVariance() {
if(string[cur] == 'i' && string[cur+1] == 'n' && string[cur+2] == ' ' ) { if(string[cur] == 'i' && string[cur+1] == 'n' && string[cur+2] == ' ' ) {
cur += 3; cur += 3;
return TypeInfoVariance.IN_VARIANCE; return TypeInfoVariance.IN;
} }
else if (string[cur] == 'o' && string[cur+1] == 'u' && string[cur+2] == 't' && string[cur+3] == ' ') { else if (string[cur] == 'o' && string[cur+1] == 'u' && string[cur+2] == 't' && string[cur+3] == ' ') {
cur += 4; cur += 4;
return TypeInfoVariance.OUT_VARIANCE; return TypeInfoVariance.OUT;
} }
else { else {
return TypeInfoVariance.INVARIANT; return TypeInfoVariance.INVARIANT;
@@ -5,8 +5,8 @@ package jet.typeinfo;
*/ */
public enum TypeInfoVariance { public enum TypeInfoVariance {
INVARIANT("") , INVARIANT("") ,
IN_VARIANCE("in"), IN("in"),
OUT_VARIANCE("out"); OUT("out");
private final String label; private final String label;