+= for strings is intrinsic

This commit is contained in:
Dmitry Jemerov
2011-07-14 20:05:56 +02:00
parent 8a6ccdfbf4
commit 0e75b3363a
4 changed files with 78 additions and 41 deletions
+2
View File
@@ -78,6 +78,8 @@ class String() : Comparable<String> {
val length : Int val length : Int
fun plus(other : Any?) : String fun plus(other : Any?) : String
fun plusAssign(other: Any?): String
fun equals(other : Any?) : Boolean fun equals(other : Any?) : Boolean
fun equalsIgnoreCase(other: String?) : Boolean fun equalsIgnoreCase(other: String?) : Boolean
@@ -799,19 +799,19 @@ public class ExpressionCodegen extends JetVisitor {
} }
} }
private StackValue invokeFunction(JetCallExpression expression, FunctionDescriptor fd, boolean haveReceiver) { private StackValue invokeFunction(JetCallExpression expression, DeclarationDescriptor fd, boolean haveReceiver) {
Callable callableMethod = resolveToCallable(fd); Callable callableMethod = resolveToCallable(fd);
return invokeCallable(fd, callableMethod, expression, haveReceiver); return invokeCallable(fd, callableMethod, expression, haveReceiver);
} }
@Nullable @Nullable
private StackValue invokeCallable(FunctionDescriptor fd, Callable callable, JetCallExpression expression, boolean haveReceiver) { private StackValue invokeCallable(DeclarationDescriptor fd, Callable callable, JetCallExpression expression, boolean haveReceiver) {
if (callable instanceof CallableMethod) { if (callable instanceof CallableMethod) {
final CallableMethod callableMethod = (CallableMethod) callable; final CallableMethod callableMethod = (CallableMethod) callable;
invokeMethodWithArguments(callableMethod, expression, haveReceiver); invokeMethodWithArguments(callableMethod, expression, haveReceiver);
final Type callReturnType = callableMethod.getSignature().getReturnType(); final Type callReturnType = callableMethod.getSignature().getReturnType();
return returnValueAsStackValue(fd, callReturnType); return returnValueAsStackValue((FunctionDescriptor) fd, callReturnType);
} }
else { else {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable; IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
@@ -832,7 +832,7 @@ public class ExpressionCodegen extends JetVisitor {
return null; return null;
} }
private Callable resolveToCallable(FunctionDescriptor fd) { private Callable resolveToCallable(DeclarationDescriptor fd) {
final IntrinsicMethod intrinsic = intrinsics.getIntrinsic(fd); final IntrinsicMethod intrinsic = intrinsics.getIntrinsic(fd);
if (intrinsic != null) { if (intrinsic != null) {
return intrinsic; return intrinsic;
@@ -843,8 +843,11 @@ public class ExpressionCodegen extends JetVisitor {
if (declarationPsiElement instanceof PsiMethod || declarationPsiElement instanceof JetNamedFunction) { if (declarationPsiElement instanceof PsiMethod || declarationPsiElement instanceof JetNamedFunction) {
callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement); callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement);
} }
else if (fd instanceof FunctionDescriptor) {
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
}
else { else {
callableMethod = ClosureCodegen.asCallableMethod(fd); throw new UnsupportedOperationException("can't resolve declaration to callable: " + fd);
} }
return callableMethod; return callableMethod;
} }
@@ -1090,22 +1093,20 @@ public class ExpressionCodegen extends JetVisitor {
} }
else { else {
DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference()); DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
if (op instanceof FunctionDescriptor) { final Callable callable = resolveToCallable(op);
final Callable callable = resolveToCallable((FunctionDescriptor) op); if (callable instanceof IntrinsicMethod) {
if (callable instanceof IntrinsicMethod) { IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
IntrinsicMethod intrinsic = (IntrinsicMethod) callable; myStack.push(intrinsic.generate(this, v, expressionType(expression), expression,
myStack.push(intrinsic.generate(this, v, expressionType(expression), expression, Arrays.asList(expression.getLeft(), expression.getRight()), false));
Arrays.asList(expression.getLeft(), expression.getRight()), false)); }
} else {
else { CallableMethod callableMethod = (CallableMethod) callable;
CallableMethod callableMethod = (CallableMethod) callable; genToJVMStack(expression.getLeft());
genToJVMStack(expression.getLeft()); genToJVMStack(expression.getRight());
genToJVMStack(expression.getRight()); callableMethod.invoke(v);
callableMethod.invoke(v); final StackValue value = returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getReturnType());
final StackValue value = returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getReturnType()); if (value != null) {
if (value != null) { myStack.push(value);
myStack.push(value);
}
} }
} }
} }
@@ -1265,28 +1266,31 @@ public class ExpressionCodegen extends JetVisitor {
private void generateAugmentedAssignment(JetBinaryExpression expression) { private void generateAugmentedAssignment(JetBinaryExpression expression) {
DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference()); DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
final Callable callable = resolveToCallable(op);
final JetExpression lhs = expression.getLeft(); final JetExpression lhs = expression.getLeft();
Type lhsType = expressionType(lhs); Type lhsType = expressionType(lhs);
if (isNumberPrimitive(lhsType)) { if (bindingContext.isVariableReassignment(expression)) {
StackValue value = generateIntermediateValue(lhs); // receiver if (isNumberPrimitive(lhsType)) {
value.dupReceiver(v, 0); // receiver receiver StackValue value = generateIntermediateValue(lhs); // receiver
value.put(lhsType, v); // receiver lhs value.dupReceiver(v, 0); // receiver receiver
genToJVMStack(expression.getRight()); // receiver lhs rhs value.put(lhsType, v); // receiver lhs
v.visitInsn(lhsType.getOpcode(opcodeForMethod(op.getName()))); // receiver result genToJVMStack(expression.getRight()); // receiver lhs rhs
value.store(v); v.visitInsn(lhsType.getOpcode(opcodeForMethod(op.getName()))); // receiver result
} value.store(v);
else if ("java.lang.String".equals(lhsType.getClassName()) && op.getName().equals("plus")) { }
generateStringBuilderConstructor(); // StringBuilder else {
StackValue value = generateIntermediateValue(lhs); // StringBuilder receiver throw new UnsupportedOperationException("Augmented assignment for non-primitive types not yet implemented");
value.dupReceiver(v, 1); // receiver StringBuilder receiver }
value.put(lhsType, v); // receiver StringBuilder value
invokeAppendMethod(lhsType); // receiver StringBuilder
invokeAppend(expression.getRight()); // receiver StringBuilder
v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;");
value.store(v);
} }
else { else {
throw new UnsupportedOperationException("Augmented assignment for non-primitive types not yet implemented"); if (callable instanceof IntrinsicMethod) {
final IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
intrinsic.generate(this, v, Type.VOID_TYPE, expression, Arrays.asList(lhs, expression.getRight()), false);
}
else {
throw new UnsupportedOperationException("TODO");
}
} }
} }
@@ -1312,7 +1316,7 @@ public class ExpressionCodegen extends JetVisitor {
invokeAppendMethod(exprType); invokeAppendMethod(exprType);
} }
private void invokeAppendMethod(Type exprType) { public void invokeAppendMethod(Type exprType) {
Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER), Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER),
new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType}); new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType});
v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor()); v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor());
@@ -1359,7 +1363,7 @@ public class ExpressionCodegen extends JetVisitor {
return; return;
} }
final Callable callable = resolveToCallable((FunctionDescriptor) op); final Callable callable = resolveToCallable(op);
if (callable instanceof IntrinsicMethod) { if (callable instanceof IntrinsicMethod) {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable; IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
myStack.push(intrinsic.generate(this, v, expressionType(unaryExpression), unaryExpression, myStack.push(intrinsic.generate(this, v, expressionType(unaryExpression), unaryExpression,
@@ -66,6 +66,7 @@ public class IntrinsicMethods {
declareIntrinsicFunction("Boolean", "not", 0, new Not()); declareIntrinsicFunction("Boolean", "not", 0, new Not());
declareIntrinsicFunction("String", "plus", 1, new Concat()); declareIntrinsicFunction("String", "plus", 1, new Concat());
declareIntrinsicFunction("String", "plusAssign", 1, new PlusConcat());
declareIntrinsicStringMethods(); declareIntrinsicStringMethods();
} }
@@ -0,0 +1,30 @@
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 PlusConcat implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
final JetExpression lhs = arguments.get(0);
final Type lhsType = codegen.expressionType(lhs);
codegen.generateStringBuilderConstructor(); // StringBuilder
StackValue value = codegen.generateIntermediateValue(lhs); // StringBuilder receiver
value.dupReceiver(v, 1); // receiver StringBuilder receiver
value.put(lhsType, v); // receiver StringBuilder value
codegen.invokeAppendMethod(lhsType); // receiver StringBuilder
codegen.invokeAppend(arguments.get(1)); // receiver StringBuilder
v.invokevirtual(ExpressionCodegen.CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;");
value.store(v);
return null;
}
}