default args
This commit is contained in:
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
@@ -89,4 +90,12 @@ public class CallableMethod implements Callable {
|
||||
public Type getGenerateCalleeType() {
|
||||
return generateCalleeType;
|
||||
}
|
||||
|
||||
public void invokeWithDefault(InstructionAdapter v, int mask) {
|
||||
v.iconst(mask);
|
||||
String desc = getSignature().getDescriptor().replace(")", "I)");
|
||||
if(getInvokeOpcode() != Opcodes.INVOKESTATIC)
|
||||
desc = desc.replace("(", "(L" + getOwner() + ";");
|
||||
v.visitMethodInsn(Opcodes.INVOKESTATIC, getInvokeOpcode() == Opcodes.INVOKEINTERFACE ? getOwner() + "$$TImpl" : getOwner(), getSignature().getName() + "$default", desc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@ import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
import org.objectweb.asm.signature.SignatureWriter;
|
||||
@@ -26,6 +23,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
|
||||
public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, ClassContext context) {
|
||||
@@ -68,8 +67,8 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
appendType(signatureWriter, funDescriptor.getReturnType(), '=');
|
||||
signatureWriter.visitEnd();
|
||||
|
||||
cv.visit(Opcodes.V1_6,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
cv.visit(V1_6,
|
||||
ACC_PUBLIC,
|
||||
name,
|
||||
null,
|
||||
funClass,
|
||||
@@ -79,7 +78,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
|
||||
|
||||
generateBridge(name, funDescriptor, cv);
|
||||
boolean captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
|
||||
captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
|
||||
final Type enclosingType = context.enclosingClassType(state.getTypeMapper());
|
||||
if (enclosingType == null) captureThis = false;
|
||||
|
||||
@@ -89,6 +88,10 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
cv.visitField(0, "this$0", enclosingType.getDescriptor(), null, null);
|
||||
}
|
||||
|
||||
if(isConst()) {
|
||||
generateConstInstance();
|
||||
}
|
||||
|
||||
cv.visitEnd();
|
||||
|
||||
final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor, captureThis);
|
||||
@@ -99,6 +102,48 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
return answer;
|
||||
}
|
||||
|
||||
private void generateConstInstance() {
|
||||
cv.visitField(ACC_PRIVATE| ACC_STATIC, "$instance", "Ljava/lang/ref/SoftReference;", null, null);
|
||||
|
||||
MethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, "$getInstance", "()L" + name + ";", null, new String[0]);
|
||||
mv.visitCode();
|
||||
mv.visitFieldInsn(GETSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;");
|
||||
mv.visitInsn(DUP);
|
||||
Label makeNew = new Label();
|
||||
mv.visitJumpInsn(IFNULL, makeNew);
|
||||
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ref/SoftReference", "get", "()Ljava/lang/Object;");
|
||||
mv.visitInsn(DUP);
|
||||
|
||||
Label ret = new Label();
|
||||
mv.visitJumpInsn(IFNULL, makeNew);
|
||||
mv.visitTypeInsn(CHECKCAST, name);
|
||||
mv.visitJumpInsn(GOTO, ret);
|
||||
|
||||
mv.visitLabel(makeNew);
|
||||
mv.visitInsn(POP);
|
||||
|
||||
mv.visitTypeInsn(NEW, "java/lang/ref/SoftReference");
|
||||
mv.visitInsn(DUP);
|
||||
|
||||
mv.visitTypeInsn(NEW, name);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitVarInsn(ASTORE, 0);
|
||||
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, name, "<init>", "()V");
|
||||
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ref/SoftReference", "<init>", "(Ljava/lang/Object;)V");
|
||||
mv.visitFieldInsn(PUTSTATIC, name, "$instance", "Ljava/lang/ref/SoftReference;");
|
||||
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
|
||||
mv.visitLabel(ret);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(0,0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private boolean generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, JetFunctionLiteral body) {
|
||||
final ClassContext closureContext = context.intoClosure(name, this);
|
||||
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
|
||||
@@ -110,7 +155,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
final Method bridge = erasedInvokeSignature(funDescriptor);
|
||||
final Method delegate = invokeSignature(funDescriptor);
|
||||
|
||||
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]);
|
||||
final MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "invoke", bridge.getDescriptor(), state.getTypeMapper().genericSignature(funDescriptor), new String[0]);
|
||||
mv.visitCode();
|
||||
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
@@ -164,7 +209,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
}
|
||||
|
||||
final Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
|
||||
final MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]);
|
||||
final MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]);
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
ExpressionCodegen expressionCodegen = new ExpressionCodegen(mv, null, Type.VOID_TYPE, context, state);
|
||||
@@ -190,7 +235,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
StackValue.field(type, name, fieldName, false).store(iv);
|
||||
}
|
||||
|
||||
iv.visitInsn(Opcodes.RETURN);
|
||||
iv.visitInsn(RETURN);
|
||||
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
@@ -219,7 +264,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
|
||||
public static CallableMethod asCallableMethod(FunctionDescriptor fd) {
|
||||
Method descriptor = erasedInvokeSignature(fd);
|
||||
String owner = getInternalClassName(fd);
|
||||
final CallableMethod result = new CallableMethod(owner, descriptor, Opcodes.INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
|
||||
final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
|
||||
if (fd.getReceiverParameter().exists()) {
|
||||
result.setNeedsReceiver(null);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.*;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
@@ -543,23 +544,29 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
|
||||
}
|
||||
else {
|
||||
final GeneratedAnonymousClassDescriptor closure = new ClosureCodegen(state, this, context).gen(expression);
|
||||
ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context);
|
||||
final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression);
|
||||
|
||||
v.anew(Type.getObjectType(closure.getClassname()));
|
||||
v.dup();
|
||||
|
||||
final Method cons = closure.getConstructor();
|
||||
|
||||
if (closure.isCaptureThis()) {
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
if(closureCodegen.isConst()) {
|
||||
v.invokestatic(closure.getClassname(), "$getInstance", "()L" + closure.getClassname() + ";");
|
||||
}
|
||||
else {
|
||||
v.anew(Type.getObjectType(closure.getClassname()));
|
||||
v.dup();
|
||||
|
||||
for (int i = 0; i < closure.getArgs().size(); i++) {
|
||||
StackValue arg = closure.getArgs().get(i);
|
||||
arg.put(cons.getArgumentTypes()[i], v);
|
||||
final Method cons = closure.getConstructor();
|
||||
|
||||
if (closure.isCaptureThis()) {
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
|
||||
for (int i = 0; i < closure.getArgs().size(); i++) {
|
||||
StackValue arg = closure.getArgs().get(i);
|
||||
arg.put(cons.getArgumentTypes()[i], v);
|
||||
}
|
||||
|
||||
v.invokespecial(closure.getClassname(), "<init>", cons.getDescriptor());
|
||||
}
|
||||
|
||||
v.invokespecial(closure.getClassname(), "<init>", cons.getDescriptor());
|
||||
return StackValue.onStack(Type.getObjectType(closure.getClassname()));
|
||||
}
|
||||
}
|
||||
@@ -1018,11 +1025,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
}
|
||||
pushMethodArguments(expression, callableMethod.getValueParameterTypes());
|
||||
int mask = pushMethodArguments(expression, callableMethod.getValueParameterTypes());
|
||||
if (callableMethod.acceptsTypeArguments()) {
|
||||
pushTypeArguments(expression);
|
||||
}
|
||||
callableMethod.invoke(v);
|
||||
if(mask == 0)
|
||||
callableMethod.invoke(v);
|
||||
else
|
||||
callableMethod.invokeWithDefault(v, mask);
|
||||
}
|
||||
|
||||
private void setOwnerFromCall(CallableMethod callableMethod, JetCallElement expression) {
|
||||
@@ -1118,11 +1128,52 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void pushMethodArguments(JetCallElement expression, List<Type> valueParameterTypes) {
|
||||
private int pushMethodArguments(JetCallElement expression, List<Type> valueParameterTypes) {
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
|
||||
List<? extends ValueArgument> args = expression.getValueArguments();
|
||||
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
|
||||
ValueArgument arg = args.get(i);
|
||||
gen(arg.getArgumentExpression(), valueParameterTypes.get(i));
|
||||
if(resolvedCall != null) {
|
||||
Map<ValueParameterDescriptor,ResolvedValueArgument> valueArguments = resolvedCall.getValueArguments();
|
||||
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
||||
|
||||
int index = 0;
|
||||
int mask = 0;
|
||||
for (ValueParameterDescriptor valueParameterDescriptor : fd.getValueParameters()) {
|
||||
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameterDescriptor);
|
||||
if(resolvedValueArgument instanceof ExpressionValueArgument) {
|
||||
ExpressionValueArgument valueArgument = (ExpressionValueArgument) resolvedValueArgument;
|
||||
gen(valueArgument.getExpression(), valueParameterTypes.get(index));
|
||||
}
|
||||
else if(resolvedValueArgument instanceof DefaultValueArgument) {
|
||||
Type type = valueParameterTypes.get(index);
|
||||
if(type.getSort() == Type.OBJECT||type.getSort() == Type.ARRAY)
|
||||
v.aconst(null);
|
||||
else if(type.getSort() == Type.FLOAT) {
|
||||
v.aconst(0f);
|
||||
}
|
||||
else if(type.getSort() == Type.DOUBLE) {
|
||||
v.aconst(0d);
|
||||
}
|
||||
else {
|
||||
v.iconst(0);
|
||||
}
|
||||
mask |= (1 << index);
|
||||
}
|
||||
else if(resolvedValueArgument instanceof VarargValueArgument) {
|
||||
throw new UnsupportedOperationException("Varargs are not supported yet");
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
else {
|
||||
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
|
||||
ValueArgument arg = args.get(i);
|
||||
gen(arg.getArgumentExpression(), valueParameterTypes.get(i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1739,6 +1790,21 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
}
|
||||
|
||||
private void pushTypeArguments(JetCallElement expression) {
|
||||
// todo when frontend calculates
|
||||
// ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
|
||||
// if(resolvedCall != null) {
|
||||
// Map<TypeParameterDescriptor, JetType> typeArguments = resolvedCall.getTypeArguments();
|
||||
// CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
|
||||
// for (TypeParameterDescriptor typeParameterDescriptor : resultingDescriptor.getTypeParameters()) {
|
||||
// JetType jetType = typeArguments.get(typeParameterDescriptor);
|
||||
// generateTypeInfo(jetType);
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
|
||||
// pushTypeArgument(jetTypeArgument);
|
||||
// }
|
||||
// }
|
||||
for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
|
||||
pushTypeArgument(jetTypeArgument);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.*;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
* @author yole
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class FunctionCodegen {
|
||||
private final ClassContext owner;
|
||||
@@ -54,74 +50,81 @@ public class FunctionCodegen {
|
||||
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
|
||||
List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
|
||||
|
||||
int flags = Opcodes.ACC_PUBLIC; // TODO.
|
||||
int flags = ACC_PUBLIC; // TODO.
|
||||
|
||||
OwnerKind kind = context.getContextKind();
|
||||
|
||||
if(kind == OwnerKind.TRAIT_IMPL && bodyExpressions == null)
|
||||
return;
|
||||
if (kind != OwnerKind.TRAIT_IMPL || bodyExpressions != null) {
|
||||
|
||||
boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL;
|
||||
if (isStatic) flags |= Opcodes.ACC_STATIC;
|
||||
boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL;
|
||||
if (isStatic) flags |= ACC_STATIC;
|
||||
|
||||
boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration()));
|
||||
if (isAbstract) flags |= Opcodes.ACC_ABSTRACT;
|
||||
boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration()));
|
||||
if (isAbstract) flags |= ACC_ABSTRACT;
|
||||
|
||||
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
|
||||
if (!isAbstract) {
|
||||
mv.visitCode();
|
||||
FrameMap frameMap = context.prepareFrame();
|
||||
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
|
||||
if (!isAbstract) {
|
||||
mv.visitCode();
|
||||
FrameMap frameMap = context.prepareFrame();
|
||||
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state);
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state);
|
||||
|
||||
Type[] argTypes = jvmSignature.getArgumentTypes();
|
||||
for (int i = 0; i < paramDescrs.size(); i++) {
|
||||
ValueParameterDescriptor parameter = paramDescrs.get(i);
|
||||
frameMap.enter(parameter, argTypes[i].getSize());
|
||||
}
|
||||
|
||||
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
|
||||
int slot = frameMap.enterTemp();
|
||||
codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
|
||||
}
|
||||
|
||||
if (kind instanceof OwnerKind.DelegateKind) {
|
||||
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
Type argType = argTypes[i];
|
||||
iv.load(i + 1, argType);
|
||||
}
|
||||
iv.invokeinterface(dk.getOwnerClass(), jvmSignature.getName(), jvmSignature.getDescriptor());
|
||||
iv.areturn(jvmSignature.getReturnType());
|
||||
}
|
||||
else {
|
||||
Type[] argTypes = jvmSignature.getArgumentTypes();
|
||||
for (int i = 0; i < paramDescrs.size(); i++) {
|
||||
ValueParameterDescriptor parameter = paramDescrs.get(i);
|
||||
|
||||
Type sharedVarType = codegen.getSharedVarType(parameter);
|
||||
Type localVarType = state.getTypeMapper().mapType(parameter.getOutType());
|
||||
if(sharedVarType != null) {
|
||||
int index = frameMap.getIndex(parameter);
|
||||
mv.visitTypeInsn(Opcodes.NEW, sharedVarType.getInternalName());
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, sharedVarType.getInternalName(), "<init>", "()V");
|
||||
mv.visitVarInsn(localVarType.getOpcode(Opcodes.ILOAD), index);
|
||||
mv.visitFieldInsn(Opcodes.PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor());
|
||||
mv.visitVarInsn(sharedVarType.getOpcode(Opcodes.ISTORE), index);
|
||||
}
|
||||
frameMap.enter(parameter, argTypes[i].getSize());
|
||||
}
|
||||
|
||||
codegen.returnExpression(bodyExpressions);
|
||||
}
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
|
||||
int slot = frameMap.enterTemp();
|
||||
codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
|
||||
}
|
||||
|
||||
generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind);
|
||||
if (kind instanceof OwnerKind.DelegateKind) {
|
||||
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
dk.getDelegate().put(JetTypeMapper.TYPE_OBJECT, iv);
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
Type argType = argTypes[i];
|
||||
iv.load(i + 1, argType);
|
||||
}
|
||||
iv.invokeinterface(dk.getOwnerClass(), jvmSignature.getName(), jvmSignature.getDescriptor());
|
||||
iv.areturn(jvmSignature.getReturnType());
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < paramDescrs.size(); i++) {
|
||||
ValueParameterDescriptor parameter = paramDescrs.get(i);
|
||||
|
||||
Type sharedVarType = codegen.getSharedVarType(parameter);
|
||||
Type localVarType = state.getTypeMapper().mapType(parameter.getOutType());
|
||||
if (sharedVarType != null) {
|
||||
int index = frameMap.getIndex(parameter);
|
||||
mv.visitTypeInsn(NEW, sharedVarType.getInternalName());
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, sharedVarType.getInternalName(), "<init>", "()V");
|
||||
mv.visitVarInsn(localVarType.getOpcode(ILOAD), index);
|
||||
mv.visitFieldInsn(PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor());
|
||||
mv.visitVarInsn(sharedVarType.getOpcode(ISTORE), index);
|
||||
}
|
||||
}
|
||||
|
||||
codegen.returnExpression(bodyExpressions);
|
||||
}
|
||||
try {
|
||||
mv.visitMaxs(0, 0);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.out.println(t);
|
||||
}
|
||||
mv.visitEnd();
|
||||
|
||||
generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind);
|
||||
}
|
||||
}
|
||||
|
||||
generateDefaultIfNeeded(context, state, v, jvmSignature, functionDescriptor, kind);
|
||||
}
|
||||
|
||||
static void generateBridgeIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) {
|
||||
@@ -135,12 +138,153 @@ public class FunctionCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
static void generateDefaultIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) {
|
||||
DeclarationDescriptor contextClass = owner.getContextClass();
|
||||
|
||||
if(kind != OwnerKind.TRAIT_IMPL) {
|
||||
// we don't generate defaults for traits but do for traitImpl
|
||||
if(contextClass instanceof ClassDescriptor) {
|
||||
PsiElement psiElement = state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, contextClass);
|
||||
if(psiElement instanceof JetClass) {
|
||||
JetClass element = (JetClass) psiElement;
|
||||
if(element.isTrait())
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean needed = false;
|
||||
for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
|
||||
if(parameterDescriptor.hasDefaultValue()) {
|
||||
needed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(needed) {
|
||||
boolean hasReceiver = functionDescriptor.getReceiverParameter().exists();
|
||||
boolean isStatic = kind == OwnerKind.NAMESPACE;
|
||||
|
||||
if(kind == OwnerKind.TRAIT_IMPL) {
|
||||
String correctedDescr = "(" + jvmSignature.getDescriptor().substring(jvmSignature.getDescriptor().indexOf(";") + 1);
|
||||
jvmSignature = new Method(jvmSignature.getName(), correctedDescr);
|
||||
}
|
||||
|
||||
int flags = ACC_PUBLIC; // TODO.
|
||||
|
||||
String ownerInternalName = contextClass instanceof NamespaceDescriptor ?
|
||||
JetTypeMapper.jvmName((NamespaceDescriptor) contextClass) :
|
||||
state.getTypeMapper().jvmName((ClassDescriptor) contextClass, OwnerKind.IMPLEMENTATION);
|
||||
|
||||
String descriptor = jvmSignature.getDescriptor().replace(")","I)");
|
||||
if(!isStatic)
|
||||
descriptor = descriptor.replace("(","(L" + ownerInternalName + ";");
|
||||
final MethodVisitor mv = v.visitMethod(flags| ACC_STATIC, jvmSignature.getName() + "$default", descriptor, null, null);
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
mv.visitCode();
|
||||
|
||||
FrameMap frameMap = owner.prepareFrame();
|
||||
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), owner, state);
|
||||
|
||||
int var = 0;
|
||||
if(!isStatic) {
|
||||
frameMap.enterTemp();
|
||||
var++;
|
||||
}
|
||||
|
||||
if(hasReceiver) {
|
||||
frameMap.enterTemp();
|
||||
var++;
|
||||
}
|
||||
|
||||
Type[] argTypes = jvmSignature.getArgumentTypes();
|
||||
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
|
||||
for (int i = 0; i < paramDescrs.size(); i++) {
|
||||
ValueParameterDescriptor parameter = paramDescrs.get(i);
|
||||
int size = argTypes[i + (hasReceiver ? 1 : 0)].getSize();
|
||||
var += size;
|
||||
frameMap.enter(parameter, size);
|
||||
}
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
|
||||
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
|
||||
int slot = frameMap.enterTemp();
|
||||
codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO));
|
||||
var++;
|
||||
}
|
||||
|
||||
frameMap.enterTemp();
|
||||
|
||||
int maskIndex = var;
|
||||
|
||||
var = 0;
|
||||
if(!isStatic) {
|
||||
mv.visitVarInsn(ALOAD, var++);
|
||||
}
|
||||
|
||||
if(hasReceiver) {
|
||||
mv.visitVarInsn(ALOAD, var++);
|
||||
}
|
||||
|
||||
Type[] argumentTypes = jvmSignature.getArgumentTypes();
|
||||
for (int index = 0; index < paramDescrs.size(); index++) {
|
||||
ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
|
||||
|
||||
Type t = argumentTypes[(hasReceiver ? 1 : 0) + index];
|
||||
Label endArg = null;
|
||||
if (parameterDescriptor.hasDefaultValue()) {
|
||||
iv.load(maskIndex, Type.INT_TYPE);
|
||||
iv.iconst(1 << index);
|
||||
iv.and(Type.INT_TYPE);
|
||||
Label loadArg = new Label();
|
||||
iv.ifeq(loadArg);
|
||||
|
||||
JetParameter jetParameter = (JetParameter) state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, parameterDescriptor);
|
||||
codegen.gen(jetParameter.getDefaultValue(), t);
|
||||
|
||||
endArg = new Label();
|
||||
iv.goTo(endArg);
|
||||
|
||||
iv.mark(loadArg);
|
||||
}
|
||||
|
||||
iv.load(var, t);
|
||||
var += t.getSize();
|
||||
|
||||
if (parameterDescriptor.hasDefaultValue()) {
|
||||
iv.mark(endArg);
|
||||
}
|
||||
}
|
||||
|
||||
for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
|
||||
iv.load(var++, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
|
||||
if(!isStatic) {
|
||||
if(kind == OwnerKind.TRAIT_IMPL) {
|
||||
iv.invokeinterface(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor());
|
||||
}
|
||||
else
|
||||
iv.invokevirtual(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor());
|
||||
}
|
||||
else {
|
||||
iv.invokestatic(ownerInternalName, jvmSignature.getName(), jvmSignature.getDescriptor());
|
||||
}
|
||||
|
||||
iv.areturn(jvmSignature.getReturnType());
|
||||
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkOverride(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenFunction) {
|
||||
Type type1 = state.getTypeMapper().mapType(overriddenFunction.getOriginal().getReturnType());
|
||||
Type type2 = state.getTypeMapper().mapType(functionDescriptor.getReturnType());
|
||||
if(!type1.equals(type2)) {
|
||||
Method overriden = state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal());
|
||||
int flags = Opcodes.ACC_PUBLIC; // TODO.
|
||||
int flags = ACC_PUBLIC; // TODO.
|
||||
|
||||
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), overriden.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
|
||||
@@ -13,6 +13,8 @@ import java.util.Map;
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class FunctionOrClosureCodegen {
|
||||
protected boolean captureThis;
|
||||
|
||||
public final GenerationState state;
|
||||
protected final ExpressionCodegen exprContext;
|
||||
protected final ClassContext context;
|
||||
@@ -54,4 +56,12 @@ public class FunctionOrClosureCodegen {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCaptureThis() {
|
||||
return captureThis;
|
||||
}
|
||||
|
||||
public boolean isConst () {
|
||||
return !captureThis && closure.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ public class ResolvedCall<D extends CallableDescriptor> {
|
||||
private D resultingDescriptor; // Probably substituted
|
||||
private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method
|
||||
private ReceiverDescriptor receiverArgument = NO_RECEIVER; // receiver of an extension function
|
||||
|
||||
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
|
||||
private final Map<ValueParameterDescriptor, JetType> autoCasts = Maps.newHashMap();
|
||||
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newHashMap();
|
||||
@@ -144,4 +145,8 @@ public class ResolvedCall<D extends CallableDescriptor> {
|
||||
public boolean isDirty() {
|
||||
return someArgumentHasNoType;
|
||||
}
|
||||
|
||||
public Map<TypeParameterDescriptor, JetType> getTypeArguments() {
|
||||
return typeArguments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
fun reformat(
|
||||
str : String,
|
||||
normalizeCase : Boolean = true,
|
||||
uppercaseFirstLetter : Boolean = true,
|
||||
divideByCamelHumps : Boolean = true,
|
||||
wordSeparator : String = " "
|
||||
) =
|
||||
(normalizeCase, uppercaseFirstLetter, divideByCamelHumps, wordSeparator)
|
||||
|
||||
trait A {
|
||||
fun bar2(arg: Int = 239) : Int
|
||||
|
||||
fun bar(arg: Int = 240) : Int = bar2(arg/2)
|
||||
}
|
||||
|
||||
open abstract class B() : A {
|
||||
fun foo(arg: Int = 239 + 1) : Int = arg
|
||||
|
||||
abstract fun foo2(arg: Int = 239) : Int
|
||||
|
||||
override fun bar2(arg: Int) : Int = arg
|
||||
}
|
||||
|
||||
class C() : B() {
|
||||
override fun foo2(arg: Int) : Int = arg
|
||||
}
|
||||
|
||||
// fun <T> T.toPrefixedString(prefix: String = "") = prefix + (this as java.lang.Object).toString()
|
||||
|
||||
fun box() : String {
|
||||
val expected = (true, true, true, " ")
|
||||
|
||||
// if("mama".toPrefixedString("papa") != "papamama") return "fail"
|
||||
// if("mama".toPrefixedString() != "mama") return "fail"
|
||||
if(C().bar(10) != 5) return "fail"
|
||||
if(C().bar() != 120) return "fail"
|
||||
if(C().foo(10) != 10) return "fail"
|
||||
if(C().foo() != 240) return "fail"
|
||||
if(C().foo2() != 239) return "fail"
|
||||
if(C().foo2(10) != 10) return "fail"
|
||||
if(C().bar2() != 239) return "fail"
|
||||
if(C().bar2(10) != 10) return "fail"
|
||||
if(reformat("", true, true, true, " ") != expected) return "fail"
|
||||
if(reformat("", true, true, true) != expected) return "fail"
|
||||
if(reformat("", true, true) != expected) return "fail"
|
||||
if(reformat("", true) != expected) return "fail"
|
||||
if(reformat("") != expected) return "fail"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fun reformat(
|
||||
str : String,
|
||||
normalizeCase : Boolean = true,
|
||||
uppercaseFirstLetter : Boolean = true,
|
||||
divideByCamelHumps : Boolean = false,
|
||||
wordSeparator : String = " "
|
||||
) =
|
||||
(normalizeCase, uppercaseFirstLetter, divideByCamelHumps, wordSeparator)
|
||||
|
||||
fun box() : String {
|
||||
val expected = (true, true, false, " ")
|
||||
if(reformat("", true, true, false, " ") != expected) return "fail"
|
||||
// if(reformat(str="", wordSeparator=" ") != expected) return "fail"
|
||||
// if(reformat("", true, true, false) != expected) return "fail"
|
||||
// if(reformat("", true, true) != expected) return "fail"
|
||||
// if(reformat("", true) != expected) return "fail"
|
||||
// if(reformat("") != expected) return "fail"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fun loop(times : Int) {
|
||||
while(times > 0) {
|
||||
val u : fun(value : Int) : Unit = {
|
||||
System.out?.println(it)
|
||||
}
|
||||
u(times--)
|
||||
}
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
loop(5)
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class FunctionGenTest extends CodegenTestCase {
|
||||
public void testDefaultArgs() throws Exception {
|
||||
blackBoxFile("functions/defaultargs.jet");
|
||||
}
|
||||
|
||||
public void testNamedArgs() throws Exception {
|
||||
blackBoxFile("functions/defaultargs.jet");
|
||||
}
|
||||
|
||||
public void testNoThisNoClosure() throws Exception {
|
||||
blackBoxFile("functions/nothisnoclosure.jet");
|
||||
System.out.println(generateToText());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user