RenageTo convertion & before call

This commit is contained in:
Michael Bogdanov
2015-04-04 10:45:31 +03:00
parent 83f8dae9ac
commit 6e9d5ebe78
6 changed files with 102 additions and 52 deletions
@@ -181,4 +181,9 @@ public class CallableMethod implements ExtendedCallable {
public boolean isStaticCall() { public boolean isStaticCall() {
return invokeOpcode == Opcodes.INVOKESTATIC; return invokeOpcode == Opcodes.INVOKESTATIC;
} }
@Override
public void beforeParameterGeneration(@NotNull InstructionAdapter v, @Nullable StackValue value) {
}
} }
@@ -2347,6 +2347,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@NotNull CallGenerator callGenerator, @NotNull CallGenerator callGenerator,
@NotNull ArgumentGenerator argumentGenerator @NotNull ArgumentGenerator argumentGenerator
) { ) {
StackValue.SafeCall safeCallReceiver = receiver instanceof StackValue.SafeCall ? (StackValue.SafeCall) receiver : null;
if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already
receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod); receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
@@ -2358,7 +2359,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
} }
} }
receiver.put(receiver.type, v); if (safeCallReceiver != null) {
//justCoerce
receiver.put(receiver.type, v);
callableMethod.beforeParameterGeneration(v, StackValue.onStack(receiver.type));
} else {
callableMethod.beforeParameterGeneration(v, null);
receiver.put(receiver.type, v);
}
} }
callGenerator.putHiddenParams(); callGenerator.putHiddenParams();
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
@@ -55,4 +56,7 @@ public interface ExtendedCallable extends Callable {
@Nullable @Nullable
Type getReceiverClass(); Type getReceiverClass();
void beforeParameterGeneration(@NotNull InstructionAdapter v, @Nullable StackValue value);
} }
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.intrinsics
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.CallableMethod import org.jetbrains.kotlin.codegen.CallableMethod
import org.jetbrains.kotlin.codegen.ExtendedCallable import org.jetbrains.kotlin.codegen.ExtendedCallable
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.context.CodegenContext import org.jetbrains.kotlin.codegen.context.CodegenContext
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -112,6 +113,10 @@ public abstract class IntrinsicCallable(val returnType1: Type,
public fun calcReceiverType(): Type? { public fun calcReceiverType(): Type? {
return getReceiverClass() ?: getThisType() return getReceiverClass() ?: getThisType()
} }
override fun beforeParameterGeneration(v: InstructionAdapter, value: StackValue?) {
}
} }
@@ -104,7 +104,13 @@ public abstract class IntrinsicMethod implements Callable {
} }
}); });
} }
public Type nullOrObject(Type type) { public Type nullOrObject(Type type) {
return type == null ? null : AsmTypes.OBJECT_TYPE; return nullOr(type, AsmTypes.OBJECT_TYPE);
} }
public Type nullOr(Type type, Type newType) {
return type == null ? null : newType;
}
} }
@@ -14,82 +14,104 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.codegen.intrinsics; package org.jetbrains.kotlin.codegen.intrinsics
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.ExpressionCodegen; import org.jetbrains.kotlin.codegen.ExtendedCallable
import org.jetbrains.kotlin.codegen.StackValue; import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.psi.JetBinaryExpression; import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.JetExpression; import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import java.util.List; import org.jetbrains.org.objectweb.asm.Type.*
import static org.jetbrains.org.objectweb.asm.Type.*; public class RangeTo : IntrinsicMethod() {
override fun generateImpl(codegen: ExpressionCodegen, v: InstructionAdapter, returnType: Type, element: PsiElement?, arguments: List<JetExpression>, receiver: StackValue): Type {
v.anew(returnType)
v.dup()
public class RangeTo extends IntrinsicMethod { val type: Type
@NotNull
@Override
public Type generateImpl(
@NotNull ExpressionCodegen codegen,
@NotNull InstructionAdapter v,
@NotNull Type returnType,
PsiElement element,
@NotNull List<JetExpression> arguments,
@NotNull StackValue receiver
) {
v.anew(returnType);
v.dup();
Type type;
if (arguments.size() == 1) { if (arguments.size() == 1) {
assert receiver instanceof StackValue.CallReceiver : assert(receiver is StackValue.CallReceiver) { "Receiver in an intrinsic qualified expression should be CallReceiver: " + receiver + " on " + element!!.getText() }
"Receiver in an intrinsic qualified expression should be CallReceiver: " + receiver + " on " + element.getText(); type = parameterType(receiver.type, codegen.expressionType(arguments.get(0)))
type = parameterType(receiver.type, codegen.expressionType(arguments.get(0))); receiver.put(type, v)
receiver.put(type, v); codegen.gen(arguments.get(0), type)
codegen.gen(arguments.get(0), type);
} }
else { else {
JetBinaryExpression expression = (JetBinaryExpression) element; val expression = element as JetBinaryExpression
type = parameterType(codegen.expressionType(expression.getLeft()), codegen.expressionType(expression.getRight())); type = parameterType(codegen.expressionType(expression.getLeft()), codegen.expressionType(expression.getRight()))
codegen.gen(expression.getLeft(), type); codegen.gen(expression.getLeft(), type)
codegen.gen(expression.getRight(), type); codegen.gen(expression.getRight(), type)
} }
v.invokespecial(returnType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, type, type), false); v.invokespecial(returnType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, type, type), false)
return returnType; return returnType
} }
@NotNull private fun nameToPrimitive(name: String) : Type {
private static Type parameterType(@NotNull Type leftType, @NotNull Type rightType) { return when (name) {
int left = leftType.getSort(); "Double" -> DOUBLE_TYPE;
int right = rightType.getSort(); "Float" -> FLOAT_TYPE
"Long" -> LONG_TYPE
"Int" -> INT_TYPE
"Short" -> SHORT_TYPE
"Char" -> CHAR_TYPE
"Byte" -> BYTE_TYPE
else -> throw IllegalStateException("RangeTo intrinsic can only work for primitive types: " + name)
}
}
private fun parameterType(leftType: Type, rightType: Type): Type {
val left = leftType.getSort()
val right = rightType.getSort()
if (left == DOUBLE || right == DOUBLE) { if (left == DOUBLE || right == DOUBLE) {
return DOUBLE_TYPE; return DOUBLE_TYPE
} }
else if (left == FLOAT || right == FLOAT) { else if (left == FLOAT || right == FLOAT) {
return FLOAT_TYPE; return FLOAT_TYPE
} }
else if (left == LONG || right == LONG) { else if (left == LONG || right == LONG) {
return LONG_TYPE; return LONG_TYPE
} }
else if (left == INT || right == INT) { else if (left == INT || right == INT) {
return INT_TYPE; return INT_TYPE
} }
else if (left == SHORT || right == SHORT) { else if (left == SHORT || right == SHORT) {
return SHORT_TYPE; return SHORT_TYPE
} }
else if (left == CHAR || right == CHAR) { else if (left == CHAR || right == CHAR) {
return CHAR_TYPE; return CHAR_TYPE
} }
else if (left == BYTE || right == BYTE) { else if (left == BYTE || right == BYTE) {
return BYTE_TYPE; return BYTE_TYPE
} }
else { else {
throw new IllegalStateException("RangeTo intrinsic can only work for primitive types: " + leftType + ", " + rightType); throw IllegalStateException("RangeTo intrinsic can only work for primitive types: " + leftType + ", " + rightType)
} }
} }
}
override fun supportCallable(): Boolean {
return true
}
override fun toCallable(fd: FunctionDescriptor, isSuper: Boolean, resolvedCall: ResolvedCall<*>, codegen: ExpressionCodegen): ExtendedCallable {
val method = codegen.getState().getTypeMapper().mapToCallableMethod(fd, false, codegen.getContext())
val argType = nameToPrimitive(method.getReturnType().getInternalName().substringAfter("kotlin/").substringBefore("Range"))
return object : IntrinsicCallable(method.getReturnType(), method.getValueParameterTypes().map { argType }, nullOr(method.getThisType(), argType), nullOr(method.getReceiverClass(), argType)) {
override fun beforeParameterGeneration(v: InstructionAdapter, value: StackValue?) {
v.anew(getReturnType())
v.dup()
value?.moveToTopOfStack(value!!.type, v, 2)
}
override fun invokeIntrinsic(v: InstructionAdapter) {
v.invokespecial(getReturnType().getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, argType, argType), false)
}
}
}
}