Extract generation logic from FunctionCodegen

Create a new class FunctionGenerationStrategy, which is used to specify exactly
how the body of a function will be generated. This is made primarily to factor
out the hard dependency on PSI in FunctionCodegen.generateMethod(). The PSI
element is now optional and is only used for debug information (as an argument
to newMethod() and endVisit()). This also helps to refactor the confusing logic
about generating default property accessors.

Assert for whether we generate code now for the declared member is now useless,
since generateMethod() will be used also for generating any possible members.

Also surround with "if ( != null)" some method call in genJetAnnotations(), as
null is possible here
This commit is contained in:
Alexander Udalov
2013-04-09 20:01:11 +04:00
parent 98688eed66
commit 9bb3663b54
4 changed files with 129 additions and 64 deletions
@@ -35,7 +35,9 @@ import org.jetbrains.jet.codegen.state.GenerationStateAware;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
@@ -49,7 +51,8 @@ import java.util.List;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.getInternalClassName;
import static org.jetbrains.jet.codegen.CodegenUtil.isConst;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.classNameForAnonymousClass;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
@@ -156,7 +159,7 @@ public class ClosureCodegen extends GenerationStateAware {
CodegenContext closureContext = context.intoClosure(funDescriptor, expressionCodegen);
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(interfaceFunctionName, funDescriptor);
fc.generateMethod(body, jvmMethodSignature, false, null, funDescriptor);
fc.generateMethod(body, jvmMethodSignature, false, null, funDescriptor, new FunctionGenerationStrategy.Default(state, body));
assert closureContext.closure != null;
return closureContext.closure.getCaptureThis();
}
@@ -37,7 +37,7 @@ import org.jetbrains.jet.codegen.state.GenerationStateAware;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
@@ -67,8 +67,8 @@ public class FunctionCodegen extends GenerationStateAware {
this.v = v;
}
public void gen(JetNamedFunction f) {
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f);
public void gen(@NotNull JetNamedFunction function) {
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function);
assert functionDescriptor != null;
OwnerKind kind = owner.getContextKind();
@@ -80,46 +80,29 @@ public class FunctionCodegen extends GenerationStateAware {
isCallInsideSameModuleAsDeclared(functionDescriptor, owner),
kind).getSignature();
if (kind != OwnerKind.TRAIT_IMPL || hasBodyExpression(f)) {
if (kind != OwnerKind.TRAIT_IMPL || function.getBodyExpression() != null) {
boolean needJetAnnotations = kind != OwnerKind.TRAIT_IMPL;
generateMethod(f, method, needJetAnnotations, null, functionDescriptor);
generateMethod(function, method, needJetAnnotations, null, functionDescriptor,
new FunctionGenerationStrategy.Default(state, function));
}
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), state, v, method.getAsmMethod(), functionDescriptor, kind,
DefaultParameterValueLoader.DEFAULT);
}
public void generateMethod(
@NotNull JetDeclaration declaration,
@Nullable PsiElement origin,
@NotNull JvmMethodSignature jvmSignature,
boolean needJetAnnotations,
@Nullable String propertyTypeSignature,
@NotNull FunctionDescriptor functionDescriptor
) {
assert declaration instanceof JetDeclarationWithBody || declaration instanceof JetProperty || declaration instanceof JetParameter;
checkMustGenerateCode(functionDescriptor);
generateMethodHeaderAndBody(declaration, jvmSignature, needJetAnnotations, propertyTypeSignature, functionDescriptor);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL && !isAbstract(functionDescriptor, owner.getContextKind())) {
generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor);
}
}
private void generateMethodHeaderAndBody(
@NotNull JetDeclaration declaration,
@NotNull JvmMethodSignature jvmSignature,
boolean needJetAnnotations,
@Nullable String propertyTypeSignature,
@NotNull FunctionDescriptor functionDescriptor
@NotNull FunctionDescriptor functionDescriptor,
@NotNull FunctionGenerationStrategy strategy
) {
MethodContext context = owner.intoFunction(functionDescriptor);
Method asmMethod = jvmSignature.getAsmMethod();
MethodVisitor mv = v.newMethod(declaration,
MethodVisitor mv = v.newMethod(origin,
getMethodAsmFlags(functionDescriptor, context.getContextKind()),
asmMethod.getName(),
asmMethod.getDescriptor(),
@@ -140,14 +123,16 @@ public class FunctionCodegen extends GenerationStateAware {
return;
}
MethodInfo info = generateMethodBody(mv, declaration, functionDescriptor, context, asmMethod);
MethodInfo info = generateMethodBody(mv, functionDescriptor, context, jvmSignature, strategy);
info.localVariableNames.addAll(getParameterNamesAsStrings(functionDescriptor));
Type thisType = getThisTypeForFunction(functionDescriptor, context);
generateLocalVariableTable(typeMapper, mv, functionDescriptor, thisType, info);
endVisit(mv, null, declaration);
endVisit(mv, null, origin);
generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor);
}
@Nullable
@@ -167,10 +152,10 @@ public class FunctionCodegen extends GenerationStateAware {
@NotNull
private MethodInfo generateMethodBody(
@NotNull MethodVisitor mv,
@NotNull JetDeclaration funOrProperty,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull MethodContext context,
@NotNull Method asmMethod
@NotNull JvmMethodSignature signature,
@NotNull FunctionGenerationStrategy strategy
) {
Collection<String> localVariableNames = new ArrayList<String>();
Map<Name, Label> labelsForSharedVars = new HashMap<Name, Label>();
@@ -182,7 +167,7 @@ public class FunctionCodegen extends GenerationStateAware {
OwnerKind kind = context.getContextKind();
if (kind instanceof OwnerKind.StaticDelegateKind) {
generateStaticDelegateMethodBody(mv, asmMethod, (OwnerKind.StaticDelegateKind) kind);
generateStaticDelegateMethodBody(mv, signature.getAsmMethod(), (OwnerKind.StaticDelegateKind) kind);
}
else {
FrameMap frameMap = context.prepareFrame(typeMapper);
@@ -195,23 +180,7 @@ public class FunctionCodegen extends GenerationStateAware {
genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
boolean hasBodyExpression = hasBodyExpression(funOrProperty);
if (hasBodyExpression) {
JetDeclarationWithBody fun = (JetDeclarationWithBody) funOrProperty;
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, asmMethod.getReturnType(), context, state);
codegen.returnExpression(fun.getBodyExpression());
localVariableNames.addAll(codegen.getLocalVariableNamesForExpression());
} else {
///generate default accessor
assert functionDescriptor instanceof PropertyAccessorDescriptor;
PropertyCodegen.generateDefaultAccessor(
(PropertyAccessorDescriptor) functionDescriptor,
new InstructionAdapter(mv),
kind,
typeMapper,
context);
}
strategy.generateBody(mv, signature, context, localVariableNames, frameMap);
}
Label methodEnd = new Label();
@@ -220,12 +189,6 @@ public class FunctionCodegen extends GenerationStateAware {
return new MethodInfo(methodBegin, methodEnd, localVariableNames, labelsForSharedVars);
}
private static boolean hasBodyExpression(JetDeclaration funOrProperty) {
return (funOrProperty instanceof JetDeclarationWithBody
&& ((JetDeclarationWithBody) funOrProperty).getBodyExpression() != null);
}
public static class MethodInfo {
public final Label beginLabel;
public final Label endLabel;
@@ -398,7 +361,9 @@ public class FunctionCodegen extends GenerationStateAware {
kotlinFlags |= DescriptorKindUtils.kindToFlags(functionDescriptor.getKind());
//noinspection ConstantConditions
aw.writeFlags(kotlinFlags);
aw.writeTypeParameters(jvmSignature.getKotlinTypeParameter());
if (jvmSignature.getKotlinTypeParameter() != null) {
aw.writeTypeParameters(jvmSignature.getKotlinTypeParameter());
}
aw.writeReturnType(jvmSignature.getKotlinReturnType());
aw.visitEnd();
}
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2013 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.asm4.MethodVisitor;
import org.jetbrains.jet.codegen.context.MethodContext;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
import java.util.Collection;
public abstract class FunctionGenerationStrategy {
public abstract void generateBody(
@NotNull MethodVisitor mv,
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context,
@NotNull Collection<String> localVariableNames,
@NotNull FrameMap frameMap
);
public static class Default extends FunctionGenerationStrategy {
private final GenerationState state;
private final JetDeclarationWithBody declaration;
public Default(@NotNull GenerationState state, @NotNull JetDeclarationWithBody declaration) {
this.state = state;
this.declaration = declaration;
}
@Override
public void generateBody(
@NotNull MethodVisitor mv,
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context,
@NotNull Collection<String> localVariableNames,
@NotNull FrameMap frameMap
) {
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getAsmMethod().getReturnType(), context, state);
codegen.returnExpression(declaration.getBodyExpression());
localVariableNames.addAll(codegen.getLocalVariableNamesForExpression());
}
}
}
@@ -24,6 +24,8 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.MethodContext;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature;
import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
import org.jetbrains.jet.codegen.state.GenerationStateAware;
@@ -39,6 +41,8 @@ import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.Collection;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.getDeprecatedAccessFlag;
import static org.jetbrains.jet.codegen.CodegenUtil.*;
@@ -128,11 +132,16 @@ public class PropertyCodegen extends GenerationStateAware {
getterDescriptor = getterDescriptor != null ? getterDescriptor : DescriptorResolver.createDefaultGetter(propertyDescriptor);
if (kind != OwnerKind.TRAIT_IMPL || !defaultGetter) {
FunctionGenerationStrategy strategy =
defaultGetter
? new DefaultPropertyAccessorStrategy(getterDescriptor)
: new FunctionGenerationStrategy.Default(state, getter);
functionCodegen.generateMethod(getter != null ? getter : p,
signature.getJvmMethodSignature(),
true,
signature.getPropertyTypeKotlinSignature(),
getterDescriptor);
getterDescriptor,
strategy);
}
//}
}
@@ -147,22 +156,47 @@ public class PropertyCodegen extends GenerationStateAware {
setterDescriptor = setterDescriptor != null ? setterDescriptor : DescriptorResolver.createDefaultSetter(propertyDescriptor);
if (kind != OwnerKind.TRAIT_IMPL || !defaultSetter) {
FunctionGenerationStrategy strategy =
defaultSetter
? new DefaultPropertyAccessorStrategy(setterDescriptor)
: new FunctionGenerationStrategy.Default(state, setter);
functionCodegen.generateMethod(setter != null ? setter : p,
signature.getJvmMethodSignature(),
true,
signature.getPropertyTypeKotlinSignature(),
setterDescriptor);
setterDescriptor,
strategy);
}
}
}
public static void generateDefaultAccessor(
private class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy {
private final PropertyAccessorDescriptor descriptor;
public DefaultPropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor descriptor) {
this.descriptor = descriptor;
}
@Override
public void generateBody(
@NotNull MethodVisitor mv,
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context,
@NotNull Collection<String> localVariableNames,
@NotNull FrameMap frameMap
) {
generateDefaultAccessor(descriptor, new InstructionAdapter(mv), typeMapper, context);
}
}
private static void generateDefaultAccessor(
@NotNull PropertyAccessorDescriptor accessorDescriptor,
@NotNull InstructionAdapter iv,
@NotNull OwnerKind kind,
@NotNull JetTypeMapper typeMapper,
@NotNull CodegenContext context) {
@NotNull CodegenContext context
) {
OwnerKind kind = context.getContextKind();
PropertyDescriptor propertyDescriptor = accessorDescriptor.getCorrespondingProperty();
Type type = typeMapper.mapType(propertyDescriptor);