diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 8f0cd40595f..c1a60ec6101 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -11,6 +11,8 @@ import jet.IntRange; import jet.JetObject; import jet.Range; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod; +import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -83,6 +85,7 @@ public class ExpressionCodegen extends JetVisitor { private final BindingContext bindingContext; private final Map typeParameterExpressions = new HashMap(); private final ClassContext context; + private final IntrinsicMethods intrinsics; public ExpressionCodegen(MethodVisitor v, FrameMap myMap, @@ -96,6 +99,7 @@ public class ExpressionCodegen extends JetVisitor { this.v = new InstructionAdapter(v); this.bindingContext = state.getBindingContext(); this.context = context; + this.intrinsics = state.getIntrinsics(); } public void addTypeParameter(TypeParameterDescriptor typeParameter, StackValue expression) { @@ -126,7 +130,7 @@ public class ExpressionCodegen extends JetVisitor { } } - private void putTopOfStack(Type type) { + public void putTopOfStack(Type type) { StackValue value = myStack.pop(); value.put(type, v); } @@ -642,18 +646,15 @@ public class ExpressionCodegen extends JetVisitor { descriptor = ((VariableAsFunctionDescriptor) descriptor).getVariableDescriptor(); } - final DeclarationDescriptor container = descriptor.getContainingDeclaration(); - if (descriptor instanceof VariableDescriptor) { - if (isClass(container, "Number")) { - Type castType = getCastType(expression.getReferencedName()); - if (castType != null) { - final StackValue value = myStack.pop(); - value.put(castType, v); - myStack.push(StackValue.onStack(castType)); - return; - } - } + final IntrinsicMethod intrinsic = intrinsics.getIntrinsic(descriptor); + if (intrinsic != null) { + final Type expectedType = expressionType(expression); + myStack.push(intrinsic.generate(this, v, expectedType, expression, Collections.emptyList())); + return; } + + final DeclarationDescriptor container = descriptor.getContainingDeclaration(); + PsiElement declaration = bindingContext.getDeclarationPsiElement(descriptor); if (declaration instanceof PsiField) { PsiField psiField = (PsiField) declaration; @@ -690,12 +691,7 @@ public class ExpressionCodegen extends JetVisitor { } } - if (isClass(container, "Array") && propertyDescriptor.getName().equals("size")) { - ensureReceiverOnStack(expression, null); - v.arraylength(); - myStack.push(StackValue.onStack(Type.INT_TYPE)); - } - else if (declaration instanceof JetObjectDeclarationName) { + if (declaration instanceof JetObjectDeclarationName) { JetObjectDeclaration objectDeclaration = PsiTreeUtil.getParentOfType(declaration, JetObjectDeclaration.class); ClassDescriptor classDescriptor = bindingContext.getClassDescriptor(objectDeclaration); myStack.push(StackValue.field(typeMapper.jvmType(classDescriptor, OwnerKind.IMPLEMENTATION), @@ -779,32 +775,6 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.property(propertyDescriptor.getName(), owner, typeMapper.mapType(outType), isStatic, isInterface, getter, setter); } - @Nullable - private static Type getCastType(String castMethodName) { - if ("dbl".equals(castMethodName)) { - return Type.DOUBLE_TYPE; - } - if ("flt".equals(castMethodName)) { - return Type.FLOAT_TYPE; - } - if ("lng".equals(castMethodName)) { - return Type.LONG_TYPE; - } - if ("int".equals(castMethodName)) { - return Type.INT_TYPE; - } - if ("chr".equals(castMethodName)) { - return Type.CHAR_TYPE; - } - if ("sht".equals(castMethodName)) { - return Type.SHORT_TYPE; - } - if ("byt".equals(castMethodName)) { - return Type.BYTE_TYPE; - } - return null; - } - @Override public void visitCallExpression(JetCallExpression expression) { final JetExpression callee = expression.getCalleeExpression(); @@ -944,7 +914,7 @@ public class ExpressionCodegen extends JetVisitor { return null; } - private void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass) { + public void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass) { JetExpression receiver = getReceiverForSelector(expression); if (receiver != null) { if (!resolvesToClassOrPackage(receiver)) { @@ -1402,7 +1372,7 @@ public class ExpressionCodegen extends JetVisitor { final Type asmType = expressionType(expression); DeclarationDescriptor cls = op.getContainingDeclaration(); if (isNumberPrimitive(cls)) { - if (generateUnaryOp(op, asmType, expression.getBaseExpression())) return; + if (generateUnaryOp(op, asmType, expression)) return; } else if (isClass(cls, "Boolean") && op.getName().equals("not")) { generateNot(expression); @@ -1435,11 +1405,11 @@ public class ExpressionCodegen extends JetVisitor { throw new UnsupportedOperationException("Don't know how to generate this prefix expression"); } - private boolean generateUnaryOp(DeclarationDescriptor op, Type asmType, final JetExpression operand) { - if (op.getName().equals("minus")) { - gen(operand, asmType); - v.neg(asmType); - myStack.push(StackValue.onStack(asmType)); + private boolean generateUnaryOp(DeclarationDescriptor op, Type asmType, final JetUnaryExpression unaryExpression) { + final IntrinsicMethod intrinsic = intrinsics.getIntrinsic(op); + final JetExpression operand = unaryExpression.getBaseExpression(); + if (intrinsic != null) { + myStack.push(intrinsic.generate(this, v, asmType, unaryExpression, Collections.singletonList(operand))); return true; } else if (op.getName().equals("inc") || op.getName().equals("dec")) { diff --git a/idea/src/org/jetbrains/jet/codegen/GenerationState.java b/idea/src/org/jetbrains/jet/codegen/GenerationState.java index 631776165d0..53a24e7713a 100644 --- a/idea/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/idea/src/org/jetbrains/jet/codegen/GenerationState.java @@ -6,6 +6,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.util.containers.Stack; +import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -23,11 +24,13 @@ public class GenerationState { private JetTypeMapper typeMapper; private final Stack bindingContexts = new Stack(); private final JetStandardLibrary standardLibrary; + private final IntrinsicMethods intrinsics; public GenerationState(Project project, boolean text) { this.project = project; this.standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); this.factory = new ClassFileFactory(project, text, this); + this.intrinsics = new IntrinsicMethods(standardLibrary); } public ClassFileFactory getFactory() { @@ -50,6 +53,10 @@ public class GenerationState { return standardLibrary; } + public IntrinsicMethods getIntrinsics() { + return intrinsics; + } + public ClassVisitor forClassInterface(ClassDescriptor aClass) { return factory.newVisitor(JetTypeMapper.jvmNameForInterface(aClass) + ".class"); } diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java new file mode 100644 index 00000000000..7a838e35d49 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java @@ -0,0 +1,22 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author yole + */ +public class ArraySize implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments) { + codegen.ensureReceiverOnStack(element, null); + v.arraylength(); + return StackValue.onStack(Type.INT_TYPE); + } +} diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethod.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethod.java new file mode 100644 index 00000000000..e4ef016a2a2 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethod.java @@ -0,0 +1,17 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author yole + */ +public interface IntrinsicMethod { + StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments); +} diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java new file mode 100644 index 00000000000..67ff080c9bf --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -0,0 +1,70 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.google.common.collect.ImmutableList; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.JetScope; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.TypeProjection; + +import java.util.*; + +/** + * @author yole + */ +public class IntrinsicMethods { + private static final IntrinsicMethod UNARY_MINUS = new UnaryMinus(); + private static final IntrinsicMethod NUMBER_CAST = new NumberCast(); + private static final IntrinsicMethod ARRAY_SIZE = new ArraySize(); + + private final Map myMethods = new HashMap(); + + public IntrinsicMethods(JetStandardLibrary stdlib) { + List primitiveCastMethods = ImmutableList.of("dbl", "flt", "lng", "int", "chr", "sht", "byt"); + for (String method : primitiveCastMethods) { + declareIntrinsicProperty(stdlib, "Number", method, NUMBER_CAST); + } + declareIntrinsicProperty(stdlib, "Array", "size", ARRAY_SIZE); + + List primitiveNumberTypes = ImmutableList.of( + stdlib.getBoolean(), + stdlib.getByte(), + stdlib.getChar(), + stdlib.getShort(), + stdlib.getInt(), + stdlib.getFloat(), + stdlib.getLong(), + stdlib.getDouble() + ); + + for (ClassDescriptor primitiveNumberType : primitiveNumberTypes) { + final JetScope memberScope = primitiveNumberType.getMemberScope(Collections.emptyList()); + + final FunctionGroup minus = memberScope.getFunctionGroup("minus"); + for (FunctionDescriptor descriptor : minus.getFunctionDescriptors()) { + if (descriptor.getValueParameters().isEmpty()) { + myMethods.put(descriptor, UNARY_MINUS); + } + } + + + } + } + + private void declareIntrinsicProperty(JetStandardLibrary stdlib, String className, String methodName, IntrinsicMethod implementation) { + final ClassDescriptor descriptor = (ClassDescriptor) stdlib.getLibraryScope().getClassifier(className); + final List typeParameterDescriptors = descriptor.getTypeConstructor().getParameters(); + List typeParameters = new ArrayList(); + for (TypeParameterDescriptor typeParameterDescriptor : typeParameterDescriptors) { + typeParameters.add(new TypeProjection(JetStandardClasses.getAnyType())); + } + final JetScope numberScope = descriptor.getMemberScope(typeParameters); + final VariableDescriptor variable = numberScope.getVariable(methodName); + myMethods.put(variable.getOriginal(), implementation); + } + + public IntrinsicMethod getIntrinsic(DeclarationDescriptor descriptor) { + return myMethods.get(descriptor.getOriginal()); + } + +} diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/NumberCast.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/NumberCast.java new file mode 100644 index 00000000000..1709921c825 --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/NumberCast.java @@ -0,0 +1,21 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author yole + */ +public class NumberCast implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments) { + codegen.putTopOfStack(expectedType); + return StackValue.onStack(expectedType); + } +} diff --git a/idea/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java b/idea/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java new file mode 100644 index 00000000000..38eb3d6449f --- /dev/null +++ b/idea/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java @@ -0,0 +1,22 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author yole + */ +public class UnaryMinus implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments) { + codegen.gen(arguments.get(0), expectedType); + v.neg(expectedType); + return StackValue.onStack(expectedType); + } +}