array code gen rewrite and work in progress on outer type info

This commit is contained in:
Alex Tkachman
2011-09-29 12:55:35 +03:00
parent b40b7ada4d
commit ea9e1bee85
31 changed files with 1035 additions and 232 deletions
@@ -45,9 +45,4 @@ public class ClassCodegen {
}
public static void newTypeInfo(InstructionAdapter v, boolean isNullable, Type asmType) {
v.aconst(asmType);
v.iconst(isNullable?1:0);
v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;");
}
}
@@ -1,9 +1,12 @@
package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.objectweb.asm.Type;
@@ -43,7 +46,7 @@ public class CodegenUtil {
return getOuterClassDescriptor(classDescriptor) != null && !isClassObject(classDescriptor);
}
public static ClassDescriptor getOuterClassDescriptor(ClassDescriptor descriptor) {
public static ClassDescriptor getOuterClassDescriptor(DeclarationDescriptor descriptor) {
DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
while(outerDescriptor != null) {
if(outerDescriptor instanceof ClassDescriptor)
@@ -54,6 +57,48 @@ public class CodegenUtil {
return (ClassDescriptor) outerDescriptor;
}
public static boolean hasOuterTypeInfo(ClassDescriptor descriptor) {
ClassDescriptor outerClassDescriptor = getOuterClassDescriptor(descriptor);
if(outerClassDescriptor == null)
return false;
if(outerClassDescriptor.getTypeConstructor().getParameters().size() > 0)
return true;
return hasOuterTypeInfo(outerClassDescriptor);
}
public static boolean hasTypeInfoField(JetType type) {
if(type.getConstructor().getParameters().size() > 0)
return true;
for (JetType jetType : type.getConstructor().getSupertypes()) {
if(hasTypeInfoField(jetType))
return true;
}
ClassDescriptor outerClassDescriptor = getOuterClassDescriptor(type.getConstructor().getDeclarationDescriptor());
if(outerClassDescriptor == null)
return false;
return hasTypeInfoField(outerClassDescriptor.getDefaultType());
}
public static boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) {
if(!exceptOwn) {
if(!isInterface(type))
if(hasTypeInfoField(type))
return true;
}
for (JetType jetType : type.getConstructor().getSupertypes()) {
if(hasDerivedTypeInfoField(jetType, false))
return true;
}
return false;
}
public static Type arrayElementType(Type type) {
return Type.getType(type.getDescriptor().substring(1));
}
@@ -17,11 +17,9 @@ public class ConstructorFrameMap extends FrameMap {
private int myFirstTypeParameter = -1;
private int myTypeParameterCount = 0;
public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, OwnerKind kind) {
public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, ClassDescriptor classDescriptor, OwnerKind kind) {
enterTemp(); // this
ClassDescriptor classDescriptor = null;
if (descriptor != null) {
classDescriptor = descriptor.getContainingDeclaration();
if (CodegenUtil.hasThis0(classDescriptor)) {
myOuterThisIndex = enterTemp(); // outer class instance
}
@@ -37,7 +35,6 @@ public class ConstructorFrameMap extends FrameMap {
enter(parameter, explicitArgTypes.get(i).getSize());
}
if (classDescriptor != null) {
myTypeParameterCount = classDescriptor.getTypeConstructor().getParameters().size();
if (kind == OwnerKind.IMPLEMENTATION) {
@@ -200,7 +200,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
final JetExpression loopRange = expression.getLoopRange();
final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, loopRange);
Type loopRangeType = typeMapper.mapType(expressionType);
if (loopRangeType.getSort() == Type.ARRAY) {
if (state.getStandardLibrary().getArray().equals(expressionType.getConstructor().getDeclarationDescriptor())) {
new ForInArrayLoopGenerator(expression, loopRangeType).invoke();
return StackValue.none();
}
@@ -364,6 +364,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
protected void generatePrologue() {
myLengthVar = myMap.enterTemp();
gen(expression.getLoopRange(), loopRangeType);
derefArray(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getLoopRange()));
v.arraylength();
v.store(myLengthVar, Type.INT_TYPE);
myIndexVar = myMap.enterTemp();
@@ -377,9 +378,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.ificmpge(end);
gen(expression.getLoopRange(), loopRangeType); // array
derefArray(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getLoopRange()));
v.load(myIndexVar, Type.INT_TYPE);
v.aload(CodegenUtil.arrayElementType(loopRangeType));
StackValue.onStack(CodegenUtil.arrayElementType(loopRangeType)).put(asmParamType, v);
v.aload(asmParamType);
StackValue.onStack(asmParamType).put(asmParamType, v);
v.store(lookupLocal(parameterDescriptor), asmParamType);
}
@@ -1622,9 +1624,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
else if (constructorDescriptor instanceof ConstructorDescriptor) {
//noinspection ConstantConditions
type = typeMapper.mapType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression), OwnerKind.IMPLEMENTATION);
if (type.getSort() == Type.ARRAY) {
generateNewArray(expression, type);
JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
type = typeMapper.mapType(expressionType, OwnerKind.IMPLEMENTATION);
if (state.getStandardLibrary().getArray().equals(expressionType.getConstructor().getDeclarationDescriptor())) {
generateNewArray(expression, expressionType);
}
else {
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
@@ -1682,9 +1685,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return type;
}
private void generateNewArray(JetCallExpression expression, Type type) {
JetType arrayType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
private void generateNewArray(JetCallExpression expression, JetType arrayType) {
List<? extends ValueArgument> args = expression.getValueArguments();
if (args.size() != 1) {
throw new CompilationException("array constructor requires one value argument");
@@ -1694,23 +1695,53 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
JetType elementType = typeMapper.getGenericsElementType(arrayType);
if(elementType != null) {
generateTypeInfo(elementType);
v.invokestatic("jet/typeinfo/TypeInfo", "newArray", "(ILjet/typeinfo/TypeInfo;)[Ljava/lang/Object;");
v.checkcast(type);
v.invokestatic("jet/arrays/JetArray", "newArray", "(ILjet/typeinfo/TypeInfo;)Ljet/arrays/JetArray;");
}
else {
v.newarray(CodegenUtil.arrayElementType(type));
elementType = arrayType.getArguments().get(0).getType();
JetStandardLibrary standardLibrary = state.getStandardLibrary();
if (elementType.equals(standardLibrary.getIntType())) {
v.invokestatic("jet/arrays/JetArray", "newIntArray", "(I)Ljet/arrays/JetIntArray;");
}
else if (elementType.equals(standardLibrary.getLongType())) {
v.invokestatic("jet/arrays/JetArray", "newLongArray", "(I)Ljet/arrays/JetLongArray;");
}
else if (elementType.equals(standardLibrary.getShortType())) {
v.invokestatic("jet/arrays/JetArray", "newShortArray", "(I)Ljet/arrays/JetShortArray;");
}
else if (elementType.equals(standardLibrary.getByteType())) {
v.invokestatic("jet/arrays/JetArray", "newByteArray", "(I)Ljet/arrays/JetByteArray;");
}
else if (elementType.equals(standardLibrary.getCharType())) {
v.invokestatic("jet/arrays/JetArray", "newCharArray", "(I)Ljet/arrays/JetCharArray;");
}
else if (elementType.equals(standardLibrary.getFloatType())) {
v.invokestatic("jet/arrays/JetArray", "newFloatArray", "(I)Ljet/arrays/JetFloatArray;");
}
else if (elementType.equals(standardLibrary.getDoubleType())) {
v.invokestatic("jet/arrays/JetArray", "newDoubleArray", "(I)Ljet/arrays/JetDoubleArray;");
}
else if (elementType.equals(standardLibrary.getBooleanType())) {
v.invokestatic("jet/arrays/JetArray", "newBoolArray", "(I)Ljet/arrays/JetBoolArray;");
}
else {
generateTypeInfo(elementType);
v.invokestatic("jet/arrays/JetArray", "newGenericArray", "(ILjet/typeinfo/TypeInfo;)Ljet/arrays/JetGenericArray;");
}
}
}
@Override
public StackValue visitArrayAccessExpression(JetArrayAccessExpression expression, StackValue receiver) {
final JetExpression array = expression.getArrayExpression();
final Type arrayType = expressionType(array);
JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, array);
final Type arrayType = type == null ? Type.VOID_TYPE : typeMapper.mapType(type);
gen(array, arrayType);
derefArray(type);
generateArrayIndex(expression);
if (arrayType.getSort() == Type.ARRAY) {
final Type elementType = CodegenUtil.arrayElementType(arrayType);
return StackValue.arrayElement(elementType);
if (state.getStandardLibrary().getArray().equals(type.getConstructor().getDeclarationDescriptor())) {
JetType elementType = type.getArguments().get(0).getType();
return StackValue.arrayElement(typeMapper.mapType(elementType), typeMapper.isGenericsArray(type));
}
else {
final PsiElement declaration = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, expression);
@@ -1733,6 +1764,46 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
}
public void derefArray(JetType type) {
if (state.getStandardLibrary().getArray().equals(type.getConstructor().getDeclarationDescriptor())) {
JetType elementType = type.getArguments().get(0).getType();
JetStandardLibrary standardLibrary = state.getStandardLibrary();
if (elementType.equals(standardLibrary.getIntType())) {
v.getfield("jet/arrays/JetIntArray", "array", "[I");
}
else if (elementType.equals(standardLibrary.getLongType())) {
v.getfield("jet/arrays/JetLongArray", "array", "[J");
}
else if (elementType.equals(standardLibrary.getShortType())) {
v.getfield("jet/arrays/JetShortArray", "array", "[S");
}
else if (elementType.equals(standardLibrary.getByteType())) {
v.getfield("jet/arrays/JetByteArray", "array", "[B");
}
else if (elementType.equals(standardLibrary.getCharType())) {
v.getfield("jet/arrays/JetCharArray", "array", "[C");
}
else if (elementType.equals(standardLibrary.getFloatType())) {
v.getfield("jet/arrays/JetFloatArray", "array", "[F");
}
else if (elementType.equals(standardLibrary.getDoubleType())) {
v.getfield("jet/arrays/JetDoubleArray", "array", "[D");
}
else if (elementType.equals(standardLibrary.getBooleanType())) {
v.getfield("jet/arrays/JetBooleanArray", "array", "[Z");
}
else {
if(typeMapper.isGenericsArray(type)) {
v.visitTypeInsn(Opcodes.CHECKCAST, "jet/arrays/JetArray");
}
else {
v.getfield("jet/arrays/JetGenericArray", "array", "[Ljava/lang/Object;");
v.visitTypeInsn(Opcodes.CHECKCAST, "[" + typeMapper.mapType(elementType).getDescriptor());
}
}
}
}
private void generateArrayIndex(JetArrayAccessExpression expression) {
final List<JetExpression> indices = expression.getIndexExpressions();
for (JetExpression index : indices) {
@@ -1989,9 +2060,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return;
}
if(jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor)) {
if(!CodegenUtil.hasTypeInfoField(jetType)) {
// TODO: we need some better checks here
v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;");
return;
}
@@ -2044,23 +2115,33 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return;
}
DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
if (containingDeclaration == contextType() && contextType() instanceof ClassDescriptor) {
if (contextType() instanceof ClassDescriptor) {
ClassDescriptor descriptor = (ClassDescriptor) contextType();
JetType defaultType = descriptor.getDefaultType();
JetType defaultType = ((ClassDescriptor)containingDeclaration).getDefaultType();
Type ownerType = typeMapper.mapType(defaultType);
ownerType = JetTypeMapper.boxType(ownerType);
if(!CodegenUtil.isInterface(descriptor)) {
if (descriptor.getTypeConstructor().getParameters().size() > 0) {
v.load(0, JetTypeMapper.TYPE_OBJECT);
v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
if (containingDeclaration == contextType()) {
if(!CodegenUtil.isInterface(descriptor)) {
if (CodegenUtil.hasTypeInfoField(defaultType)) {
v.load(0, JetTypeMapper.TYPE_OBJECT);
v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
}
else {
v.getstatic(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
}
}
else {
v.getstatic(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
v.load(0, JetTypeMapper.TYPE_OBJECT);
v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;");
}
}
else {
v.load(0, JetTypeMapper.TYPE_OBJECT);
v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;");
while(descriptor != containingDeclaration) {
descriptor = CodegenUtil.getOuterClassDescriptor(descriptor);
v.invokevirtual("jet/typeinfo/TypeInfo", "getOuterTypeInfo", "()Ljet/typeinfo/TypeInfo;");
}
}
v.aconst(ownerType);
v.iconst(typeParameterDescriptor.getIndex());
@@ -8,7 +8,6 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.OverridingUtil;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lexer.JetTokens;
@@ -99,6 +98,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
);
v.visitSource(myClass.getContainingFile().getName(), null);
if(descriptor.getContainingDeclaration() instanceof ClassDescriptor) {
v.visitOuterClass(state.getTypeMapper().jvmType((ClassDescriptor) descriptor.getContainingDeclaration(), OwnerKind.IMPLEMENTATION).getInternalName(), null, null);
}
if(myClass instanceof JetClass) {
AnnotationVisitor annotationVisitor = v.visitAnnotation("Ljet/typeinfo/JetSignature;", true);
annotationVisitor.visit("value", SignatureUtil.classToSignature((JetClass)myClass, state.getBindingContext(), state.getTypeMapper()));
@@ -205,7 +208,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
Method method;
CallableMethod callableMethod;
if (constructorDescriptor == null) {
method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
List<Type> parameterTypes = new ArrayList<Type>();
if (CodegenUtil.hasThis0(descriptor)) {
parameterTypes.add(state.getTypeMapper().jvmType(CodegenUtil.getOuterClassDescriptor(descriptor), OwnerKind.IMPLEMENTATION));
}
List<TypeParameterDescriptor> typeParameters = descriptor.getTypeConstructor().getParameters();
for (int n = typeParameters.size(); n > 0; n--) {
parameterTypes.add(JetTypeMapper.TYPE_TYPEINFO);
}
method = new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
callableMethod = new CallableMethod("", method, Opcodes.INVOKESPECIAL, Collections.<Type>emptyList());
}
else {
@@ -220,13 +233,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
? constructorDescriptor.getValueParameters()
: Collections.<ValueParameterDescriptor>emptyList();
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, kind);
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, descriptor, kind);
final InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state);
for(int slot = 0; slot != frameMap.getTypeParameterCount(); ++slot) {
codegen.addTypeParameter(constructorDescriptor.getTypeParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO));
if(constructorDescriptor != null)
codegen.addTypeParameter(constructorDescriptor.getTypeParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO));
else
codegen.addTypeParameter(descriptor.getTypeConstructor().getParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO));
}
String classname = state.getTypeMapper().jvmName(descriptor, kind);
@@ -241,7 +257,24 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (superCall == null || superCall instanceof JetDelegatorToSuperClass) {
iv.load(0, Type.getType("L" + superClass + ";"));
iv.invokespecial(superClass, "<init>", "()V");
if(superCall == null) {
iv.invokespecial(superClass, "<init>", "()V");
}
else {
JetType superType = state.getBindingContext().get(BindingContext.TYPE, superCall.getTypeReference());
List<Type> parameterTypes = new ArrayList<Type>();
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
if (CodegenUtil.hasThis0(superClassDescriptor)) {
iv.load(1, JetTypeMapper.TYPE_OBJECT);
parameterTypes.add(state.getTypeMapper().jvmType(CodegenUtil.getOuterClassDescriptor(descriptor), OwnerKind.IMPLEMENTATION));
}
for(TypeProjection typeParameterDescriptor : superType.getArguments()) {
codegen.generateTypeInfo(typeParameterDescriptor.getType());
parameterTypes.add(JetTypeMapper.TYPE_TYPEINFO);
}
Method superCallMethod = new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
iv.invokespecial(state.getTypeMapper().jvmName(superClassDescriptor, OwnerKind.IMPLEMENTATION), "<init>", superCallMethod.getDescriptor());
}
}
else {
iv.load(0, classType);
@@ -285,7 +318,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.putfield(classname, fieldName, interfaceDesc);
}
if (frameMap.getFirstTypeParameter() > 0 && kind == OwnerKind.IMPLEMENTATION) {
if (CodegenUtil.hasTypeInfoField(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) {
generateTypeInfoInitializer(frameMap.getFirstTypeParameter(), frameMap.getTypeParameterCount(), iv);
}
@@ -473,7 +506,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
final MethodVisitor mv = v.visitMethod(flags, "<init>", method.getSignature().getDescriptor(), null, null);
mv.visitCode();
ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, kind);
ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, descriptor, kind);
final InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state);
@@ -507,17 +540,38 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.aconst(state.getTypeMapper().jvmType(descriptor, OwnerKind.IMPLEMENTATION));
iv.iconst(0);
iv.iconst(typeParamCount);
iv.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION);
for (int i = 0; i < typeParamCount; i++) {
iv.dup();
iv.iconst(i);
iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT);
iv.checkcast(JetTypeMapper.TYPE_TYPEINFOPROJECTION);
iv.astore(JetTypeMapper.TYPE_OBJECT);
if(CodegenUtil.hasOuterTypeInfo(descriptor)) {
iv.load(1, JetTypeMapper.TYPE_OBJECT);
iv.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;");
}
iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;");
if(typeParamCount != 0) {
iv.iconst(typeParamCount);
iv.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION);
for (int i = 0; i < typeParamCount; i++) {
iv.dup();
iv.iconst(i);
iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT);
iv.checkcast(JetTypeMapper.TYPE_TYPEINFOPROJECTION);
iv.astore(JetTypeMapper.TYPE_OBJECT);
}
if(CodegenUtil.hasOuterTypeInfo(descriptor)) {
iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;");
}
else
iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;");
}
else {
if(CodegenUtil.hasOuterTypeInfo(descriptor)) {
iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfo;");
}
else
iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;");
}
iv.invokevirtual(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$setTypeInfo", "(Ljet/typeinfo/TypeInfo;)V");
}
@@ -617,8 +671,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return;
JetType defaultType = descriptor.getDefaultType();
if(isParametrizedClass(defaultType)) {
if(!hasDerivedTypeInfoField(defaultType, true)) {
if(CodegenUtil.hasTypeInfoField(defaultType)) {
if(!CodegenUtil.hasDerivedTypeInfoField(defaultType, true)) {
v.visitField(Opcodes.ACC_PRIVATE, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null);
@@ -642,51 +696,45 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
mv.visitMaxs(0, 0);
mv.visitEnd();
}
else {
if(descriptor.getTypeConstructor().getParameters().isEmpty()) {
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter v) {
JetTypeMapper typeMapper = state.getTypeMapper();
ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.IMPLEMENTATION));
v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
}
});
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null);
mv.visitCode();
InstructionAdapter v = new InstructionAdapter(mv);
String owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION);
v.getstatic(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;");
v.areturn(JetTypeMapper.TYPE_TYPEINFO);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
}
else {
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter v) {
JetTypeMapper typeMapper = state.getTypeMapper();
ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.IMPLEMENTATION));
v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
}
});
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null);
mv.visitCode();
InstructionAdapter v = new InstructionAdapter(mv);
String owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION);
v.getstatic(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;");
v.areturn(JetTypeMapper.TYPE_TYPEINFO);
mv.visitMaxs(0, 0);
mv.visitEnd();
genGetStaticGetTypeInfoMethod();
staticTypeInfoField();
}
}
private void genGetStaticGetTypeInfoMethod() {
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null);
mv.visitCode();
InstructionAdapter v = new InstructionAdapter(mv);
String owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION);
v.getstatic(owner, "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;");
v.areturn(JetTypeMapper.TYPE_TYPEINFO);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private void staticTypeInfoField() {
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter v) {
JetTypeMapper typeMapper = state.getTypeMapper();
v.aconst(typeMapper.jvmType(descriptor, OwnerKind.IMPLEMENTATION));
v.iconst(0);
ClassDescriptor outerClassDescriptor = CodegenUtil.getOuterClassDescriptor(descriptor);
if(outerClassDescriptor == null) {
v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;");
}
else {
v.getstatic(state.getTypeMapper().jvmName(outerClassDescriptor, OwnerKind.IMPLEMENTATION), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;");
v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfo;");
}
v.putstatic(typeMapper.jvmName(descriptor, kind), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;");
}
});
}
private void generateClassObject(JetClassObject declaration) {
state.forClass().generate(context, declaration.getObjectDeclaration());
}
@@ -737,30 +785,4 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return sb.toString();
}
public static boolean isParametrizedClass(JetType type) {
if(type.getConstructor().getParameters().size() > 0)
return true;
for (JetType jetType : type.getConstructor().getSupertypes()) {
if(isParametrizedClass(jetType))
return true;
}
return false;
}
public static boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) {
if(!exceptOwn) {
if(!CodegenUtil.isInterface(type))
if(isParametrizedClass(type))
return true;
}
for (JetType jetType : type.getConstructor().getSupertypes()) {
if(hasDerivedTypeInfoField(jetType, false))
return true;
}
return false;
}
}
@@ -40,12 +40,23 @@ public class JetTypeMapper {
public static final Type JL_NUMBER_TYPE = Type.getObjectType("java/lang/Number");
public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder");
public static final Type ARRAY_INT_TYPE = Type.getObjectType("jet/arrays/JetIntArray");
public static final Type ARRAY_LONG_TYPE = Type.getObjectType("jet/arrays/JetLongArray");
public static final Type ARRAY_SHORT_TYPE = Type.getObjectType("jet/arrays/JetShortArray");
public static final Type ARRAY_BYTE_TYPE = Type.getObjectType("jet/arrays/JetByteArray");
public static final Type ARRAY_CHAR_TYPE = Type.getObjectType("jet/arrays/JetCharArray");
public static final Type ARRAY_FLOAT_TYPE = Type.getObjectType("jet/arrays/JetFloatArray");
public static final Type ARRAY_DOUBLE_TYPE = Type.getObjectType("jet/arrays/JetDoubleArray");
public static final Type ARRAY_BOOL_TYPE = Type.getObjectType("jet/arrays/JetBoolArray");
public static final Type ARRAY_GENERIC_TYPE = Type.getObjectType("jet/arrays/JetGenericArray");
private final JetStandardLibrary standardLibrary;
private final BindingContext bindingContext;
private final Map<JetExpression, String> classNamesForAnonymousClasses = new HashMap<JetExpression, String>();
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
private final HashMap<JetType,String> knowTypes = new HashMap<JetType, String>();
private final HashMap<JetType,String> knowArrayTypes = new HashMap<JetType, String>();
public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) {
this.standardLibrary = standardLibrary;
@@ -377,9 +388,36 @@ public class JetTypeMapper {
if (jetType.getArguments().size() != 1) {
throw new UnsupportedOperationException("arrays must have one type argument");
}
TypeProjection memberType = jetType.getArguments().get(0);
Type elementType = mapType(memberType.getType());
return Type.getType("[" + elementType.getDescriptor());
JetType memberType = jetType.getArguments().get(0).getType();
if (memberType.equals(standardLibrary.getIntType())) {
return ARRAY_INT_TYPE;
}
if (memberType.equals(standardLibrary.getLongType())) {
return ARRAY_LONG_TYPE;
}
if (memberType.equals(standardLibrary.getShortType())) {
return ARRAY_SHORT_TYPE;
}
if (memberType.equals(standardLibrary.getByteType())) {
return ARRAY_BYTE_TYPE;
}
if (memberType.equals(standardLibrary.getCharType())) {
return ARRAY_CHAR_TYPE;
}
if (memberType.equals(standardLibrary.getFloatType())) {
return ARRAY_FLOAT_TYPE;
}
if (memberType.equals(standardLibrary.getDoubleType())) {
return ARRAY_DOUBLE_TYPE;
}
if (memberType.equals(standardLibrary.getBooleanType())) {
return ARRAY_BOOL_TYPE;
}
if(!isGenericsArray(jetType))
return ARRAY_GENERIC_TYPE;
else
return TYPE_OBJECT;
}
if (JetStandardClasses.getAny().equals(descriptor)) {
return Type.getType(Object.class);
@@ -665,9 +703,21 @@ public class JetTypeMapper {
knowTypes.put(standardLibrary.getNullableStringType(),"NULLABLE_STRING_TYPE_INFO");
knowTypes.put(standardLibrary.getTuple0Type(),"TUPLE0_TYPE_INFO");
knowTypes.put(standardLibrary.getNullableTuple0Type(),"NULLABLE_TUPLE0_TYPE_INFO");
knowArrayTypes.put(standardLibrary.getIntType(), "INT_ARRAY_TYPE_INFO");
knowArrayTypes.put(standardLibrary.getLongType(), "LONG_ARRAY_TYPE_INFO");
knowArrayTypes.put(standardLibrary.getShortType(),"SHORT_ARRAY_TYPE_INFO");
knowArrayTypes.put(standardLibrary.getByteType(),"BYTE_ARRAY_TYPE_INFO");
knowArrayTypes.put(standardLibrary.getCharType(),"CHAR_ARRAY_TYPE_INFO");
knowArrayTypes.put(standardLibrary.getFloatType(),"FLOAT_ARRAY_TYPE_INFO");
knowArrayTypes.put(standardLibrary.getDoubleType(),"DOUBLE_ARRAY_TYPE_INFO");
knowArrayTypes.put(standardLibrary.getBooleanType(),"BOOLEAN_ARRAY_TYPE_INFO");
}
public String isKnownTypeInfo(JetType jetType) {
if(standardLibrary.getArray().equals(jetType.getConstructor().getDeclarationDescriptor()))
return knowArrayTypes.get(jetType.getArguments().get(0).getType());
return knowTypes.get(jetType);
}
@@ -1,19 +1,15 @@
package org.jetbrains.jet.codegen;
import jet.typeinfo.TypeInfoVariance;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
import org.jetbrains.jet.lang.psi.JetTypeParameter;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.Variance;
import org.objectweb.asm.Type;
import java.util.List;
@@ -44,7 +40,11 @@ public class SignatureUtil {
sb.append(type.getDescriptor());
}
else {
sb.append("T").append(descriptor.getName()).append(";");
sb.append("T");
sb.append(descriptor.getContainingDeclaration().getName());
sb.append(";");
sb.append(descriptor.getName());
sb.append(";");
}
if(!jetType.getArguments().isEmpty()) {
sb.append("<");
@@ -13,7 +13,7 @@ import org.objectweb.asm.commons.Method;
* @author yole
*/
public abstract class StackValue {
protected final Type type;
public final Type type;
public StackValue(Type type) {
this.type = type;
@@ -75,8 +75,8 @@ public abstract class StackValue {
return new Invert(stackValue);
}
public static StackValue arrayElement(Type type) {
return new ArrayElement(type);
public static StackValue arrayElement(Type type, boolean genericsArray) {
return new ArrayElement(type, genericsArray);
}
public static StackValue collectionElement(Type type, CallableMethod getter, CallableMethod setter) {
@@ -424,19 +424,32 @@ public abstract class StackValue {
}
private static class ArrayElement extends StackValue {
public ArrayElement(Type type) {
private boolean genericsArray;
public ArrayElement(Type type, boolean genericsArray) {
super(type);
this.genericsArray = genericsArray;
}
@Override
public void put(Type type, InstructionAdapter v) {
v.aload(type); // assumes array and index are on the stack
if(genericsArray) {
v.invokevirtual("jet/arrays/JetArray", "get", "(I)Ljava/lang/Object;");
}
else {
v.aload(this.type); // assumes array and index are on the stack
}
coerce(type, v);
}
@Override
public void store(InstructionAdapter v) {
v.astore(type); // assumes array and index are on the stack
if(genericsArray) {
v.invokevirtual("jet/arrays/JetArray", "set", "(ILjava/lang/Object;)V");
}
else {
v.astore(type); // assumes array and index are on the stack
}
}
@Override
@@ -5,6 +5,7 @@ import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
@@ -17,7 +18,33 @@ public class ArraySize implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
v.arraylength();
if(receiver.type.equals(JetTypeMapper.TYPE_OBJECT)) {
v.visitTypeInsn(Opcodes.CHECKCAST, "jet/arrays/JetArray");
v.invokevirtual("jet/arrays/JetArray", "getSize", "()I");
}
else {
if(receiver.type.equals(JetTypeMapper.ARRAY_BYTE_TYPE))
v.getfield(receiver.type.getInternalName(), "array", "[B");
else if(receiver.type.equals(JetTypeMapper.ARRAY_SHORT_TYPE))
v.getfield(receiver.type.getInternalName(), "array", "[S");
else if(receiver.type.equals(JetTypeMapper.ARRAY_INT_TYPE))
v.getfield(receiver.type.getInternalName(), "array", "[I");
else if(receiver.type.equals(JetTypeMapper.ARRAY_LONG_TYPE))
v.getfield(receiver.type.getInternalName(), "array", "[J");
else if(receiver.type.equals(JetTypeMapper.ARRAY_FLOAT_TYPE))
v.getfield(receiver.type.getInternalName(), "array", "[F");
else if(receiver.type.equals(JetTypeMapper.ARRAY_DOUBLE_TYPE))
v.getfield(receiver.type.getInternalName(), "array", "[D");
else if(receiver.type.equals(JetTypeMapper.ARRAY_CHAR_TYPE))
v.getfield(receiver.type.getInternalName(), "array", "[C");
else if(receiver.type.equals(JetTypeMapper.ARRAY_BOOL_TYPE))
v.getfield(receiver.type.getInternalName(), "array", "[Z");
else
v.getfield("jet/arrays/JetGenericArray", "array", "[Ljava/lang/Object;");
v.arraylength();
}
return StackValue.onStack(Type.INT_TYPE);
}
}
@@ -63,22 +63,23 @@ public class JetStandardLibrary {
private final ClassDescriptor typeInfoClass;
private final JetType byteType;
private final JetType nullableByteType;
private final JetType charType;
private final JetType nullableCharType;
private final JetType shortType;
private final JetType nullableShortType;
private final JetType intType;
private final JetType nullableIntType;
private final JetType longType;
private final JetType nullableLongType;
private final JetType floatType;
private final JetType nullableFloatType;
private final JetType doubleType;
private final JetType nullableDoubleType;
private final JetType booleanType;
private final JetType nullableBooleanType;
private final JetType stringType;
private final JetType nullableByteType;
private final JetType nullableCharType;
private final JetType nullableShortType;
private final JetType nullableIntType;
private final JetType nullableLongType;
private final JetType nullableFloatType;
private final JetType nullableDoubleType;
private final JetType nullableBooleanType;
private final JetType nullableTuple0Type;
public JetType getTuple0Type() {