Introduce an abstract ArgumentGenerator in ExpressionCodegen
This commit is contained in:
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.DefaultValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ExpressionValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.VarargValueArgument;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class ArgumentGenerator {
|
||||||
|
/**
|
||||||
|
* @return a bit mask of default arguments which should be passed as the last argument to $default method, if there were any default
|
||||||
|
* arguments, or 0 if there were none
|
||||||
|
*/
|
||||||
|
public int generate(@NotNull List<ResolvedValueArgument> valueArguments) {
|
||||||
|
int mask = 0;
|
||||||
|
int n = valueArguments.size();
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
ResolvedValueArgument argument = valueArguments.get(i);
|
||||||
|
if (argument instanceof ExpressionValueArgument) {
|
||||||
|
generateExpression(i, (ExpressionValueArgument) argument);
|
||||||
|
}
|
||||||
|
else if (argument instanceof DefaultValueArgument) {
|
||||||
|
mask |= 1 << i;
|
||||||
|
generateDefault(i, (DefaultValueArgument) argument);
|
||||||
|
}
|
||||||
|
else if (argument instanceof VarargValueArgument) {
|
||||||
|
generateVararg(i, (VarargValueArgument) argument);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
generateOther(i, argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void generateExpression(int i, @NotNull ExpressionValueArgument argument) {
|
||||||
|
throw new UnsupportedOperationException("Unsupported expression value argument #" + i + ": " + argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void generateDefault(int i, @NotNull DefaultValueArgument argument) {
|
||||||
|
throw new UnsupportedOperationException("Unsupported default value argument #" + i + ": " + argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void generateVararg(int i, @NotNull VarargValueArgument argument) {
|
||||||
|
throw new UnsupportedOperationException("Unsupported vararg value argument #" + i + ": " + argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("MethodMayBeStatic") // is supposed to be overridden
|
||||||
|
protected void generateOther(int i, @NotNull ResolvedValueArgument argument) {
|
||||||
|
throw new UnsupportedOperationException("Unsupported value argument #" + i + ": " + argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
|
import org.jetbrains.jet.lang.psi.ValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.DefaultValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.ExpressionValueArgument;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.model.VarargValueArgument;
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.codegen.AsmUtil.pushDefaultValueOnStack;
|
||||||
|
|
||||||
|
public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||||
|
private final ExpressionCodegen codegen;
|
||||||
|
private final CallGenerator callGenerator;
|
||||||
|
private final List<ValueParameterDescriptor> valueParameters;
|
||||||
|
private final List<Type> valueParameterTypes;
|
||||||
|
private final boolean skipLast;
|
||||||
|
|
||||||
|
public CallBasedArgumentGenerator(
|
||||||
|
@NotNull ExpressionCodegen codegen,
|
||||||
|
@NotNull CallGenerator callGenerator,
|
||||||
|
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||||
|
@NotNull List<Type> valueParameterTypes,
|
||||||
|
boolean skipLast
|
||||||
|
) {
|
||||||
|
this.codegen = codegen;
|
||||||
|
this.callGenerator = callGenerator;
|
||||||
|
this.valueParameters = valueParameters;
|
||||||
|
this.valueParameterTypes = valueParameterTypes;
|
||||||
|
this.skipLast = skipLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateExpression(int i, @NotNull ExpressionValueArgument argument) {
|
||||||
|
if (shouldSkip(i)) return;
|
||||||
|
ValueParameterDescriptor parameter = valueParameters.get(i);
|
||||||
|
Type type = valueParameterTypes.get(i);
|
||||||
|
ValueArgument valueArgument = argument.getValueArgument();
|
||||||
|
assert valueArgument != null;
|
||||||
|
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||||
|
assert argumentExpression != null : valueArgument.asElement().getText();
|
||||||
|
callGenerator.genValueAndPut(parameter, argumentExpression, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateDefault(int i, @NotNull DefaultValueArgument argument) {
|
||||||
|
if (shouldSkip(i)) return;
|
||||||
|
ValueParameterDescriptor parameter = valueParameters.get(i);
|
||||||
|
Type type = valueParameterTypes.get(i);
|
||||||
|
pushDefaultValueOnStack(type, codegen.v);
|
||||||
|
callGenerator.afterParameterPut(type, null, parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateVararg(int i, @NotNull VarargValueArgument argument) {
|
||||||
|
if (shouldSkip(i)) return;
|
||||||
|
ValueParameterDescriptor parameter = valueParameters.get(i);
|
||||||
|
Type type = valueParameterTypes.get(i);
|
||||||
|
codegen.genVarargs(argument, parameter.getType());
|
||||||
|
callGenerator.afterParameterPut(type, null, parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldSkip(int i) {
|
||||||
|
return skipLast && i == valueParameters.size() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1324,11 +1324,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
CalculatedClosure closure = generateObjectLiteral(expression);
|
CalculatedClosure closure = generateObjectLiteral(expression);
|
||||||
|
|
||||||
ConstructorDescriptor constructorDescriptor = bindingContext.get(CONSTRUCTOR, expression.getObjectDeclaration());
|
ConstructorDescriptor constructorDescriptor = bindingContext.get(CONSTRUCTOR, expression.getObjectDeclaration());
|
||||||
assert constructorDescriptor != null;
|
assert constructorDescriptor != null : "Unresolved constructor: " + expression.getText();
|
||||||
Method constructor = typeMapper.mapSignature(constructorDescriptor).getAsmMethod();
|
CallableMethod constructor = typeMapper.mapToCallableMethod(constructorDescriptor);
|
||||||
|
|
||||||
Type type = bindingContext.get(ASM_TYPE, constructorDescriptor.getContainingDeclaration());
|
Type type = typeMapper.mapType(constructorDescriptor.getContainingDeclaration());
|
||||||
assert type != null;
|
|
||||||
|
|
||||||
v.anew(type);
|
v.anew(type);
|
||||||
v.dup();
|
v.dup();
|
||||||
@@ -1339,43 +1338,48 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
if (superCall != null) {
|
if (superCall != null) {
|
||||||
ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(superCall, bindingContext);
|
ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(superCall, bindingContext);
|
||||||
ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
|
ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
|
||||||
Type[] argumentTypes = typeMapper.mapSignature(superConstructor).getAsmMethod().getArgumentTypes();
|
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
|
||||||
pushMethodArgumentsWithoutCallReceiver(resolvedCall, Arrays.asList(argumentTypes), false, defaultCallGenerator);
|
assert valueArguments != null : "Failed to arrange value arguments by index: " + superConstructor;
|
||||||
|
ArgumentGenerator argumentGenerator =
|
||||||
|
new CallBasedArgumentGenerator(this, defaultCallGenerator, superConstructor.getValueParameters(),
|
||||||
|
typeMapper.mapToCallableMethod(superConstructor).getValueParameterTypes(),
|
||||||
|
/* skipLast = */ false);
|
||||||
|
argumentGenerator.generate(valueArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
v.invokespecial(type.getInternalName(), "<init>", constructor.getDescriptor());
|
v.invokespecial(type.getInternalName(), "<init>", constructor.getAsmMethod().getDescriptor());
|
||||||
return StackValue.onStack(type);
|
return StackValue.onStack(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushClosureOnStack(@Nullable CalculatedClosure closure, boolean ignoreThisAndReceiver, @NotNull CallGenerator callGenerator) {
|
public void pushClosureOnStack(@Nullable CalculatedClosure closure, boolean ignoreThisAndReceiver, @NotNull CallGenerator callGenerator) {
|
||||||
if (closure != null) {
|
if (closure == null) return;
|
||||||
int paramIndex = 0;
|
|
||||||
if (!ignoreThisAndReceiver) {
|
|
||||||
ClassDescriptor captureThis = closure.getCaptureThis();
|
|
||||||
if (captureThis != null) {
|
|
||||||
StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
|
|
||||||
|
|
||||||
assert !isPrimitive(thisOrOuter.type) : "This or outer should be non primitive: " + thisOrOuter.type;
|
int paramIndex = 0;
|
||||||
callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, paramIndex++);
|
if (!ignoreThisAndReceiver) {
|
||||||
}
|
ClassDescriptor captureThis = closure.getCaptureThis();
|
||||||
|
if (captureThis != null) {
|
||||||
|
StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
|
||||||
|
|
||||||
JetType captureReceiver = closure.getCaptureReceiverType();
|
assert !isPrimitive(thisOrOuter.type) : "This or outer should be non primitive: " + thisOrOuter.type;
|
||||||
if (captureReceiver != null) {
|
callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, paramIndex++);
|
||||||
Type asmType = typeMapper.mapType(captureReceiver);
|
|
||||||
StackValue.Local capturedReceiver = StackValue.local(context.isStatic() ? 0 : 1, asmType);
|
|
||||||
callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
|
JetType captureReceiver = closure.getCaptureReceiverType();
|
||||||
Type sharedVarType = typeMapper.getSharedVarType(entry.getKey());
|
if (captureReceiver != null) {
|
||||||
if (sharedVarType == null) {
|
Type asmType = typeMapper.mapType(captureReceiver);
|
||||||
sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey());
|
StackValue.Local capturedReceiver = StackValue.local(context.isStatic() ? 0 : 1, asmType);
|
||||||
}
|
callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++);
|
||||||
StackValue capturedVar = entry.getValue().getOuterValue(this);
|
|
||||||
callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
|
||||||
|
Type sharedVarType = typeMapper.getSharedVarType(entry.getKey());
|
||||||
|
if (sharedVarType == null) {
|
||||||
|
sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey());
|
||||||
|
}
|
||||||
|
StackValue capturedVar = entry.getValue().getOuterValue(this);
|
||||||
|
callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue generateBlock(List<JetElement> statements, boolean lastStatementIsExpression) {
|
private StackValue generateBlock(List<JetElement> statements, boolean lastStatementIsExpression) {
|
||||||
@@ -2126,7 +2130,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) :
|
assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) :
|
||||||
"Tail recursive method couldn't be inlined " + descriptor;
|
"Tail recursive method couldn't be inlined " + descriptor;
|
||||||
|
|
||||||
int mask = pushMethodArgumentsWithCallReceiver(receiver, resolvedCall, callableMethod, false, callGenerator);
|
ArgumentGenerator argumentGenerator = new CallBasedArgumentGenerator(this, callGenerator, descriptor.getValueParameters(),
|
||||||
|
callableMethod.getValueParameterTypes(),
|
||||||
|
/* skipLast = */ false);
|
||||||
|
int mask = pushMethodArguments(receiver, resolvedCall, callableMethod, callGenerator, argumentGenerator);
|
||||||
|
|
||||||
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
|
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
|
||||||
tailRecursionCodegen.generateTailRecursion(resolvedCall);
|
tailRecursionCodegen.generateTailRecursion(resolvedCall);
|
||||||
@@ -2309,12 +2316,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int pushMethodArgumentsWithCallReceiver(
|
private int pushMethodArguments(
|
||||||
@Nullable StackValue receiver,
|
@Nullable StackValue receiver,
|
||||||
@NotNull ResolvedCall<?> resolvedCall,
|
@NotNull ResolvedCall<?> resolvedCall,
|
||||||
@NotNull CallableMethod callableMethod,
|
@NotNull CallableMethod callableMethod,
|
||||||
boolean skipLast,
|
@NotNull CallGenerator callGenerator,
|
||||||
@NotNull CallGenerator callGenerator
|
@NotNull ArgumentGenerator argumentGenerator
|
||||||
) {
|
) {
|
||||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||||
|
|
||||||
@@ -2325,57 +2332,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
|
|
||||||
callGenerator.putHiddenParams();
|
callGenerator.putHiddenParams();
|
||||||
|
|
||||||
return pushMethodArgumentsWithoutCallReceiver(resolvedCall, callableMethod.getValueParameterTypes(), skipLast, callGenerator);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int pushMethodArgumentsWithoutCallReceiver(
|
|
||||||
@NotNull ResolvedCall<?> resolvedCall,
|
|
||||||
List<Type> valueParameterTypes,
|
|
||||||
boolean skipLast,
|
|
||||||
@NotNull CallGenerator callGenerator
|
|
||||||
) {
|
|
||||||
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
|
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
|
||||||
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
assert valueArguments != null : "Failed to arrange value arguments by index: " + descriptor;
|
||||||
if (valueArguments == null) {
|
|
||||||
throw new IllegalStateException("Failed to arrange value arguments by index: " + fd);
|
|
||||||
}
|
|
||||||
List<ValueParameterDescriptor> valueParameters = fd.getValueParameters();
|
|
||||||
|
|
||||||
int n = valueParameters.size();
|
return argumentGenerator.generate(valueArguments);
|
||||||
if (n != valueArguments.size()) {
|
|
||||||
throw new IllegalStateException("Parameters and arguments size mismatch: " + n + " != " + valueArguments.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
int mask = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
if (skipLast && i == n - 1) break;
|
|
||||||
|
|
||||||
ValueParameterDescriptor valueParameter = valueParameters.get(i);
|
|
||||||
ResolvedValueArgument argument = valueArguments.get(i);
|
|
||||||
Type parameterType = valueParameterTypes.get(i);
|
|
||||||
if (argument instanceof ExpressionValueArgument) {
|
|
||||||
ValueArgument valueArgument = ((ExpressionValueArgument) argument).getValueArgument();
|
|
||||||
assert valueArgument != null;
|
|
||||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
|
||||||
assert argumentExpression != null : valueArgument.asElement().getText();
|
|
||||||
callGenerator.genValueAndPut(valueParameter, argumentExpression, parameterType);
|
|
||||||
}
|
|
||||||
else if (argument instanceof DefaultValueArgument) {
|
|
||||||
pushDefaultValueOnStack(parameterType, v);
|
|
||||||
mask |= 1 << i;
|
|
||||||
callGenerator.afterParameterPut(parameterType, null, valueParameter);
|
|
||||||
}
|
|
||||||
else if (argument instanceof VarargValueArgument) {
|
|
||||||
genVarargs((VarargValueArgument) argument, valueParameter.getType());
|
|
||||||
callGenerator.afterParameterPut(parameterType, null, valueParameter);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new UnsupportedOperationException("Unsupported value argument: " + argument);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull JetType outType) {
|
public void genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull JetType outType) {
|
||||||
@@ -3407,8 +3367,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
Type[] argumentTypes = asmMethod.getArgumentTypes();
|
Type[] argumentTypes = asmMethod.getArgumentTypes();
|
||||||
|
|
||||||
if (callable instanceof CallableMethod) {
|
if (callable instanceof CallableMethod) {
|
||||||
boolean skipLast = !isGetter;
|
CallableMethod callableMethod = (CallableMethod) callable;
|
||||||
pushMethodArgumentsWithCallReceiver(receiver, resolvedCall, (CallableMethod) callable, skipLast, defaultCallGenerator);
|
ArgumentGenerator argumentGenerator =
|
||||||
|
new CallBasedArgumentGenerator(this, defaultCallGenerator,
|
||||||
|
resolvedCall.getResultingDescriptor().getValueParameters(),
|
||||||
|
callableMethod.getValueParameterTypes(),
|
||||||
|
/* skipLast = */ !isGetter);
|
||||||
|
pushMethodArguments(receiver, resolvedCall, callableMethod, defaultCallGenerator, argumentGenerator);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gen(array, arrayType); // intrinsic method
|
gen(array, arrayType); // intrinsic method
|
||||||
|
|||||||
Reference in New Issue
Block a user