From 2bdf1a4290094925cd9b7b4997c7625aa5f20c2d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 4 Jul 2014 19:09:15 +0400 Subject: [PATCH] Introduce an abstract ArgumentGenerator in ExpressionCodegen --- .../jet/codegen/ArgumentGenerator.java | 71 ++++++++++ .../codegen/CallBasedArgumentGenerator.java | 86 +++++++++++ .../jet/codegen/ExpressionCodegen.java | 133 +++++++----------- 3 files changed, 206 insertions(+), 84 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/ArgumentGenerator.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/CallBasedArgumentGenerator.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ArgumentGenerator.java b/compiler/backend/src/org/jetbrains/jet/codegen/ArgumentGenerator.java new file mode 100644 index 00000000000..72c58dcae8f --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ArgumentGenerator.java @@ -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 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); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallBasedArgumentGenerator.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallBasedArgumentGenerator.java new file mode 100644 index 00000000000..f25ceac4416 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallBasedArgumentGenerator.java @@ -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 valueParameters; + private final List valueParameterTypes; + private final boolean skipLast; + + public CallBasedArgumentGenerator( + @NotNull ExpressionCodegen codegen, + @NotNull CallGenerator callGenerator, + @NotNull List valueParameters, + @NotNull List 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; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 547c5452fb5..2a2b80c7b90 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1324,11 +1324,10 @@ public class ExpressionCodegen extends JetVisitor 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 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 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(), "", constructor.getDescriptor()); + v.invokespecial(type.getInternalName(), "", 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 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 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 statements, boolean lastStatementIsExpression) { @@ -2126,7 +2130,10 @@ public class ExpressionCodegen extends JetVisitor 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 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 implem callGenerator.putHiddenParams(); - return pushMethodArgumentsWithoutCallReceiver(resolvedCall, callableMethod.getValueParameterTypes(), skipLast, callGenerator); - } - - private int pushMethodArgumentsWithoutCallReceiver( - @NotNull ResolvedCall resolvedCall, - List valueParameterTypes, - boolean skipLast, - @NotNull CallGenerator callGenerator - ) { List valueArguments = resolvedCall.getValueArgumentsByIndex(); - CallableDescriptor fd = resolvedCall.getResultingDescriptor(); - if (valueArguments == null) { - throw new IllegalStateException("Failed to arrange value arguments by index: " + fd); - } - List 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 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