intrinsics - initial

This commit is contained in:
Dmitry Jemerov
2011-07-13 19:31:30 +02:00
parent cf5763739f
commit 324106904c
7 changed files with 180 additions and 51 deletions
@@ -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<TypeParameterDescriptor, StackValue> typeParameterExpressions = new HashMap<TypeParameterDescriptor, StackValue>();
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.<JetExpression>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")) {
@@ -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<BindingContext> bindingContexts = new Stack<BindingContext>();
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");
}
@@ -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<JetExpression> arguments) {
codegen.ensureReceiverOnStack(element, null);
v.arraylength();
return StackValue.onStack(Type.INT_TYPE);
}
}
@@ -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<JetExpression> arguments);
}
@@ -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<DeclarationDescriptor, IntrinsicMethod> myMethods = new HashMap<DeclarationDescriptor, IntrinsicMethod>();
public IntrinsicMethods(JetStandardLibrary stdlib) {
List<String> 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<ClassDescriptor> 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.<TypeProjection>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<TypeParameterDescriptor> typeParameterDescriptors = descriptor.getTypeConstructor().getParameters();
List<TypeProjection> typeParameters = new ArrayList<TypeProjection>();
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());
}
}
@@ -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<JetExpression> arguments) {
codegen.putTopOfStack(expectedType);
return StackValue.onStack(expectedType);
}
}
@@ -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<JetExpression> arguments) {
codegen.gen(arguments.get(0), expectedType);
v.neg(expectedType);
return StackValue.onStack(expectedType);
}
}