default args

This commit is contained in:
Alex Tkachman
2011-10-19 07:42:31 +02:00
parent 1b4bebaaf0
commit 33d09eb1df
10 changed files with 475 additions and 96 deletions
@@ -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());
}
}