+= 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
fun plus(other : Any?) : String
fun plusAssign(other: Any?): String
fun equals(other : Any?) : 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);
return invokeCallable(fd, callableMethod, expression, haveReceiver);
}
@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) {
final CallableMethod callableMethod = (CallableMethod) callable;
invokeMethodWithArguments(callableMethod, expression, haveReceiver);
final Type callReturnType = callableMethod.getSignature().getReturnType();
return returnValueAsStackValue(fd, callReturnType);
return returnValueAsStackValue((FunctionDescriptor) fd, callReturnType);
}
else {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
@@ -832,7 +832,7 @@ public class ExpressionCodegen extends JetVisitor {
return null;
}
private Callable resolveToCallable(FunctionDescriptor fd) {
private Callable resolveToCallable(DeclarationDescriptor fd) {
final IntrinsicMethod intrinsic = intrinsics.getIntrinsic(fd);
if (intrinsic != null) {
return intrinsic;
@@ -843,8 +843,11 @@ public class ExpressionCodegen extends JetVisitor {
if (declarationPsiElement instanceof PsiMethod || declarationPsiElement instanceof JetNamedFunction) {
callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement);
}
else if (fd instanceof FunctionDescriptor) {
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
}
else {
callableMethod = ClosureCodegen.asCallableMethod(fd);
throw new UnsupportedOperationException("can't resolve declaration to callable: " + fd);
}
return callableMethod;
}
@@ -1090,22 +1093,20 @@ public class ExpressionCodegen extends JetVisitor {
}
else {
DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
if (op instanceof FunctionDescriptor) {
final Callable callable = resolveToCallable((FunctionDescriptor) op);
if (callable instanceof IntrinsicMethod) {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
myStack.push(intrinsic.generate(this, v, expressionType(expression), expression,
Arrays.asList(expression.getLeft(), expression.getRight()), false));
}
else {
CallableMethod callableMethod = (CallableMethod) callable;
genToJVMStack(expression.getLeft());
genToJVMStack(expression.getRight());
callableMethod.invoke(v);
final StackValue value = returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getReturnType());
if (value != null) {
myStack.push(value);
}
final Callable callable = resolveToCallable(op);
if (callable instanceof IntrinsicMethod) {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
myStack.push(intrinsic.generate(this, v, expressionType(expression), expression,
Arrays.asList(expression.getLeft(), expression.getRight()), false));
}
else {
CallableMethod callableMethod = (CallableMethod) callable;
genToJVMStack(expression.getLeft());
genToJVMStack(expression.getRight());
callableMethod.invoke(v);
final StackValue value = returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getReturnType());
if (value != null) {
myStack.push(value);
}
}
}
@@ -1265,28 +1266,31 @@ public class ExpressionCodegen extends JetVisitor {
private void generateAugmentedAssignment(JetBinaryExpression expression) {
DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
final Callable callable = resolveToCallable(op);
final JetExpression lhs = expression.getLeft();
Type lhsType = expressionType(lhs);
if (isNumberPrimitive(lhsType)) {
StackValue value = generateIntermediateValue(lhs); // receiver
value.dupReceiver(v, 0); // receiver receiver
value.put(lhsType, v); // receiver lhs
genToJVMStack(expression.getRight()); // receiver lhs rhs
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
StackValue value = generateIntermediateValue(lhs); // StringBuilder receiver
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);
if (bindingContext.isVariableReassignment(expression)) {
if (isNumberPrimitive(lhsType)) {
StackValue value = generateIntermediateValue(lhs); // receiver
value.dupReceiver(v, 0); // receiver receiver
value.put(lhsType, v); // receiver lhs
genToJVMStack(expression.getRight()); // receiver lhs rhs
v.visitInsn(lhsType.getOpcode(opcodeForMethod(op.getName()))); // receiver result
value.store(v);
}
else {
throw new UnsupportedOperationException("Augmented assignment for non-primitive types not yet implemented");
}
}
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);
}
private void invokeAppendMethod(Type exprType) {
public void invokeAppendMethod(Type exprType) {
Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER),
new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType});
v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor());
@@ -1359,7 +1363,7 @@ public class ExpressionCodegen extends JetVisitor {
return;
}
final Callable callable = resolveToCallable((FunctionDescriptor) op);
final Callable callable = resolveToCallable(op);
if (callable instanceof IntrinsicMethod) {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
myStack.push(intrinsic.generate(this, v, expressionType(unaryExpression), unaryExpression,
@@ -66,6 +66,7 @@ public class IntrinsicMethods {
declareIntrinsicFunction("Boolean", "not", 0, new Not());
declareIntrinsicFunction("String", "plus", 1, new Concat());
declareIntrinsicFunction("String", "plusAssign", 1, new PlusConcat());
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;
}
}