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);
|
||||
|
||||
ConstructorDescriptor constructorDescriptor = bindingContext.get(CONSTRUCTOR, expression.getObjectDeclaration());
|
||||
assert constructorDescriptor != null;
|
||||
Method constructor = typeMapper.mapSignature(constructorDescriptor).getAsmMethod();
|
||||
assert constructorDescriptor != null : "Unresolved constructor: " + expression.getText();
|
||||
CallableMethod constructor = typeMapper.mapToCallableMethod(constructorDescriptor);
|
||||
|
||||
Type type = bindingContext.get(ASM_TYPE, constructorDescriptor.getContainingDeclaration());
|
||||
assert type != null;
|
||||
Type type = typeMapper.mapType(constructorDescriptor.getContainingDeclaration());
|
||||
|
||||
v.anew(type);
|
||||
v.dup();
|
||||
@@ -1339,43 +1338,48 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
if (superCall != null) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(superCall, bindingContext);
|
||||
ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
|
||||
Type[] argumentTypes = typeMapper.mapSignature(superConstructor).getAsmMethod().getArgumentTypes();
|
||||
pushMethodArgumentsWithoutCallReceiver(resolvedCall, Arrays.asList(argumentTypes), false, defaultCallGenerator);
|
||||
List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
|
||||
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);
|
||||
}
|
||||
|
||||
public void pushClosureOnStack(@Nullable CalculatedClosure closure, boolean ignoreThisAndReceiver, @NotNull CallGenerator callGenerator) {
|
||||
if (closure != null) {
|
||||
int paramIndex = 0;
|
||||
if (!ignoreThisAndReceiver) {
|
||||
ClassDescriptor captureThis = closure.getCaptureThis();
|
||||
if (captureThis != null) {
|
||||
StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
|
||||
if (closure == null) return;
|
||||
|
||||
assert !isPrimitive(thisOrOuter.type) : "This or outer should be non primitive: " + thisOrOuter.type;
|
||||
callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, paramIndex++);
|
||||
}
|
||||
int paramIndex = 0;
|
||||
if (!ignoreThisAndReceiver) {
|
||||
ClassDescriptor captureThis = closure.getCaptureThis();
|
||||
if (captureThis != null) {
|
||||
StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
|
||||
|
||||
JetType captureReceiver = closure.getCaptureReceiverType();
|
||||
if (captureReceiver != null) {
|
||||
Type asmType = typeMapper.mapType(captureReceiver);
|
||||
StackValue.Local capturedReceiver = StackValue.local(context.isStatic() ? 0 : 1, asmType);
|
||||
callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++);
|
||||
}
|
||||
assert !isPrimitive(thisOrOuter.type) : "This or outer should be non primitive: " + thisOrOuter.type;
|
||||
callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, 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++);
|
||||
JetType captureReceiver = closure.getCaptureReceiverType();
|
||||
if (captureReceiver != null) {
|
||||
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()) {
|
||||
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) {
|
||||
@@ -2126,7 +2130,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) :
|
||||
"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)) {
|
||||
tailRecursionCodegen.generateTailRecursion(resolvedCall);
|
||||
@@ -2309,12 +2316,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
return false;
|
||||
}
|
||||
|
||||
private int pushMethodArgumentsWithCallReceiver(
|
||||
private int pushMethodArguments(
|
||||
@Nullable StackValue receiver,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull CallableMethod callableMethod,
|
||||
boolean skipLast,
|
||||
@NotNull CallGenerator callGenerator
|
||||
@NotNull CallGenerator callGenerator,
|
||||
@NotNull ArgumentGenerator argumentGenerator
|
||||
) {
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
|
||||
@@ -2325,57 +2332,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
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();
|
||||
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
||||
if (valueArguments == null) {
|
||||
throw new IllegalStateException("Failed to arrange value arguments by index: " + fd);
|
||||
}
|
||||
List<ValueParameterDescriptor> valueParameters = fd.getValueParameters();
|
||||
assert valueArguments != null : "Failed to arrange value arguments by index: " + descriptor;
|
||||
|
||||
int n = valueParameters.size();
|
||||
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;
|
||||
return argumentGenerator.generate(valueArguments);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (callable instanceof CallableMethod) {
|
||||
boolean skipLast = !isGetter;
|
||||
pushMethodArgumentsWithCallReceiver(receiver, resolvedCall, (CallableMethod) callable, skipLast, defaultCallGenerator);
|
||||
CallableMethod callableMethod = (CallableMethod) callable;
|
||||
ArgumentGenerator argumentGenerator =
|
||||
new CallBasedArgumentGenerator(this, defaultCallGenerator,
|
||||
resolvedCall.getResultingDescriptor().getValueParameters(),
|
||||
callableMethod.getValueParameterTypes(),
|
||||
/* skipLast = */ !isGetter);
|
||||
pushMethodArguments(receiver, resolvedCall, callableMethod, defaultCallGenerator, argumentGenerator);
|
||||
}
|
||||
else {
|
||||
gen(array, arrayType); // intrinsic method
|
||||
|
||||
Reference in New Issue
Block a user