massive refactoring of CodegenUtil

- generation method names standartized on genXXX
- many methods moved to newly created AsmUtil
- some methods moved to CodegenContext
- got rid of almost trivial StubCodegen
This commit is contained in:
Alex Tkachman
2012-09-20 20:19:01 +03:00
parent c355e182e8
commit bc1a4a1fe9
31 changed files with 663 additions and 635 deletions
@@ -0,0 +1,420 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.codegen;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Label;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.CodegenUtil.isInterface;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
/**
* @author alex.tkachman
*/
public class AsmUtil {
private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet(
JetStandardLibrary.getInstance().getByte(),
JetStandardLibrary.getInstance().getShort(),
JetStandardLibrary.getInstance().getInt(),
JetStandardLibrary.getInstance().getLong(),
JetStandardLibrary.getInstance().getFloat(),
JetStandardLibrary.getInstance().getDouble(),
JetStandardLibrary.getInstance().getChar()
);
private static final int NO_FLAG_LOCAL = 0;
private static final int NO_FLAG_PACKAGE_PRIVATE = 0;
@NotNull
private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder()
.put(Visibilities.PRIVATE, ACC_PRIVATE)
.put(Visibilities.PROTECTED, ACC_PROTECTED)
.put(Visibilities.PUBLIC, ACC_PUBLIC)
.put(Visibilities.INTERNAL, ACC_PUBLIC)
.put(Visibilities.LOCAL, NO_FLAG_LOCAL)
.put(JavaDescriptorResolver.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE)
.build();
public static final String RECEIVER$0 = "receiver$0";
public static final String THIS$0 = "this$0";
private static final String STUB_EXCEPTION = "java/lang/RuntimeException";
private static final String STUB_EXCEPTION_MESSAGE = "Stubs are for compiler only, do not add them to runtime classpath";
private AsmUtil() {
}
public static Type boxType(Type asmType) {
JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByAsmType(asmType);
if (jvmPrimitiveType != null) {
return jvmPrimitiveType.getWrapper().getAsmType();
}
else {
return asmType;
}
}
public static boolean isIntPrimitive(Type type) {
return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
}
public static boolean isNumberPrimitive(Type type) {
return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
}
public static boolean isPrimitive(Type type) {
return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY;
}
public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) {
if (!(descriptor instanceof ClassDescriptor)) {
return false;
}
return PRIMITIVE_NUMBER_CLASSES.contains(descriptor);
}
public static Type correctElementType(Type type) {
String internalName = type.getInternalName();
assert internalName.charAt(0) == '[';
return Type.getType(internalName.substring(1));
}
public static Type unboxType(final Type type) {
JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByWrapperAsmType(type);
if (jvmPrimitiveType != null) {
return jvmPrimitiveType.getAsmType();
}
else {
throw new UnsupportedOperationException("Unboxing: " + type);
}
}
//TODO: move mapping logic to front-end java
public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) {
Integer specialCase = specialCaseVisibility(descriptor);
if (specialCase != null) {
return specialCase;
}
Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility());
if (defaultMapping == null) {
throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend.");
}
return defaultMapping;
}
@Nullable
private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
if (isInterface(containingDeclaration)) {
return ACC_PUBLIC;
}
Visibility memberVisibility = memberDescriptor.getVisibility();
if (memberVisibility != Visibilities.PRIVATE) {
return null;
}
if (isClassObject(containingDeclaration)) {
return NO_FLAG_PACKAGE_PRIVATE;
}
if (memberDescriptor instanceof ConstructorDescriptor) {
ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind();
if (kind == ClassKind.OBJECT) {
//TODO: should be NO_FLAG_PACKAGE_PRIVATE
// see http://youtrack.jetbrains.com/issue/KT-2700
return ACC_PUBLIC;
}
else if (kind == ClassKind.ENUM_ENTRY) {
return NO_FLAG_PACKAGE_PRIVATE;
}
else if (kind == ClassKind.ENUM_CLASS) {
//TODO: should be ACC_PRIVATE
// see http://youtrack.jetbrains.com/issue/KT-2680
return ACC_PROTECTED;
}
}
if (containingDeclaration instanceof NamespaceDescriptor) {
return ACC_PUBLIC;
}
return null;
}
private static Type stringValueOfOrStringBuilderAppendType(Type type) {
final int sort = type.getSort();
return sort == Type.OBJECT || sort == Type.ARRAY
? AsmTypeConstants.OBJECT_TYPE
: sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
}
public static void genThrow(MethodVisitor mv, String exception, String message) {
InstructionAdapter iv = new InstructionAdapter(mv);
iv.anew(Type.getObjectType(exception));
iv.dup();
iv.aconst(message);
iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
iv.athrow();
}
public static void genMethodThrow(MethodVisitor mv, String exception, String message) {
mv.visitCode();
genThrow(mv, exception, message);
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
final ClassifierDescriptor captureThis = closure.getCaptureThis();
final int access = ACC_PUBLIC | ACC_SYNTHETIC | ACC_FINAL;
if (captureThis != null) {
v.newField(null, access, THIS$0, typeMapper.mapType(captureThis).getDescriptor(), null,
null);
}
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) {
v.newField(null, access, RECEIVER$0, typeMapper.mapType(captureReceiver).getDescriptor(),
null, null);
}
final List<Pair<String, Type>> fields = closure.getRecordedFields();
for (Pair<String, Type> field : fields) {
v.newField(null, access, field.first, field.second.getDescriptor(), null, null);
}
}
public static void genInitSingletonField(Type classAsmType, InstructionAdapter iv) {
iv.anew(classAsmType);
iv.dup();
iv.invokespecial(classAsmType.getInternalName(), "<init>", "()V");
iv.putstatic(classAsmType.getInternalName(), JvmAbi.INSTANCE_FIELD, classAsmType.getDescriptor());
}
public static void genStringBuilderConstructor(InstructionAdapter v) {
v.visitTypeInsn(NEW, "java/lang/StringBuilder");
v.dup();
v.invokespecial("java/lang/StringBuilder", "<init>", "()V");
}
public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
type = stringValueOfOrStringBuilderAppendType(type);
v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;");
}
public static StackValue genToString(InstructionAdapter v, StackValue receiver) {
final Type type = stringValueOfOrStringBuilderAppendType(receiver.type);
receiver.put(type, v);
v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;");
return StackValue.onStack(JAVA_STRING_TYPE);
}
static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
if (type.getSort() == Type.ARRAY) {
final Type elementType = correctElementType(type);
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I");
}
else {
iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I");
}
}
else if (type.getSort() == Type.OBJECT) {
iv.invokevirtual("java/lang/Object", "hashCode", "()I");
}
else if (type.getSort() == Type.LONG) {
genLongHashCode(mv, iv);
}
else if (type.getSort() == Type.DOUBLE) {
iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J");
genLongHashCode(mv, iv);
}
else if (type.getSort() == Type.FLOAT) {
iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I");
}
else if (type.getSort() == Type.BOOLEAN) {
Label end = new Label();
iv.dup();
iv.ifeq(end);
iv.pop();
iv.iconst(1);
iv.mark(end);
}
else { // byte short char int
// do nothing
}
}
private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
iv.dup2();
iv.iconst(32);
iv.ushr(Type.LONG_TYPE);
iv.xor(Type.LONG_TYPE);
mv.visitInsn(L2I);
}
static StackValue compareExpressionsOnStack(InstructionAdapter v, IElementType opToken, Type operandType) {
if (operandType.getSort() == Type.OBJECT) {
v.invokeinterface("java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I");
v.iconst(0);
operandType = Type.INT_TYPE;
}
return StackValue.cmp(opToken, operandType);
}
static StackValue genNullSafeEquals(
InstructionAdapter v,
IElementType opToken,
boolean leftNullable,
boolean rightNullable
) {
if (!leftNullable) {
v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ) {
genInvertBoolean(v);
}
}
else {
if (rightNullable) {
v.dup2(); // left right left right
Label rightNull = new Label();
v.ifnull(rightNull);
Label leftNull = new Label();
v.ifnull(leftNull);
v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
genInvertBoolean(v);
}
Label end = new Label();
v.goTo(end);
v.mark(rightNull);
// left right left
Label bothNull = new Label();
v.ifnull(bothNull);
v.mark(leftNull);
v.pop2();
v.iconst(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ ? 1 : 0);
v.goTo(end);
v.mark(bothNull);
v.pop2();
v.iconst(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ ? 0 : 1);
v.mark(end);
}
else {
v.dup2(); // left right left right
v.pop();
Label leftNull = new Label();
v.ifnull(leftNull);
v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
genInvertBoolean(v);
}
Label end = new Label();
v.goTo(end);
// left right
v.mark(leftNull);
v.pop2();
v.iconst(opToken == JetTokens.EXCLEQ ? 1 : 0);
v.mark(end);
}
}
return StackValue.onStack(Type.BOOLEAN_TYPE);
}
static void genInvertBoolean(InstructionAdapter v) {
v.iconst(1);
v.xor(Type.INT_TYPE);
}
public static StackValue genEqualsForExpressionsOnStack(
InstructionAdapter v,
IElementType opToken,
Type leftType,
Type rightType,
boolean leftNullable,
boolean rightNullable
) {
if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) {
return compareExpressionsOnStack(v, opToken, leftType);
}
else {
if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
return StackValue.cmp(opToken, leftType);
}
else {
return genNullSafeEquals(v, opToken, leftNullable, rightNullable);
}
}
}
public static Type genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
if (expectedType == Type.LONG_TYPE) {
//noinspection UnnecessaryBoxing
v.lconst(myDelta);
}
else if (expectedType == Type.FLOAT_TYPE) {
//noinspection UnnecessaryBoxing
v.fconst(myDelta);
}
else if (expectedType == Type.DOUBLE_TYPE) {
//noinspection UnnecessaryBoxing
v.dconst(myDelta);
}
else {
v.iconst(myDelta);
expectedType = Type.INT_TYPE;
}
v.add(expectedType);
return expectedType;
}
public static Type genNegate(Type expectedType, InstructionAdapter v) {
if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) {
expectedType = Type.INT_TYPE;
}
v.neg(expectedType);
return expectedType;
}
public static void genStubThrow(MethodVisitor mv) {
genThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
}
public static void genStubCode(MethodVisitor mv) {
genMethodThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
}
}
@@ -34,8 +34,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.CodegenUtil.generateMethodThrow; import static org.jetbrains.jet.codegen.AsmUtil.genMethodThrow;
import static org.jetbrains.jet.codegen.CodegenUtil.getVisibilityAccessFlag; import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag;
/** /**
* @author max * @author max
@@ -89,7 +89,7 @@ public abstract class ClassBodyCodegen extends GenerationStateAware {
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) { if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
CodegenUtil.generateFunctionOrProperty(state, (JetTypeParameterListOwner) declaration, context, v); context.genFunctionOrProperty(state, (JetTypeParameterListOwner) declaration, v);
} }
} }
@@ -146,7 +146,7 @@ public abstract class ClassBodyCodegen extends GenerationStateAware {
// generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator // generates stub 'remove' function for subclasses of Iterator to be compatible with java.util.Iterator
if (DescriptorUtils.isIteratorWithoutRemoveImpl(descriptor)) { if (DescriptorUtils.isIteratorWithoutRemoveImpl(descriptor)) {
final MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "remove", "()V", null, null); final MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "remove", "()V", null, null);
generateMethodThrow(mv, "java/lang/UnsupportedOperationException", "Mutating method called on a Kotlin Iterator"); genMethodThrow(mv, "java/lang/UnsupportedOperationException", "Mutating method called on a Kotlin Iterator");
} }
} }
} }
@@ -28,6 +28,8 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive;
/** /**
* @author max * @author max
* @author alex.tkachman * @author alex.tkachman
@@ -114,7 +116,7 @@ public final class ClassFileFactory extends GenerationStateAware {
public ClassBuilder forClassImplementation(ClassDescriptor aClass) { public ClassBuilder forClassImplementation(ClassDescriptor aClass) {
Type type = state.getTypeMapper().mapType(aClass.getDefaultType(), JetTypeMapperMode.IMPL); Type type = state.getTypeMapper().mapType(aClass.getDefaultType(), JetTypeMapperMode.IMPL);
if (CodegenUtil.isPrimitive(type)) { if (isPrimitive(type)) {
throw new IllegalStateException("Codegen for primitive type is not possible: " + aClass); throw new IllegalStateException("Codegen for primitive type is not possible: " + aClass);
} }
return newVisitor(type.getInternalName() + ".class"); return newVisitor(type.getInternalName() + ".class");
@@ -49,6 +49,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.classNameForAnonymousClass; import static org.jetbrains.jet.codegen.binding.CodegenBinding.classNameForAnonymousClass;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun; import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
@@ -108,7 +109,7 @@ public class ClosureCodegen extends GenerationStateAware {
generateConstInstance(fun, cv); generateConstInstance(fun, cv);
} }
generateClosureFields(closure, cv, state.getTypeMapper()); genClosureFields(closure, cv, state.getTypeMapper());
cv.done(); cv.done();
@@ -122,11 +123,11 @@ public class ClosureCodegen extends GenerationStateAware {
cv.newField(fun, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, JvmAbi.INSTANCE_FIELD, name.getDescriptor(), null, null); cv.newField(fun, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, JvmAbi.INSTANCE_FIELD, name.getDescriptor(), null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
initSingletonField(name.getAsmType(), iv); genInitSingletonField(name.getAsmType(), iv);
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
FunctionCodegen.endVisit(mv, "<clinit>", fun); FunctionCodegen.endVisit(mv, "<clinit>", fun);
} }
@@ -164,7 +165,7 @@ public class ClosureCodegen extends GenerationStateAware {
cv.newMethod(fun, ACC_PUBLIC | ACC_BRIDGE | ACC_VOLATILE, "invoke", bridge.getAsmMethod().getDescriptor(), null, cv.newMethod(fun, ACC_PUBLIC | ACC_BRIDGE | ACC_VOLATILE, "invoke", bridge.getAsmMethod().getDescriptor(), null,
new String[0]); new String[0]);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
@@ -212,7 +213,7 @@ public class ClosureCodegen extends GenerationStateAware {
final Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); final Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
final MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]); final MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
@@ -16,44 +16,29 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.Stack; import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Label;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.signature.BothSignatureWriter; import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.JetClassObject;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*; import java.util.*;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
/** /**
@@ -61,31 +46,6 @@ import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
* @author alex.tkachman * @author alex.tkachman
*/ */
public class CodegenUtil { public class CodegenUtil {
public static final String RECEIVER$0 = "receiver$0";
public static final String THIS$0 = "this$0";
private static final int NO_FLAG_LOCAL = 0;
private static final int NO_FLAG_PACKAGE_PRIVATE = 0;
@NotNull
private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder()
.put(Visibilities.PRIVATE, ACC_PRIVATE)
.put(Visibilities.PROTECTED, ACC_PROTECTED)
.put(Visibilities.PUBLIC, ACC_PUBLIC)
.put(Visibilities.INTERNAL, ACC_PUBLIC)
.put(Visibilities.LOCAL, NO_FLAG_LOCAL)
.put(JavaDescriptorResolver.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE)
.build();
private static final Set<ClassDescriptor> PRIMITIVE_NUMBER_CLASSES = Sets.newHashSet(
JetStandardLibrary.getInstance().getByte(),
JetStandardLibrary.getInstance().getShort(),
JetStandardLibrary.getInstance().getInt(),
JetStandardLibrary.getInstance().getLong(),
JetStandardLibrary.getInstance().getFloat(),
JetStandardLibrary.getInstance().getDouble(),
JetStandardLibrary.getInstance().getChar()
);
private CodegenUtil() { private CodegenUtil() {
} }
@@ -130,7 +90,7 @@ public class CodegenUtil {
} }
public static String generateTmpVariableName(Collection<String> existingNames) { public static String createTmpVariableName(Collection<String> existingNames) {
String prefix = "tmp"; String prefix = "tmp";
int i = RANDOM.nextInt(Integer.MAX_VALUE); int i = RANDOM.nextInt(Integer.MAX_VALUE);
String name = prefix + i; String name = prefix + i;
@@ -142,9 +102,8 @@ public class CodegenUtil {
} }
public static
@NotNull @NotNull
BitSet getFlagsForVisibility(@NotNull Visibility visibility) { public static BitSet getFlagsForVisibility(@NotNull Visibility visibility) {
BitSet flags = new BitSet(); BitSet flags = new BitSet();
if (visibility == Visibilities.INTERNAL) { if (visibility == Visibilities.INTERNAL) {
flags.set(JvmStdlibNames.FLAG_INTERNAL_BIT); flags.set(JvmStdlibNames.FLAG_INTERNAL_BIT);
@@ -155,22 +114,6 @@ public class CodegenUtil {
return flags; return flags;
} }
public static void generateThrow(MethodVisitor mv, String exception, String message) {
InstructionAdapter iv = new InstructionAdapter(mv);
iv.anew(Type.getObjectType(exception));
iv.dup();
iv.aconst(message);
iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
iv.athrow();
}
public static void generateMethodThrow(MethodVisitor mv, String exception, String message) {
mv.visitCode();
generateThrow(mv, exception, message);
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
@NotNull @NotNull
public static JvmClassName getInternalClassName(FunctionDescriptor descriptor) { public static JvmClassName getInternalClassName(FunctionDescriptor descriptor) {
final int paramCount = descriptor.getValueParameters().size(); final int paramCount = descriptor.getValueParameters().size();
@@ -216,123 +159,10 @@ public class CodegenUtil {
return closure.getCaptureThis() == null && closure.getCaptureReceiver() == null && closure.getCaptureVariables().isEmpty(); return closure.getCaptureThis() == null && closure.getCaptureReceiver() == null && closure.getCaptureVariables().isEmpty();
} }
public static void generateClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
final ClassifierDescriptor captureThis = closure.getCaptureThis();
final int access = ACC_PUBLIC | ACC_SYNTHETIC | ACC_FINAL;
if (captureThis != null) {
v.newField(null, access, THIS$0, typeMapper.mapType(captureThis).getDescriptor(), null,
null);
}
final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) {
v.newField(null, access, RECEIVER$0, typeMapper.mapType(captureReceiver).getDescriptor(),
null, null);
}
final List<Pair<String, Type>> fields = closure.getRecordedFields();
for (Pair<String, Type> field : fields) {
v.newField(null, access, field.first, field.second.getDescriptor(), null, null);
}
}
public static <T> T peekFromStack(Stack<T> stack) { public static <T> T peekFromStack(Stack<T> stack) {
return stack.empty() ? null : stack.peek(); return stack.empty() ? null : stack.peek();
} }
//TODO: move mapping logic to front-end java
public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) {
Integer specialCase = specialCaseVisibility(descriptor);
if (specialCase != null) {
return specialCase;
}
Integer defaultMapping = visibilityToAccessFlag.get(descriptor.getVisibility());
if (defaultMapping == null) {
throw new IllegalStateException(descriptor.getVisibility() + " is not a valid visibility in backend.");
}
return defaultMapping;
}
@Nullable
private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
if (isInterface(containingDeclaration)) {
return ACC_PUBLIC;
}
Visibility memberVisibility = memberDescriptor.getVisibility();
if (memberVisibility != Visibilities.PRIVATE) {
return null;
}
if (isClassObject(containingDeclaration)) {
return NO_FLAG_PACKAGE_PRIVATE;
}
if (memberDescriptor instanceof ConstructorDescriptor) {
ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind();
if (kind == ClassKind.OBJECT) {
//TODO: should be NO_FLAG_PACKAGE_PRIVATE
// see http://youtrack.jetbrains.com/issue/KT-2700
return ACC_PUBLIC;
}
else if (kind == ClassKind.ENUM_ENTRY) {
return NO_FLAG_PACKAGE_PRIVATE;
}
else if (kind == ClassKind.ENUM_CLASS) {
//TODO: should be ACC_PRIVATE
// see http://youtrack.jetbrains.com/issue/KT-2680
return ACC_PROTECTED;
}
}
if (containingDeclaration instanceof NamespaceDescriptor) {
return ACC_PUBLIC;
}
return null;
}
public static Type unboxType(final Type type) {
JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByWrapperAsmType(type);
if (jvmPrimitiveType != null) {
return jvmPrimitiveType.getAsmType();
}
else {
throw new UnsupportedOperationException("Unboxing: " + type);
}
}
public static Type boxType(Type asmType) {
JvmPrimitiveType jvmPrimitiveType = JvmPrimitiveType.getByAsmType(asmType);
if (jvmPrimitiveType != null) {
return jvmPrimitiveType.getWrapper().getAsmType();
}
else {
return asmType;
}
}
public static boolean isIntPrimitive(Type type) {
return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
}
public static boolean isNumberPrimitive(Type type) {
return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
}
public static boolean isPrimitive(Type type) {
return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY;
}
public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) {
if (!(descriptor instanceof ClassDescriptor)) {
return false;
}
return PRIMITIVE_NUMBER_CLASSES.contains(descriptor);
}
public static Type correctElementType(Type type) {
String internalName = type.getInternalName();
assert internalName.charAt(0) == '[';
return Type.getType(internalName.substring(1));
}
@Nullable @Nullable
public static String getLocalNameForObject(JetObjectDeclaration object) { public static String getLocalNameForObject(JetObjectDeclaration object) {
PsiElement parent = object.getParent(); PsiElement parent = object.getParent();
@@ -369,309 +199,4 @@ public class CodegenUtil {
throw new IllegalStateException("code generation for synthesized members should be handled separately"); throw new IllegalStateException("code generation for synthesized members should be handled separately");
} }
} }
public static void initSingletonField(Type classAsmType, InstructionAdapter iv) {
iv.anew(classAsmType);
iv.dup();
iv.invokespecial(classAsmType.getInternalName(), "<init>", "()V");
iv.putstatic(classAsmType.getInternalName(), JvmAbi.INSTANCE_FIELD, classAsmType.getDescriptor());
}
public static void generateStringBuilderConstructor(InstructionAdapter v) {
v.visitTypeInsn(NEW, "java/lang/StringBuilder");
v.dup();
v.invokespecial("java/lang/StringBuilder", "<init>", "()V");
}
public static void invokeAppendMethod(InstructionAdapter v, Type type) {
type = getStringValueOfOrStringBuilderAppendType(type);
v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;");
}
public static StackValue genToString(InstructionAdapter v, StackValue receiver) {
final Type type = getStringValueOfOrStringBuilderAppendType(receiver.type);
receiver.put(type, v);
v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;");
return StackValue.onStack(JAVA_STRING_TYPE);
}
private static Type getStringValueOfOrStringBuilderAppendType(Type type) {
final int sort = type.getSort();
return sort == Type.OBJECT || sort == Type.ARRAY
? AsmTypeConstants.OBJECT_TYPE
: sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
}
static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
if (type.getSort() == Type.ARRAY) {
final Type elementType = correctElementType(type);
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I");
}
else {
iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I");
}
}
else if (type.getSort() == Type.OBJECT) {
iv.invokevirtual("java/lang/Object", "hashCode", "()I");
}
else if (type.getSort() == Type.LONG) {
genLongHashCode(mv, iv);
}
else if (type.getSort() == Type.DOUBLE) {
iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J");
genLongHashCode(mv, iv);
}
else if (type.getSort() == Type.FLOAT) {
iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I");
}
else if (type.getSort() == Type.BOOLEAN) {
Label end = new Label();
iv.dup();
iv.ifeq(end);
iv.pop();
iv.iconst(1);
iv.mark(end);
}
else { // byte short char int
// do nothing
}
}
private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
iv.dup2();
iv.iconst(32);
iv.ushr(Type.LONG_TYPE);
iv.xor(Type.LONG_TYPE);
mv.visitInsn(L2I);
}
static StackValue compareExpressionsOnStack(InstructionAdapter v, IElementType opToken, Type operandType) {
if (operandType.getSort() == Type.OBJECT) {
v.invokeinterface("java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I");
v.iconst(0);
operandType = Type.INT_TYPE;
}
return StackValue.cmp(opToken, operandType);
}
static StackValue generateNullSafeEquals(
InstructionAdapter v,
IElementType opToken,
boolean leftNullable,
boolean rightNullable
) {
if (!leftNullable) {
v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ) {
invertBoolean(v);
}
}
else {
if (rightNullable) {
v.dup2(); // left right left right
Label rightNull = new Label();
v.ifnull(rightNull);
Label leftNull = new Label();
v.ifnull(leftNull);
v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
invertBoolean(v);
}
Label end = new Label();
v.goTo(end);
v.mark(rightNull);
// left right left
Label bothNull = new Label();
v.ifnull(bothNull);
v.mark(leftNull);
v.pop2();
v.iconst(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ ? 1 : 0);
v.goTo(end);
v.mark(bothNull);
v.pop2();
v.iconst(opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ ? 0 : 1);
v.mark(end);
}
else {
v.dup2(); // left right left right
v.pop();
Label leftNull = new Label();
v.ifnull(leftNull);
v.invokevirtual("java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
invertBoolean(v);
}
Label end = new Label();
v.goTo(end);
// left right
v.mark(leftNull);
v.pop2();
v.iconst(opToken == JetTokens.EXCLEQ ? 1 : 0);
v.mark(end);
}
}
return StackValue.onStack(Type.BOOLEAN_TYPE);
}
static void invertBoolean(InstructionAdapter v) {
v.iconst(1);
v.xor(Type.INT_TYPE);
}
public static StackValue generateEqualsForExpressionsOnStack(
InstructionAdapter v,
IElementType opToken,
Type leftType,
Type rightType,
boolean leftNullable,
boolean rightNullable
) {
if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) {
return compareExpressionsOnStack(v, opToken, leftType);
}
else {
if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
return StackValue.cmp(opToken, leftType);
}
else {
return generateNullSafeEquals(v, opToken, leftNullable, rightNullable);
}
}
}
public static Type genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
if (expectedType == Type.LONG_TYPE) {
//noinspection UnnecessaryBoxing
v.lconst(myDelta);
}
else if (expectedType == Type.FLOAT_TYPE) {
//noinspection UnnecessaryBoxing
v.fconst(myDelta);
}
else if (expectedType == Type.DOUBLE_TYPE) {
//noinspection UnnecessaryBoxing
v.dconst(myDelta);
}
else {
v.iconst(myDelta);
expectedType = Type.INT_TYPE;
}
v.add(expectedType);
return expectedType;
}
public static Type genNegate(Type expectedType, InstructionAdapter v) {
if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) {
expectedType = Type.INT_TYPE;
}
v.neg(expectedType);
return expectedType;
}
public static void generate(GenerationState state, CodegenContext context, JetClassOrObject aClass) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
if (descriptor == null || ErrorUtils.isError(descriptor) || descriptor.getName().equals(JetPsiUtil.NO_NAME_PROVIDED)) {
if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES) {
throw new IllegalStateException(
"Generating bad descriptor in ClassBuilderMode = " + state.getClassBuilderMode() + ": " + descriptor);
}
return;
}
ClassBuilder classBuilder = state.getFactory().forClassImplementation(descriptor);
final CodegenContext contextForInners = context.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state);
if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) {
// Outer class implementation must happen prior inner classes so we get proper scoping tree in JetLightClass's delegate
// The same code is present below for the case when we generate real bytecode. This is because the order should be
// different for the case when we compute closures
generateImplementation(state, context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder);
}
genInners(state, aClass, contextForInners);
if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES) {
generateImplementation(state, context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder);
}
classBuilder.done();
}
public static void genInners(GenerationState state, JetClassOrObject aClass, CodegenContext contextForInners) {
for (JetDeclaration declaration : aClass.getDeclarations()) {
if (declaration instanceof JetClass) {
if (declaration instanceof JetEnumEntry && !enumEntryNeedSubclass(
state.getBindingContext(), (JetEnumEntry) declaration)) {
continue;
}
generate(state, contextForInners, (JetClass) declaration);
}
else if (declaration instanceof JetClassObject) {
generate(state, contextForInners, ((JetClassObject) declaration).getObjectDeclaration());
}
else if (declaration instanceof JetObjectDeclaration) {
generate(state, contextForInners, (JetObjectDeclaration) declaration);
}
}
}
private static void generateImplementation(
GenerationState state,
CodegenContext context,
JetClassOrObject aClass,
OwnerKind kind,
Map<DeclarationDescriptor, DeclarationDescriptor> accessors,
ClassBuilder classBuilder
) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
CodegenContext classContext = context.intoClass(descriptor, kind, state);
classContext.copyAccessors(accessors);
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate();
if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
ClassBuilder traitBuilder = state.getFactory().forTraitImplementation(descriptor, state);
new TraitImplBodyCodegen(aClass, context.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state)
.generate();
traitBuilder.done();
}
}
public static void generateFunctionOrProperty(
GenerationState state,
@NotNull JetTypeParameterListOwner functionOrProperty,
@NotNull CodegenContext context, @NotNull ClassBuilder classBuilder
) {
FunctionCodegen functionCodegen = new FunctionCodegen(context, classBuilder, state);
if (functionOrProperty instanceof JetNamedFunction) {
try {
functionCodegen.gen((JetNamedFunction) functionOrProperty);
}
catch (CompilationException e) {
throw e;
}
catch (Exception e) {
throw new CompilationException("Failed to generate function " + functionOrProperty.getName(), e, functionOrProperty);
}
}
else if (functionOrProperty instanceof JetProperty) {
try {
new PropertyCodegen(context, classBuilder, functionCodegen).gen((JetProperty) functionOrProperty);
}
catch (CompilationException e) {
throw e;
}
catch (Exception e) {
throw new CompilationException("Failed to generate property " + functionOrProperty.getName(), e, functionOrProperty);
}
}
else {
throw new IllegalArgumentException("Unknown parameter: " + functionOrProperty);
}
}
} }
@@ -30,7 +30,7 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
public class CompilationException extends RuntimeException { public class CompilationException extends RuntimeException {
private final PsiElement element; private final PsiElement element;
CompilationException(@NotNull String message, @Nullable Throwable cause, @NotNull PsiElement element) { public CompilationException(@NotNull String message, @Nullable Throwable cause, @NotNull PsiElement element) {
super(message, cause); super(message, cause);
this.element = element; this.element = element;
} }
@@ -61,6 +61,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.*; import java.util.*;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*;
@@ -117,7 +118,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
final CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor); final CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor);
final CodegenContext contextForInners = context.intoClass(classDescriptor, OwnerKind.IMPLEMENTATION, state); final CodegenContext contextForInners = context.intoClass(classDescriptor, OwnerKind.IMPLEMENTATION, state);
genInners(state, objectDeclaration, contextForInners); contextForInners.genInners(state, objectDeclaration);
final CodegenContext objectContext = context.intoAnonymousClass(classDescriptor, this); final CodegenContext objectContext = context.intoAnonymousClass(classDescriptor, this);
objectContext.copyAccessors(contextForInners.getAccessors()); objectContext.copyAccessors(contextForInners.getAccessors());
@@ -994,7 +995,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return StackValue.constant(constantValue.toString(), type); return StackValue.constant(constantValue.toString(), type);
} }
else { else {
generateStringBuilderConstructor(v); genStringBuilderConstructor(v);
for (JetStringTemplateEntry entry : entries) { for (JetStringTemplateEntry entry : entries) {
if (entry instanceof JetStringTemplateEntryWithExpression) { if (entry instanceof JetStringTemplateEntryWithExpression) {
invokeAppend(entry.getExpression()); invokeAppend(entry.getExpression());
@@ -1004,7 +1005,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
? ((JetEscapeStringTemplateEntry) entry).getUnescapedValue() ? ((JetEscapeStringTemplateEntry) entry).getUnescapedValue()
: entry.getText(); : entry.getText();
v.aconst(text); v.aconst(text);
invokeAppendMethod(v, JAVA_STRING_TYPE); genInvokeAppendMethod(v, JAVA_STRING_TYPE);
} }
} }
v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;"); v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
@@ -1665,9 +1666,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
PropertySetterDescriptor setter = propertyDescriptor.getSetter(); PropertySetterDescriptor setter = propertyDescriptor.getSetter();
PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
final int flag = CodegenUtil.getVisibilityAccessFlag(propertyDescriptor) | final int flag = getVisibilityAccessFlag(propertyDescriptor) |
(getter == null ? 0 : CodegenUtil.getVisibilityAccessFlag(getter)) | (getter == null ? 0 : getVisibilityAccessFlag(getter)) |
(setter == null ? 0 : CodegenUtil.getVisibilityAccessFlag(setter)); (setter == null ? 0 : getVisibilityAccessFlag(setter));
if ((flag & ACC_PRIVATE) == 0) { if ((flag & ACC_PRIVATE) == 0) {
return propertyDescriptor; return propertyDescriptor;
@@ -1677,7 +1678,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
} }
private FunctionDescriptor accessableFunctionDescriptor(FunctionDescriptor fd) { private FunctionDescriptor accessableFunctionDescriptor(FunctionDescriptor fd) {
final int flag = CodegenUtil.getVisibilityAccessFlag(fd); final int flag = getVisibilityAccessFlag(fd);
if ((flag & ACC_PRIVATE) == 0) { if ((flag & ACC_PRIVATE) == 0) {
return fd; return fd;
} }
@@ -2261,7 +2262,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
else { else {
invokeFunctionByReference(expression.getOperationReference()); invokeFunctionByReference(expression.getOperationReference());
if (inverted) { if (inverted) {
invertBoolean(v); genInvertBoolean(v);
} }
} }
return StackValue.onStack(Type.BOOLEAN_TYPE); return StackValue.onStack(Type.BOOLEAN_TYPE);
@@ -2302,7 +2303,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
v.and(Type.INT_TYPE); v.and(Type.INT_TYPE);
if (inverted) { if (inverted) {
invertBoolean(v); genInvertBoolean(v);
} }
} }
@@ -2362,10 +2363,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
if (isPrimitive(leftType)) // both are primitive if (isPrimitive(leftType)) // both are primitive
{ {
return generateEqualsForExpressionsOnStack(v, opToken, leftType, rightType, false, false); return genEqualsForExpressionsOnStack(v, opToken, leftType, rightType, false, false);
} }
return generateEqualsForExpressionsOnStack(v, opToken, leftType, rightType, leftJetType.isNullable(), rightJetType.isNullable()); return
genEqualsForExpressionsOnStack(v, opToken, leftType, rightType, leftJetType.isNullable(), rightJetType.isNullable());
} }
private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) { private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) {
@@ -2514,7 +2516,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
} }
Type exprType = expressionType(expr); Type exprType = expressionType(expr);
gen(expr, exprType); gen(expr, exprType);
invokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType); genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType);
} }
@Nullable @Nullable
@@ -3187,10 +3189,10 @@ The "returned" value of try expression with no finally is either the last expres
boolean patternIsNullable = false; boolean patternIsNullable = false;
JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, patternExpression); JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, patternExpression);
Type condType; Type condType;
if (CodegenUtil.isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) { if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
assert condJetType != null; assert condJetType != null;
condType = asmType(condJetType); condType = asmType(condJetType);
if (!(CodegenUtil.isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) { if (!(isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) {
subjectType = boxType(subjectType); subjectType = boxType(subjectType);
expressionToMatch.coerceTo(subjectType, v); expressionToMatch.coerceTo(subjectType, v);
} }
@@ -3200,8 +3202,8 @@ The "returned" value of try expression with no finally is either the last expres
patternIsNullable = condJetType != null && condJetType.isNullable(); patternIsNullable = condJetType != null && condJetType.isNullable();
} }
gen(patternExpression, condType); gen(patternExpression, condType);
return generateEqualsForExpressionsOnStack(v, JetTokens.EQEQ, subjectType, condType, expressionToMatchIsNullable, return genEqualsForExpressionsOnStack(v, JetTokens.EQEQ, subjectType, condType, expressionToMatchIsNullable,
patternIsNullable); patternIsNullable);
} }
else { else {
return gen(patternExpression); return gen(patternExpression);
@@ -3326,7 +3328,7 @@ The "returned" value of try expression with no finally is either the last expres
//invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v); //invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v);
invokeFunctionByReference(operationReference); invokeFunctionByReference(operationReference);
if (inverted) { if (inverted) {
invertBoolean(v); genInvertBoolean(v);
} }
} }
return StackValue.onStack(Type.BOOLEAN_TYPE); return StackValue.onStack(Type.BOOLEAN_TYPE);
@@ -48,6 +48,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import java.util.*; import java.util.*;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalFun; import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalFun;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
@@ -130,7 +131,7 @@ public class FunctionCodegen extends GenerationStateAware {
} }
if (!isAbstract && state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (!isAbstract && state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
@@ -258,7 +259,7 @@ public class FunctionCodegen extends GenerationStateAware {
Type sharedVarType = state.getTypeMapper().getSharedVarType(parameter); Type sharedVarType = state.getTypeMapper().getSharedVarType(parameter);
mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, divideLabel, k); mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, divideLabel, k);
String nameForSharedVar = generateTmpVariableName(localVariableNames); String nameForSharedVar = createTmpVariableName(localVariableNames);
localVariableNames.add(nameForSharedVar); localVariableNames.add(nameForSharedVar);
mv.visitLocalVariable(nameForSharedVar, sharedVarType.getDescriptor(), null, divideLabel, methodEnd, k); mv.visitLocalVariable(nameForSharedVar, sharedVarType.getDescriptor(), null, divideLabel, methodEnd, k);
@@ -516,7 +517,7 @@ public class FunctionCodegen extends GenerationStateAware {
descriptor, null, null); descriptor, null, null);
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
generateDefaultImpl(owner, state, jvmSignature, functionDescriptor, kind, receiverParameter, hasReceiver, isStatic, generateDefaultImpl(owner, state, jvmSignature, functionDescriptor, kind, receiverParameter, hasReceiver, isStatic,
@@ -684,7 +685,7 @@ public class FunctionCodegen extends GenerationStateAware {
final MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null); final MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
@@ -738,7 +739,7 @@ public class FunctionCodegen extends GenerationStateAware {
final MethodVisitor mv = v.newMethod(null, flags, method.getName(), method.getDescriptor(), null, null); final MethodVisitor mv = v.newMethod(null, flags, method.getName(), method.getDescriptor(), null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
@@ -19,8 +19,6 @@ package org.jetbrains.jet.codegen;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.AnnotationVisitor; import org.jetbrains.asm4.AnnotationVisitor;
@@ -43,7 +41,6 @@ import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
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.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.OverridingUtil; import org.jetbrains.jet.lang.resolve.OverridingUtil;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
@@ -61,6 +58,7 @@ import org.jetbrains.jet.utils.BitSetUtils;
import java.util.*; import java.util.*;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
@@ -394,7 +392,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateFunctionsForDataClasses(); generateFunctionsForDataClasses();
generateClosureFields(context.closure, v, state.getTypeMapper()); genClosureFields(context.closure, v, state.getTypeMapper());
} }
private List<PropertyDescriptor> getDataProperties() { private List<PropertyDescriptor> getDataProperties() {
@@ -451,7 +449,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
genPropertyOnStack(iv, propertyDescriptor, 2); genPropertyOnStack(iv, propertyDescriptor, 2);
if (asmType.getSort() == Type.ARRAY) { if (asmType.getSort() == Type.ARRAY) {
final Type elementType = CodegenUtil.correctElementType(asmType); final Type elementType = correctElementType(asmType);
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
iv.invokestatic("java/util/Arrays", "equals", "([Ljava/lang/Object;[Ljava/lang/Object;)Z"); iv.invokestatic("java/util/Arrays", "equals", "([Ljava/lang/Object;[Ljava/lang/Object;)Z");
} }
@@ -461,7 +459,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
else { else {
final StackValue value = final StackValue value =
generateEqualsForExpressionsOnStack(iv, JetTokens.EQEQ, asmType, asmType, type.isNullable(), type.isNullable()); genEqualsForExpressionsOnStack(iv, JetTokens.EQEQ, asmType, asmType, type.isNullable(), type.isNullable());
value.put(Type.BOOLEAN_TYPE, iv); value.put(Type.BOOLEAN_TYPE, iv);
} }
@@ -530,7 +528,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
final InstructionAdapter iv = new InstructionAdapter(mv); final InstructionAdapter iv = new InstructionAdapter(mv);
mv.visitCode(); mv.visitCode();
generateStringBuilderConstructor(iv); genStringBuilderConstructor(iv);
boolean first = true; boolean first = true;
for (PropertyDescriptor propertyDescriptor : properties) { for (PropertyDescriptor propertyDescriptor : properties) {
@@ -541,7 +539,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
else { else {
iv.aconst(", " + propertyDescriptor.getName().getName()+"="); iv.aconst(", " + propertyDescriptor.getName().getName()+"=");
} }
invokeAppendMethod(iv, JAVA_STRING_TYPE); genInvokeAppendMethod(iv, JAVA_STRING_TYPE);
Type type = genPropertyOnStack(iv, propertyDescriptor, 0); Type type = genPropertyOnStack(iv, propertyDescriptor, 0);
@@ -558,11 +556,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
} }
} }
invokeAppendMethod(iv, type); genInvokeAppendMethod(iv, type);
} }
iv.aconst(")"); iv.aconst(")");
invokeAppendMethod(iv, JAVA_STRING_TYPE); genInvokeAppendMethod(iv, JAVA_STRING_TYPE);
iv.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;"); iv.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
iv.areturn(JAVA_STRING_TYPE); iv.areturn(JAVA_STRING_TYPE);
@@ -673,7 +671,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
MethodVisitor mv = v.newMethod(null, ACC_BRIDGE | ACC_SYNTHETIC | ACC_STATIC, bridge.getName().getName(), MethodVisitor mv = v.newMethod(null, ACC_BRIDGE | ACC_SYNTHETIC | ACC_STATIC, bridge.getName().getName(),
method.getDescriptor(), null, null); method.getDescriptor(), null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
@@ -718,7 +716,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
original, original,
getter.getVisibility()); getter.getVisibility());
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
@@ -753,7 +751,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
original, original,
setter.getVisibility()); setter.getVisibility());
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
@@ -795,7 +793,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
staticInitializerChunks.add(new CodeChunk() { staticInitializerChunks.add(new CodeChunk() {
@Override @Override
public void generate(InstructionAdapter iv) { public void generate(InstructionAdapter iv) {
initSingletonField(classAsmType, iv); genInitSingletonField(classAsmType, iv);
} }
}); });
} }
@@ -841,7 +839,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
writeParameterAnnotations(constructorDescriptor, constructorMethod, hasThis0, mv); writeParameterAnnotations(constructorDescriptor, constructorMethod, hasThis0, mv);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
return; return;
} }
@@ -1238,7 +1236,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
aw.visitEnd(); aw.visitEnd();
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode(); mv.visitCode();
@@ -128,19 +128,17 @@ public class NamespaceCodegen extends GenerationStateAware {
for (JetDeclaration declaration : file.getDeclarations()) { for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor); final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
CodegenUtil.generateFunctionOrProperty( context.genFunctionOrProperty(state, (JetTypeParameterListOwner) declaration, v.getClassBuilder());
state, (JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
} }
else if (declaration instanceof JetNamedFunction) { else if (declaration instanceof JetNamedFunction) {
if (!multiFile) { if (!multiFile) {
final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor); final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
CodegenUtil.generateFunctionOrProperty( context.genFunctionOrProperty(state, (JetTypeParameterListOwner) declaration, v.getClassBuilder());
state, (JetTypeParameterListOwner) declaration, context, v.getClassBuilder());
} }
} }
else if (declaration instanceof JetClassOrObject) { else if (declaration instanceof JetClassOrObject) {
final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor); final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor);
CodegenUtil.generate(state, context, (JetClassOrObject) declaration); context.genClassOrObject(state, (JetClassOrObject) declaration);
} }
else if (declaration instanceof JetScript) { else if (declaration instanceof JetScript) {
state.getScriptCodegen().generate((JetScript) declaration); state.getScriptCodegen().generate((JetScript) declaration);
@@ -176,16 +174,12 @@ public class NamespaceCodegen extends GenerationStateAware {
{ {
final CodegenContext context = final CodegenContext context =
CodegenContext.STATIC.intoNamespace(descriptor); CodegenContext.STATIC.intoNamespace(descriptor);
CodegenUtil context.genFunctionOrProperty(state, (JetTypeParameterListOwner) declaration, builder);
.generateFunctionOrProperty(state, (JetTypeParameterListOwner) declaration,
context, builder);
} }
{ {
final CodegenContext context = final CodegenContext context =
CodegenContext.STATIC.intoNamespacePart(className, descriptor); CodegenContext.STATIC.intoNamespacePart(className, descriptor);
CodegenUtil context.genFunctionOrProperty(state, (JetTypeParameterListOwner) declaration, v.getClassBuilder());
.generateFunctionOrProperty(state, (JetTypeParameterListOwner) declaration,
context, v.getClassBuilder());
} }
} }
} }
@@ -42,6 +42,8 @@ import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import java.util.BitSet; import java.util.BitSet;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.genStubThrow;
import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag;
import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
@@ -214,7 +216,7 @@ public class PropertyCodegen extends GenerationStateAware {
if (propertyDescriptor.getModality() != Modality.ABSTRACT) { if (propertyDescriptor.getModality() != Modality.ABSTRACT) {
mv.visitCode(); mv.visitCode();
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubThrow(mv); genStubThrow(mv);
} }
else { else {
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
@@ -316,7 +318,7 @@ public class PropertyCodegen extends GenerationStateAware {
if (propertyDescriptor.getModality() != Modality.ABSTRACT) { if (propertyDescriptor.getModality() != Modality.ABSTRACT) {
mv.visitCode(); mv.visitCode();
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
StubCodegen.generateStubThrow(mv); genStubThrow(mv);
} }
else { else {
InstructionAdapter iv = new InstructionAdapter(mv); InstructionAdapter iv = new InstructionAdapter(mv);
@@ -27,6 +27,8 @@ import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.isPrimitiveNumberClassDescriptor;
/** /**
* @author abreslav * @author abreslav
*/ */
@@ -91,7 +93,7 @@ public class RangeCodegenUtil {
public static boolean isOptimizableRangeTo(CallableDescriptor rangeTo) { public static boolean isOptimizableRangeTo(CallableDescriptor rangeTo) {
if ("rangeTo".equals(rangeTo.getName().getName())) { if ("rangeTo".equals(rangeTo.getName().getName())) {
if (CodegenUtil.isPrimitiveNumberClassDescriptor(rangeTo.getContainingDeclaration())) { if (isPrimitiveNumberClassDescriptor(rangeTo.getContainingDeclaration())) {
return true; return true;
} }
} }
@@ -202,7 +202,7 @@ public class ScriptCodegen extends GenerationStateAware {
private void genMembers(@NotNull JetScript scriptDeclaration, @NotNull CodegenContext context, @NotNull ClassBuilder classBuilder) { private void genMembers(@NotNull JetScript scriptDeclaration, @NotNull CodegenContext context, @NotNull ClassBuilder classBuilder) {
for (JetDeclaration decl : scriptDeclaration.getDeclarations()) { for (JetDeclaration decl : scriptDeclaration.getDeclarations()) {
CodegenUtil.generateFunctionOrProperty(state, (JetTypeParameterListOwner) decl, context, classBuilder); context.genFunctionOrProperty(state, (JetTypeParameterListOwner) decl, classBuilder);
} }
} }
@@ -39,6 +39,8 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.List; import java.util.List;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.boxType;
import static org.jetbrains.jet.codegen.AsmUtil.isIntPrimitive;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
/** /**
@@ -61,7 +63,7 @@ public abstract class StackValue {
instructionAdapter.aconst(null); instructionAdapter.aconst(null);
} }
else { else {
Type boxed = CodegenUtil.boxType(type); Type boxed = boxType(type);
instructionAdapter.invokestatic(boxed.getInternalName(), "valueOf", "(" + type.getDescriptor() + ")" + boxed.getDescriptor()); instructionAdapter.invokestatic(boxed.getInternalName(), "valueOf", "(" + type.getDescriptor() + ")" + boxed.getDescriptor());
} }
} }
@@ -76,7 +78,7 @@ public abstract class StackValue {
* JVM stack after this value was generated. * JVM stack after this value was generated.
* *
* @param type the type as which the value should be put * @param type the type as which the value should be put
* @param v the visitor used to generate the instructions * @param v the visitor used to genClassOrObject the instructions
* @param depth the number of new values put onto the stack * @param depth the number of new values put onto the stack
*/ */
protected void moveToTopOfStack(Type type, InstructionAdapter v, int depth) { protected void moveToTopOfStack(Type type, InstructionAdapter v, int depth) {
@@ -171,7 +173,7 @@ public abstract class StackValue {
private static void box(final Type type, final Type toType, InstructionAdapter v) { private static void box(final Type type, final Type toType, InstructionAdapter v) {
// TODO handle toType correctly // TODO handle toType correctly
if (type == Type.INT_TYPE || (CodegenUtil.isIntPrimitive(type) && toType.getInternalName().equals("java/lang/Integer"))) { if (type == Type.INT_TYPE || (isIntPrimitive(type) && toType.getInternalName().equals("java/lang/Integer"))) {
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
} }
else if (type == Type.BOOLEAN_TYPE) { else if (type == Type.BOOLEAN_TYPE) {
@@ -614,7 +616,7 @@ public abstract class StackValue {
public ArrayElement(Type type, boolean unbox) { public ArrayElement(Type type, boolean unbox) {
super(type); super(type);
this.boxed = unbox ? CodegenUtil.boxType(type) : type; this.boxed = unbox ? boxType(type) : type;
} }
@Override @Override
@@ -1,41 +0,0 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.codegen;
import org.jetbrains.asm4.MethodVisitor;
import static org.jetbrains.jet.codegen.CodegenUtil.generateMethodThrow;
import static org.jetbrains.jet.codegen.CodegenUtil.generateThrow;
/**
* @author Stepan Koltsov
*/
public class StubCodegen {
private static final String STUB_EXCEPTION = "java/lang/RuntimeException";
private static final String STUB_EXCEPTION_MESSAGE = "Stubs are for compiler only, do not add them to runtime classpath";
private StubCodegen() {
}
public static void generateStubThrow(MethodVisitor mv) {
generateThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
}
public static void generateStubCode(MethodVisitor mv) {
generateMethodThrow(mv, STUB_EXCEPTION, STUB_EXCEPTION_MESSAGE);
}
}
@@ -19,7 +19,6 @@ package org.jetbrains.jet.codegen.binding;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -39,6 +38,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import static org.jetbrains.jet.codegen.CodegenUtil.isInterface;
import static org.jetbrains.jet.lang.resolve.BindingContext.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
@@ -365,7 +365,7 @@ public class CodegenBinding {
assert superType != null; assert superType != null;
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
assert superClassDescriptor != null; assert superClassDescriptor != null;
if (!CodegenUtil.isInterface(superClassDescriptor)) { if (!isInterface(superClassDescriptor)) {
return (JetDelegatorToSuperCall) specifier; return (JetDelegatorToSuperCall) specifier;
} }
} }
@@ -26,13 +26,16 @@ import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.ErrorUtils;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.CLASS_FOR_FUNCTION; import static org.jetbrains.jet.codegen.AsmUtil.THIS$0;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.FQN; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
/* /*
@@ -261,7 +264,7 @@ public abstract class CodegenContext {
final ClassDescriptor enclosingClass = getEnclosingClass(); final ClassDescriptor enclosingClass = getEnclosingClass();
outerExpression = enclosingClass != null outerExpression = enclosingClass != null
? StackValue ? StackValue
.field(typeMapper.mapType(enclosingClass), CodegenBinding.getJvmInternalName(typeMapper.getBindingTrace(), classDescriptor), CodegenUtil.THIS$0, .field(typeMapper.mapType(enclosingClass), CodegenBinding.getJvmInternalName(typeMapper.getBindingTrace(), classDescriptor), THIS$0,
false) false)
: null; : null;
} }
@@ -298,4 +301,108 @@ public abstract class CodegenContext {
public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() { public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() {
return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors; return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors;
} }
public void genFunctionOrProperty(
GenerationState state,
@NotNull JetTypeParameterListOwner functionOrProperty,
@NotNull ClassBuilder classBuilder
) {
FunctionCodegen functionCodegen = new FunctionCodegen(this, classBuilder, state);
if (functionOrProperty instanceof JetNamedFunction) {
try {
functionCodegen.gen((JetNamedFunction) functionOrProperty);
}
catch (CompilationException e) {
throw e;
}
catch (Exception e) {
throw new CompilationException("Failed to generate function " + functionOrProperty.getName(), e, functionOrProperty);
}
}
else if (functionOrProperty instanceof JetProperty) {
try {
new PropertyCodegen(this, classBuilder, functionCodegen).gen((JetProperty) functionOrProperty);
}
catch (CompilationException e) {
throw e;
}
catch (Exception e) {
throw new CompilationException("Failed to generate property " + functionOrProperty.getName(), e, functionOrProperty);
}
}
else {
throw new IllegalArgumentException("Unknown parameter: " + functionOrProperty);
}
}
public void genImplementation(
GenerationState state,
JetClassOrObject aClass,
OwnerKind kind,
Map<DeclarationDescriptor, DeclarationDescriptor> accessors,
ClassBuilder classBuilder
) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
CodegenContext classContext = intoClass(descriptor, kind, state);
classContext.copyAccessors(accessors);
new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate();
if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
ClassBuilder traitBuilder = state.getFactory().forTraitImplementation(descriptor, state);
new TraitImplBodyCodegen(aClass, intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state)
.generate();
traitBuilder.done();
}
}
public void genInners(GenerationState state, JetClassOrObject aClass) {
for (JetDeclaration declaration : aClass.getDeclarations()) {
if (declaration instanceof JetClass) {
if (declaration instanceof JetEnumEntry && !enumEntryNeedSubclass(
state.getBindingContext(), (JetEnumEntry) declaration)) {
continue;
}
genClassOrObject(state, (JetClass) declaration);
}
else if (declaration instanceof JetClassObject) {
genClassOrObject(state, ((JetClassObject) declaration).getObjectDeclaration());
}
else if (declaration instanceof JetObjectDeclaration) {
genClassOrObject(state, (JetObjectDeclaration) declaration);
}
}
}
public void genClassOrObject(GenerationState state, JetClassOrObject aClass) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
if (descriptor == null || ErrorUtils.isError(descriptor) || descriptor.getName().equals(JetPsiUtil.NO_NAME_PROVIDED)) {
if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES) {
throw new IllegalStateException(
"Generating bad descriptor in ClassBuilderMode = " + state.getClassBuilderMode() + ": " + descriptor);
}
return;
}
ClassBuilder classBuilder = state.getFactory().forClassImplementation(descriptor);
final CodegenContext contextForInners = intoClass(descriptor, OwnerKind.IMPLEMENTATION, state);
if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) {
// Outer class implementation must happen prior inner classes so we get proper scoping tree in JetLightClass's delegate
// The same code is present below for the case when we genClassOrObject real bytecode. This is because the order should be
// different for the case when we compute closures
genImplementation(state, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder);
}
contextForInners.genInners(state, aClass);
if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES) {
genImplementation(state, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder);
}
classBuilder.done();
}
} }
@@ -17,7 +17,6 @@
package org.jetbrains.jet.codegen.context; package org.jetbrains.jet.codegen.context;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.binding.MutableClosure; import org.jetbrains.jet.codegen.binding.MutableClosure;
@@ -27,6 +26,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import static org.jetbrains.jet.codegen.AsmUtil.RECEIVER$0;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.classNameForAnonymousClass; import static org.jetbrains.jet.codegen.binding.CodegenBinding.classNameForAnonymousClass;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun; import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
@@ -122,7 +122,7 @@ public interface LocalLookup {
final JetType receiverType = ((CallableDescriptor) d).getReceiverParameter().getType(); final JetType receiverType = ((CallableDescriptor) d).getReceiverParameter().getType();
Type type = state.getTypeMapper().mapType(receiverType); Type type = state.getTypeMapper().mapType(receiverType);
StackValue innerValue = StackValue.field(type, className, CodegenUtil.RECEIVER$0, false); StackValue innerValue = StackValue.field(type, className, RECEIVER$0, false);
closure.setCaptureReceiver(); closure.setCaptureReceiver();
return innerValue; return innerValue;
@@ -20,15 +20,16 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.correctElementType;
/** /**
* @author alex.tkachman * @author alex.tkachman
*/ */
@@ -44,7 +45,7 @@ public class ArrayGet implements IntrinsicMethod {
@NotNull GenerationState state @NotNull GenerationState state
) { ) {
receiver.put(AsmTypeConstants.OBJECT_TYPE, v); receiver.put(AsmTypeConstants.OBJECT_TYPE, v);
Type type = CodegenUtil.correctElementType(receiver.type); Type type = correctElementType(receiver.type);
codegen.gen(arguments.get(0), Type.INT_TYPE); codegen.gen(arguments.get(0), Type.INT_TYPE);
@@ -20,15 +20,16 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.correctElementType;
/** /**
* @author alex.tkachman * @author alex.tkachman
*/ */
@@ -44,7 +45,7 @@ public class ArraySet implements IntrinsicMethod {
@NotNull GenerationState state @NotNull GenerationState state
) { ) {
receiver.put(AsmTypeConstants.OBJECT_TYPE, v); receiver.put(AsmTypeConstants.OBJECT_TYPE, v);
Type type = CodegenUtil.correctElementType(receiver.type); Type type = correctElementType(receiver.type);
codegen.gen(arguments.get(0), Type.INT_TYPE); codegen.gen(arguments.get(0), Type.INT_TYPE);
codegen.gen(arguments.get(1), type); codegen.gen(arguments.get(1), type);
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
@@ -29,6 +28,8 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.List; import java.util.List;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.boxType;
import static org.jetbrains.jet.codegen.AsmUtil.unboxType;
/** /**
* @author yole * @author yole
@@ -52,7 +53,7 @@ public class BinaryOp implements IntrinsicMethod {
) { ) {
boolean nullable = expectedType.getSort() == Type.OBJECT; boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) { if (nullable) {
expectedType = CodegenUtil.unboxType(expectedType); expectedType = unboxType(expectedType);
} }
if (arguments.size() == 1) { if (arguments.size() == 1) {
// Intrinsic is called as an ordinary function // Intrinsic is called as an ordinary function
@@ -68,7 +69,7 @@ public class BinaryOp implements IntrinsicMethod {
v.visitInsn(expectedType.getOpcode(opcode)); v.visitInsn(expectedType.getOpcode(opcode));
if (nullable) { if (nullable) {
StackValue.onStack(expectedType).put(expectedType = CodegenUtil.boxType(expectedType), v); StackValue.onStack(expectedType).put(expectedType = boxType(expectedType), v);
} }
return StackValue.onStack(expectedType); return StackValue.onStack(expectedType);
} }
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
@@ -29,6 +28,9 @@ import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.genInvokeAppendMethod;
import static org.jetbrains.jet.codegen.AsmUtil.genStringBuilderConstructor;
/** /**
* @author yole * @author yole
*/ */
@@ -44,15 +46,15 @@ public class Concat implements IntrinsicMethod {
@NotNull GenerationState state @NotNull GenerationState state
) { ) {
if (receiver == null || receiver == StackValue.none()) { // LHS + RHS if (receiver == null || receiver == StackValue.none()) { // LHS + RHS
CodegenUtil.generateStringBuilderConstructor(v); genStringBuilderConstructor(v);
codegen.invokeAppend(arguments.get(0)); // StringBuilder(LHS) codegen.invokeAppend(arguments.get(0)); // StringBuilder(LHS)
codegen.invokeAppend(arguments.get(1)); codegen.invokeAppend(arguments.get(1));
} }
else { // LHS.plus(RHS) else { // LHS.plus(RHS)
receiver.put(AsmTypeConstants.OBJECT_TYPE, v); receiver.put(AsmTypeConstants.OBJECT_TYPE, v);
CodegenUtil.generateStringBuilderConstructor(v); genStringBuilderConstructor(v);
v.swap(); // StringBuilder LHS v.swap(); // StringBuilder LHS
CodegenUtil.invokeAppendMethod(v, expectedType); // StringBuilder(LHS) genInvokeAppendMethod(v, expectedType); // StringBuilder(LHS)
codegen.invokeAppend(arguments.get(0)); codegen.invokeAppend(arguments.get(0));
} }
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
@@ -33,6 +32,8 @@ import org.jetbrains.jet.lexer.JetTokens;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.genEqualsForExpressionsOnStack;
/** /**
* @author alex.tkachman * @author alex.tkachman
*/ */
@@ -75,9 +76,8 @@ public class Equals implements IntrinsicMethod {
codegen.gen(rightExpr).put(AsmTypeConstants.OBJECT_TYPE, v); codegen.gen(rightExpr).put(AsmTypeConstants.OBJECT_TYPE, v);
assert rightType != null; assert rightType != null;
return CodegenUtil return genEqualsForExpressionsOnStack(v, JetTokens.EQEQ, AsmTypeConstants.OBJECT_TYPE, AsmTypeConstants.OBJECT_TYPE,
.generateEqualsForExpressionsOnStack(v, JetTokens.EQEQ, AsmTypeConstants.OBJECT_TYPE, AsmTypeConstants.OBJECT_TYPE, leftNullable,
leftNullable, rightType.isNullable());
rightType.isNullable());
} }
} }
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
@@ -30,6 +29,8 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.*;
/** /**
* @author yole * @author yole
*/ */
@@ -52,7 +53,7 @@ public class Increment implements IntrinsicMethod {
) { ) {
boolean nullable = expectedType.getSort() == Type.OBJECT; boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) { if (nullable) {
expectedType = CodegenUtil.unboxType(expectedType); expectedType = unboxType(expectedType);
} }
if (arguments.size() > 0) { if (arguments.size() > 0) {
JetExpression operand = arguments.get(0); JetExpression operand = arguments.get(0);
@@ -61,7 +62,7 @@ public class Increment implements IntrinsicMethod {
} }
if (operand instanceof JetReferenceExpression) { if (operand instanceof JetReferenceExpression) {
final int index = codegen.indexOfLocal((JetReferenceExpression) operand); final int index = codegen.indexOfLocal((JetReferenceExpression) operand);
if (index >= 0 && CodegenUtil.isIntPrimitive(expectedType)) { if (index >= 0 && isIntPrimitive(expectedType)) {
return StackValue.preIncrement(index, myDelta); return StackValue.preIncrement(index, myDelta);
} }
} }
@@ -70,12 +71,12 @@ public class Increment implements IntrinsicMethod {
value.dupReceiver(v); value.dupReceiver(v);
value.put(expectedType, v); value.put(expectedType, v);
value.store(CodegenUtil.genIncrement(expectedType, myDelta, v), v); value.store(genIncrement(expectedType, myDelta, v), v);
value.put(expectedType, v); value.put(expectedType, v);
} }
else { else {
receiver.put(expectedType, v); receiver.put(expectedType, v);
StackValue.coerce(CodegenUtil.genIncrement(expectedType, myDelta, v), expectedType, v); StackValue.coerce(genIncrement(expectedType, myDelta, v), expectedType, v);
} }
return StackValue.onStack(expectedType); return StackValue.onStack(expectedType);
} }
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
@@ -28,6 +27,8 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.unboxType;
/** /**
* @author yole * @author yole
* @author alex.tkachman * @author alex.tkachman
@@ -45,7 +46,7 @@ public class Inv implements IntrinsicMethod {
) { ) {
boolean nullable = expectedType.getSort() == Type.OBJECT; boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) { if (nullable) {
expectedType = CodegenUtil.unboxType(expectedType); expectedType = unboxType(expectedType);
} }
receiver.put(expectedType, v); receiver.put(expectedType, v);
if (expectedType == Type.LONG_TYPE) { if (expectedType == Type.LONG_TYPE) {
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
@@ -28,6 +27,8 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.genToString;
/** /**
* @author alex.tkachman * @author alex.tkachman
*/ */
@@ -42,6 +43,6 @@ public class ToString implements IntrinsicMethod {
StackValue receiver, StackValue receiver,
@NotNull GenerationState state @NotNull GenerationState state
) { ) {
return CodegenUtil.genToString(v, receiver); return genToString(v, receiver);
} }
} }
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
@@ -28,6 +27,9 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.genNegate;
import static org.jetbrains.jet.codegen.AsmUtil.unboxType;
/** /**
* @author yole * @author yole
*/ */
@@ -44,7 +46,7 @@ public class UnaryMinus implements IntrinsicMethod {
) { ) {
boolean nullable = expectedType.getSort() == Type.OBJECT; boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) { if (nullable) {
expectedType = CodegenUtil.unboxType(expectedType); expectedType = unboxType(expectedType);
} }
if (arguments.size() == 1) { if (arguments.size() == 1) {
codegen.gen(arguments.get(0), expectedType); codegen.gen(arguments.get(0), expectedType);
@@ -52,7 +54,7 @@ public class UnaryMinus implements IntrinsicMethod {
else { else {
receiver.put(expectedType, v); receiver.put(expectedType, v);
} }
StackValue.coerce(CodegenUtil.genNegate(expectedType, v), expectedType, v); StackValue.coerce(genNegate(expectedType, v), expectedType, v);
return StackValue.onStack(expectedType); return StackValue.onStack(expectedType);
} }
} }
@@ -21,7 +21,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
@@ -29,6 +28,8 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.List; import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.unboxType;
/** /**
* @author alex.tkachman * @author alex.tkachman
*/ */
@@ -45,7 +46,7 @@ public class UnaryPlus implements IntrinsicMethod {
) { ) {
boolean nullable = expectedType.getSort() == Type.OBJECT; boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) { if (nullable) {
expectedType = CodegenUtil.unboxType(expectedType); expectedType = unboxType(expectedType);
} }
if (receiver != null && receiver != StackValue.none()) { if (receiver != null && receiver != StackValue.none()) {
receiver.put(expectedType, v); receiver.put(expectedType, v);
@@ -46,6 +46,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.boxType;
import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
@@ -658,7 +659,7 @@ public class JetTypeMapper extends BindingTraceAware {
((ClassDescriptor) parentDescriptor).getKind() == ClassKind.ANNOTATION_CLASS; ((ClassDescriptor) parentDescriptor).getKind() == ClassKind.ANNOTATION_CLASS;
String name = isAnnotation ? descriptor.getName().getName() : PropertyCodegen.getterName(descriptor.getName()); String name = isAnnotation ? descriptor.getName().getName() : PropertyCodegen.getterName(descriptor.getName());
// TODO: do not generate generics if not needed // TODO: do not genClassOrObject generics if not needed
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true); BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
writeFormalTypeParameters(descriptor.getTypeParameters(), signatureWriter); writeFormalTypeParameters(descriptor.getTypeParameters(), signatureWriter);
@@ -29,7 +29,6 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.SmartList; import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.CodegenUtil;
import org.jetbrains.jet.codegen.NamespaceCodegen; import org.jetbrains.jet.codegen.NamespaceCodegen;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.java.JavaPsiFacadeKotlinHacks; import org.jetbrains.jet.lang.resolve.java.JavaPsiFacadeKotlinHacks;
@@ -41,6 +40,8 @@ import org.jetbrains.jet.util.QualifiedNamesUtil;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.codegen.CodegenUtil.getLocalNameForObject;
public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacadeKotlinHacks.KotlinFinderMarker { public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacadeKotlinHacks.KotlinFinderMarker {
private final Project project; private final Project project;
private final PsiManager psiManager; private final PsiManager psiManager;
@@ -166,7 +167,7 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
if (given != null) return given; if (given != null) return given;
if (declaration instanceof JetObjectDeclaration) { if (declaration instanceof JetObjectDeclaration) {
return CodegenUtil.getLocalNameForObject((JetObjectDeclaration) declaration); return getLocalNameForObject((JetObjectDeclaration) declaration);
} }
return null; return null;
@@ -266,7 +266,7 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa
public static PsiMethod wrapMethod(@NotNull JetNamedFunction function) { public static PsiMethod wrapMethod(@NotNull JetNamedFunction function) {
//noinspection unchecked //noinspection unchecked
if (PsiTreeUtil.getParentOfType(function, JetFunction.class, JetProperty.class) != null) { if (PsiTreeUtil.getParentOfType(function, JetFunction.class, JetProperty.class) != null) {
// Don't generate method wrappers for internal declarations. Their classes are not generated during calcStub // Don't genClassOrObject method wrappers for internal declarations. Their classes are not generated during calcStub
// with ClassBuilderMode.SIGNATURES mode, and this produces "Class not found exception" in getDelegate() // with ClassBuilderMode.SIGNATURES mode, and this produces "Class not found exception" in getDelegate()
return null; return null;
} }