ScriptCodegen refactoring: unsingleton

This commit is contained in:
Mikhael Bogdanov
2013-06-28 16:31:43 +04:00
parent 08a90ba7d4
commit d4b84a8809
21 changed files with 286 additions and 219 deletions
@@ -83,7 +83,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
}
private void generateClassBody() {
FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state);
FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state, this);
PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, this);
if (kind != OwnerKind.TRAIT_IMPL) {
@@ -184,7 +184,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
clInit.initialize(null, null, Collections.<TypeParameterDescriptor>emptyList(),
Collections.<ValueParameterDescriptor>emptyList(), null, null, Visibilities.PRIVATE, false);
clInitCodegen = new ExpressionCodegen(method, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInit), state);
clInitCodegen = new ExpressionCodegen(method, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInit), state, this);
}
return clInitCodegen;
}
@@ -51,7 +51,7 @@ import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.isConst;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
public class ClosureCodegen extends GenerationStateAware {
public class ClosureCodegen extends ParentCodegenAwareImpl {
private final PsiElement fun;
private final FunctionDescriptor funDescriptor;
private final ClassDescriptor samInterface;
@@ -71,9 +71,10 @@ public class ClosureCodegen extends GenerationStateAware {
@NotNull Type closureSuperClass,
@NotNull CodegenContext context,
@NotNull LocalLookup localLookup,
@NotNull FunctionGenerationStrategy strategy
@NotNull FunctionGenerationStrategy strategy,
@Nullable MemberCodegen parentCodegen
) {
super(state);
super(state, parentCodegen);
this.fun = fun;
this.funDescriptor = funDescriptor;
@@ -89,7 +90,6 @@ public class ClosureCodegen extends GenerationStateAware {
this.asmType = asmTypeForAnonymousClass(bindingContext, funDescriptor);
}
public void gen() {
ClassBuilder cv = state.getFactory().newVisitor(asmType, fun.getContainingFile());
@@ -120,7 +120,7 @@ public class ClosureCodegen extends GenerationStateAware {
JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(interfaceFunction.getName(), funDescriptor);
FunctionCodegen fc = new FunctionCodegen(context, cv, state);
FunctionCodegen fc = new FunctionCodegen(context, cv, state, getParentCodegen());
fc.generateMethod(fun, jvmMethodSignature, funDescriptor, strategy);
this.constructor = generateConstructor(cv);
@@ -131,9 +131,11 @@ public class ClosureCodegen extends GenerationStateAware {
genClosureFields(closure, cv, typeMapper);
FunctionCodegen.generateDefaultIfNeeded(context.intoFunction(funDescriptor), state, cv,
typeMapper.mapSignature(Name.identifier("invoke"), funDescriptor), funDescriptor,
context.getContextKind(), DefaultParameterValueLoader.DEFAULT);
fc.generateDefaultIfNeeded(context.intoFunction(funDescriptor),
typeMapper.mapSignature(Name.identifier("invoke"), funDescriptor),
funDescriptor,
context.getContextKind(),
DefaultParameterValueLoader.DEFAULT);
cv.done();
}
@@ -78,7 +78,7 @@ import static org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind.TH
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implements LocalLookup {
public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implements LocalLookup, ParentCodegenAware {
private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException";
private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException";
@@ -101,6 +101,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>();
private final Collection<String> localVariableNames = new HashSet<String>();
@Nullable
private final MemberCodegen parentCodegen;
/*
* When we create a temporary variable to hold some value not to compute it many times
* we put it into this map to emit access to that variable instead of evaluating the whole expression
@@ -161,9 +164,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@NotNull FrameMap myMap,
@NotNull Type returnType,
@NotNull MethodContext context,
@NotNull GenerationState state
@NotNull GenerationState state,
@Nullable MemberCodegen parentCodegen
) {
this.myFrameMap = myMap;
this.parentCodegen = parentCodegen;
this.typeMapper = state.getTypeMapper();
this.returnType = returnType;
this.state = state;
@@ -219,6 +224,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return localVariableNames;
}
@Nullable
@Override
public MemberCodegen getParentCodegen() {
return parentCodegen;
}
public StackValue genQualified(StackValue receiver, JetElement selector) {
return genQualified(receiver, selector, this);
}
@@ -1311,7 +1322,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
Type closureSuperClass = samInterfaceClass == null ? getFunctionImplType(descriptor) : OBJECT_TYPE;
ClosureCodegen closureCodegen = new ClosureCodegen(state, declaration, descriptor, samInterfaceClass, closureSuperClass, context,
this, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration));
this, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), parentCodegen);
closureCodegen.gen();
@@ -2218,7 +2229,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
else {
Type classType = asmTypeForScriptDescriptor(bindingContext, receiver.getDeclarationDescriptor());
String fieldName = state.getScriptCodegen().getScriptFieldName(receiver.getDeclarationDescriptor());
String fieldName = getParentScriptCodegen().getScriptFieldName(receiver.getDeclarationDescriptor());
result.put(currentScriptType, v);
StackValue.field(classType, currentScriptType, fieldName, false).put(classType, v);
}
@@ -2434,14 +2445,15 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Override
public ExpressionCodegen initializeExpressionCodegen(
JvmMethodSignature signature, MethodContext context, MethodVisitor mv,
Type returnType
Type returnType,
MemberCodegen parentCodegen
) {
FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
JetType returnJetType = referencedFunction.getReturnType();
assert returnJetType != null : "Return type can't be null: " + referencedFunction;
return super.initializeExpressionCodegen(signature, context,
mv, typeMapper.mapReturnType(returnJetType));
mv, typeMapper.mapReturnType(returnJetType), parentCodegen);
}
@Override
@@ -2564,8 +2576,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
return new ExpressionReceiver(receiverExpression, receiver.getType());
}
}
);
},
getParentCodegen());
closureCodegen.gen();
@@ -3809,4 +3821,16 @@ The "returned" value of try expression with no finally is either the last expres
public String toString() {
return context.getContextDescriptor().toString();
}
@NotNull
private ScriptCodegen getParentScriptCodegen() {
MemberCodegen codegen = parentCodegen;
while (codegen != null) {
if (codegen instanceof ScriptCodegen) {
return (ScriptCodegen) codegen;
}
codegen = codegen.getParentCodegen();
}
throw new IllegalStateException("Script codegen should be present in codegen tree");
}
}
@@ -57,12 +57,13 @@ import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isFunctionLiteral;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
import static org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils.fqNameByClass;
public class FunctionCodegen extends GenerationStateAware {
public class FunctionCodegen extends ParentCodegenAwareImpl {
private final CodegenContext owner;
private final ClassBuilder v;
public FunctionCodegen(CodegenContext owner, ClassBuilder v, GenerationState state) {
super(state);
public FunctionCodegen(@NotNull CodegenContext owner, @NotNull ClassBuilder v, @NotNull GenerationState state, MemberCodegen parentCodegen) {
super(state, parentCodegen);
this.owner = owner;
this.v = v;
}
@@ -80,7 +81,7 @@ public class FunctionCodegen extends GenerationStateAware {
new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function));
}
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), state, v, method, functionDescriptor, kind,
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), method, functionDescriptor, kind,
DefaultParameterValueLoader.DEFAULT);
}
@@ -267,7 +268,7 @@ public class FunctionCodegen extends GenerationStateAware {
genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
}
strategy.generateBody(mv, signature, context);
strategy.generateBody(mv, signature, context, getParentCodegen());
localVariableNames.addAll(strategy.getLocalVariableNames());
}
@@ -518,10 +519,8 @@ public class FunctionCodegen extends GenerationStateAware {
}
}
static void generateDefaultIfNeeded(
void generateDefaultIfNeeded(
@NotNull MethodContext owner,
@NotNull GenerationState state,
@NotNull ClassBuilder v,
@NotNull JvmMethodSignature signature,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull OwnerKind kind,
@@ -565,17 +564,17 @@ public class FunctionCodegen extends GenerationStateAware {
descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
}
MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
descriptor, null, null);
isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
descriptor, null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
generateDefaultImpl(owner, state, signature, functionDescriptor, isStatic, mv, loadStrategy);
generateDefaultImpl(owner, signature, functionDescriptor, isStatic, mv, loadStrategy);
}
}
private static void generateDefaultImpl(
private void generateDefaultImpl(
@NotNull MethodContext methodContext,
@NotNull GenerationState state,
@NotNull JvmMethodSignature signature,
@NotNull FunctionDescriptor functionDescriptor,
boolean aStatic,
@@ -591,7 +590,7 @@ public class FunctionCodegen extends GenerationStateAware {
}
Method jvmSignature = signature.getAsmMethod();
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), methodContext, state);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), methodContext, state, getParentCodegen());
Type[] argTypes = jvmSignature.getArgumentTypes();
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
@@ -17,6 +17,7 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.context.MethodContext;
@@ -38,7 +39,8 @@ public abstract class FunctionGenerationStrategy {
public abstract void generateBody(
@NotNull MethodVisitor mv,
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context
@NotNull MethodContext context,
@Nullable MemberCodegen parentCodegen
);
protected void addLocalVariableName(@NotNull String name) {
@@ -97,9 +99,10 @@ public abstract class FunctionGenerationStrategy {
public void generateBody(
@NotNull MethodVisitor mv,
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context
@NotNull MethodContext context,
@Nullable MemberCodegen parentCodegen
) {
ExpressionCodegen codegen = initializeExpressionCodegen(signature, context, mv, signature.getAsmMethod().getReturnType());
ExpressionCodegen codegen = initializeExpressionCodegen(signature, context, mv, signature.getAsmMethod().getReturnType(), parentCodegen);
doGenerateBody(codegen, signature);
generateLocalVarNames(codegen);
}
@@ -111,9 +114,10 @@ public abstract class FunctionGenerationStrategy {
JvmMethodSignature signature,
MethodContext context,
MethodVisitor mv,
Type returnType
Type returnType,
MemberCodegen parentCodegen
) {
return new ExpressionCodegen(mv, getFrameMap(state.getTypeMapper(), context), returnType, context, state);
return new ExpressionCodegen(mv, getFrameMap(state.getTypeMapper(), context), returnType, context, state, parentCodegen);
}
public void generateLocalVarNames(@NotNull ExpressionCodegen codegen) {
@@ -98,7 +98,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
) {
super(aClass, context, v, state, parentCodegen);
this.classAsmType = typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL);
this.functionCodegen = new FunctionCodegen(context, v, state);
this.functionCodegen = new FunctionCodegen(context, v, state, this);
this.propertyCodegen = new PropertyCodegen(context, v, this.functionCodegen, this);
}
@@ -819,13 +819,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
JvmMethodSignature signature = typeMapper.mapSignature(function);
FunctionCodegen fc = new FunctionCodegen(context, v, state);
fc.generateMethod(myClass, signature, function, new FunctionGenerationStrategy() {
functionCodegen.generateMethod(myClass, signature, function, new FunctionGenerationStrategy() {
@Override
public void generateBody(
@NotNull MethodVisitor mv,
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context
@NotNull MethodContext context,
@Nullable MemberCodegen parentCodegen
) {
InstructionAdapter iv = new InstructionAdapter(mv);
if (!componentType.equals(Type.VOID_TYPE)) {
@@ -843,13 +843,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
final Type thisDescriptorType = typeMapper.mapType(descriptor.getDefaultType());
FunctionCodegen fc = new FunctionCodegen(context, v, state);
fc.generateMethod(myClass, methodSignature, function, new FunctionGenerationStrategy() {
functionCodegen.generateMethod(myClass, methodSignature, function, new FunctionGenerationStrategy() {
@Override
public void generateBody(
@NotNull MethodVisitor mv,
@NotNull JvmMethodSignature signature,
@NotNull MethodContext context
@NotNull MethodContext context,
@Nullable MemberCodegen parentCodegen
) {
InstructionAdapter iv = new InstructionAdapter(mv);
@@ -884,7 +884,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
});
MethodContext functionContext = context.intoFunction(function);
FunctionCodegen.generateDefaultIfNeeded(functionContext, state, v, methodSignature, function, OwnerKind.IMPLEMENTATION,
functionCodegen.generateDefaultIfNeeded(functionContext, methodSignature, function, OwnerKind.IMPLEMENTATION,
new DefaultParameterValueLoader() {
@Override
public void putValueOnStack(
@@ -904,7 +905,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
.put(propertyType, codegen.v);
}
});
}
}
private void generateEnumMethodsAndConstInitializers() {
if (!myEnumConstants.isEmpty()) {
@@ -1171,7 +1173,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
);
FunctionCodegen.generateDefaultIfNeeded(constructorContext, state, v, constructorSignature, constructorDescriptor,
functionCodegen.generateDefaultIfNeeded(constructorContext, constructorSignature, constructorDescriptor,
OwnerKind.IMPLEMENTATION, DefaultParameterValueLoader.DEFAULT);
CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, closure);
@@ -1483,7 +1485,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
mv.visitCode();
FrameMap frameMap = context.prepareFrame(typeMapper);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, returnType, context.intoFunction(inheritedFun), state);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, returnType, context.intoFunction(inheritedFun), state, this);
codegen.generateThisOrOuter(descriptor, false); // ??? wouldn't it be addClosureToConstructorParameters good idea to put it?
Type[] argTypes = methodToGenerate.getArgumentTypes();
@@ -48,8 +48,6 @@ public class KotlinCodegenFacade {
}
}
state.getScriptCodegen().registerEarlierScripts(Collections.<Pair<ScriptDescriptor, Type>>emptyList());
state.beforeCompile();
MultiMap<FqName, JetFile> namespaceGrouping = new MultiMap<FqName, JetFile>();
@@ -23,26 +23,16 @@ import org.jetbrains.jet.codegen.context.ClassContext;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.FieldOwnerContext;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.GenerationStateAware;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.ErrorUtils;
public class MemberCodegen extends GenerationStateAware {
@Nullable
private MemberCodegen parentCodegen;
public class MemberCodegen extends ParentCodegenAwareImpl {
public MemberCodegen(@NotNull GenerationState state, @Nullable MemberCodegen parentCodegen) {
super(state);
this.parentCodegen = parentCodegen;
}
@Nullable
public MemberCodegen getParentCodegen() {
return parentCodegen;
super(state, parentCodegen);
}
public void genFunctionOrProperty(
@@ -50,7 +40,7 @@ public class MemberCodegen extends GenerationStateAware {
@NotNull JetTypeParameterListOwner functionOrProperty,
@NotNull ClassBuilder classBuilder
) {
FunctionCodegen functionCodegen = new FunctionCodegen(context, classBuilder, state);
FunctionCodegen functionCodegen = new FunctionCodegen(context, classBuilder, state, this);
if (functionOrProperty instanceof JetNamedFunction) {
try {
functionCodegen.gen((JetNamedFunction) functionOrProperty);
@@ -102,7 +92,7 @@ public class MemberCodegen extends GenerationStateAware {
if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
ClassBuilder traitBuilder = state.getFactory().forTraitImplementation(descriptor, state, aClass.getContainingFile());
new TraitImplBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state)
new TraitImplBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state, this)
.generate();
traitBuilder.done();
}
@@ -178,7 +178,7 @@ public class NamespaceCodegen extends MemberCodegen {
}
}
else if (declaration instanceof JetScript) {
state.getScriptCodegen().generate((JetScript) declaration);
ScriptCodegen.createScriptCodegen((JetScript) declaration, state, CodegenContext.STATIC.intoNamespace(descriptor)).generate();
}
}
@@ -280,7 +280,7 @@ public class NamespaceCodegen extends MemberCodegen {
clInit.initialize(null, null, Collections.<TypeParameterDescriptor>emptyList(),
Collections.<ValueParameterDescriptor>emptyList(), null, null, Visibilities.PRIVATE, false);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context.intoFunction(clInit), state);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context.intoFunction(clInit), state, this);
for (JetDeclaration declaration : properties) {
ImplementationBodyCodegen.
@@ -0,0 +1,25 @@
/*
* 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.Nullable;
public interface ParentCodegenAware {
@Nullable
MemberCodegen getParentCodegen();
}
@@ -0,0 +1,38 @@
/*
* 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.annotations.Nullable;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.GenerationStateAware;
public class ParentCodegenAwareImpl extends GenerationStateAware implements ParentCodegenAware {
@Nullable private final MemberCodegen parentCodegen;
public ParentCodegenAwareImpl(@NotNull GenerationState state, @Nullable MemberCodegen parentCodegen) {
super(state);
this.parentCodegen = parentCodegen;
}
@Nullable
@Override
public MemberCodegen getParentCodegen() {
return parentCodegen;
}
}
@@ -43,7 +43,7 @@ public class SamWrapperClasses {
new Factory<Type>() {
@Override
public Type create() {
return new SamWrapperCodegen(state, samInterface).genWrapper(file);
return new SamWrapperCodegen(state, samInterface, null).genWrapper(file);
}
});
}
@@ -17,6 +17,7 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
@@ -42,13 +43,17 @@ import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.NO_FLAG_PACKAGE_PRIVATE;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
public class SamWrapperCodegen extends GenerationStateAware {
public class SamWrapperCodegen extends ParentCodegenAwareImpl {
private static final String FUNCTION_FIELD_NAME = "function";
@NotNull private final ClassDescriptorFromJvmBytecode samInterface;
public SamWrapperCodegen(@NotNull GenerationState state, @NotNull ClassDescriptorFromJvmBytecode samInterface) {
super(state);
public SamWrapperCodegen(
@NotNull GenerationState state,
@NotNull ClassDescriptorFromJvmBytecode samInterface,
@Nullable MemberCodegen parentCodegen
) {
super(state, parentCodegen);
this.samInterface = samInterface;
}
@@ -121,7 +126,7 @@ public class SamWrapperCodegen extends GenerationStateAware {
) {
// using static context to avoid creating ClassDescriptor and everything else
FunctionCodegen codegen = new FunctionCodegen(CodegenContext.STATIC, cv, state);
FunctionCodegen codegen = new FunctionCodegen(CodegenContext.STATIC, cv, state, getParentCodegen());
FunctionDescriptor invokeFunction = functionJetType.getMemberScope()
.getFunctions(Name.identifier("invoke")).iterator().next().getOriginal();
@@ -16,13 +16,11 @@
package org.jetbrains.jet.codegen;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.FieldOwnerContext;
import org.jetbrains.jet.codegen.context.MethodContext;
@@ -35,7 +33,6 @@ import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import javax.inject.Inject;
import java.util.Collections;
import java.util.List;
@@ -45,35 +42,50 @@ import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
public class ScriptCodegen extends MemberCodegen {
@NotNull
private ClassFileFactory classFileFactory;
private List<ScriptDescriptor> earlierScripts;
private Method scriptConstructorMethod;
public ScriptCodegen(@NotNull GenerationState state) {
super(state, null);
}
@Inject
public void setClassFileFactory(@NotNull ClassFileFactory classFileFactory) {
this.classFileFactory = classFileFactory;
}
public void generate(JetScript scriptDeclaration) {
ScriptDescriptor scriptDescriptor = state.getBindingContext().get(BindingContext.SCRIPT, scriptDeclaration);
public static ScriptCodegen createScriptCodegen(
@NotNull JetScript declaration,
@NotNull GenerationState state,
@NotNull CodegenContext parentContext
) {
ScriptDescriptor scriptDescriptor = state.getBindingContext().get(BindingContext.SCRIPT, declaration);
assert scriptDescriptor != null;
ClassDescriptor classDescriptorForScript = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, scriptDescriptor);
assert classDescriptorForScript != null;
ScriptContext context = (ScriptContext) CodegenContext.STATIC.intoScript(scriptDescriptor, classDescriptorForScript);
ScriptContext scriptContext = parentContext.intoScript(scriptDescriptor, classDescriptorForScript);
return new ScriptCodegen(declaration, state, scriptContext, state.getEarlierScriptsForReplInterpreter());
}
@NotNull
private JetScript scriptDeclaration;
@NotNull
private final ScriptContext context;
@NotNull
private List<ScriptDescriptor> earlierScripts;
private ScriptCodegen(
@NotNull JetScript scriptDeclaration,
@NotNull GenerationState state,
@NotNull ScriptContext context,
@Nullable List<ScriptDescriptor> earlierScripts
) {
super(state, null);
this.scriptDeclaration = scriptDeclaration;
this.context = context;
this.earlierScripts = earlierScripts == null ? Collections.<ScriptDescriptor>emptyList() : earlierScripts;
}
public void generate() {
ScriptDescriptor scriptDescriptor = context.getScriptDescriptor();
ClassDescriptor classDescriptorForScript = context.getContextDescriptor();
Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript);
assert classType != null;
ClassBuilder classBuilder = classFileFactory.newVisitor(classType, scriptDeclaration.getContainingFile());
ClassBuilder classBuilder = state.getFactory().newVisitor(classType, scriptDeclaration.getContainingFile());
classBuilder.defineClass(scriptDeclaration,
V1_6,
ACC_PUBLIC,
@@ -82,22 +94,19 @@ public class ScriptCodegen extends MemberCodegen {
"java/lang/Object",
new String[0]);
genMembers(scriptDeclaration, context, classBuilder);
genMembers(context, classBuilder);
genFieldsForParameters(scriptDescriptor, classBuilder);
genConstructor(scriptDeclaration, scriptDescriptor, classDescriptorForScript, classBuilder,
context.intoFunction(scriptDescriptor.getScriptCodeDescriptor()),
earlierScripts);
genConstructor(scriptDescriptor, classDescriptorForScript, classBuilder,
context.intoFunction(scriptDescriptor.getScriptCodeDescriptor()));
classBuilder.done();
}
private void genConstructor(
@NotNull JetScript scriptDeclaration,
@NotNull ScriptDescriptor scriptDescriptor,
@NotNull ClassDescriptor classDescriptorForScript,
@NotNull ClassBuilder classBuilder,
@NotNull MethodContext context,
@NotNull List<ScriptDescriptor> importedScripts
@NotNull MethodContext context
) {
Type blockType = typeMapper.mapType(scriptDescriptor.getReturnType());
@@ -105,9 +114,7 @@ public class ScriptCodegen extends MemberCodegen {
classBuilder.newField(null, ACC_PUBLIC | ACC_FINAL, ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME,
blockType.getDescriptor(), null, null);
JvmMethodSignature jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, importedScripts);
state.getScriptCodegen().setScriptConstructorMethod(jvmSignature.getAsmMethod());
JvmMethodSignature jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, earlierScripts);
MethodVisitor mv = classBuilder.newMethod(
scriptDeclaration, ACC_PUBLIC, jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor(),
@@ -127,7 +134,7 @@ public class ScriptCodegen extends MemberCodegen {
FrameMap frameMap = context.prepareFrame(typeMapper);
for (ScriptDescriptor importedScript : importedScripts) {
for (ScriptDescriptor importedScript : earlierScripts) {
frameMap.enter(importedScript, OBJECT_TYPE);
}
@@ -140,14 +147,14 @@ public class ScriptCodegen extends MemberCodegen {
}
ImplementationBodyCodegen.generateInitializers(
new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state),
new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state, this),
scriptDeclaration.getDeclarations(),
bindingContext,
state);
int offset = 1;
for (ScriptDescriptor earlierScript : importedScripts) {
for (ScriptDescriptor earlierScript : earlierScripts) {
Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, earlierScript);
instructionAdapter.load(0, classType);
instructionAdapter.load(offset, earlierClassType);
@@ -164,7 +171,7 @@ public class ScriptCodegen extends MemberCodegen {
}
StackValue stackValue =
new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state).gen(scriptDeclaration.getBlockExpression());
new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state, this).gen(scriptDeclaration.getBlockExpression());
if (stackValue.type != Type.VOID_TYPE) {
stackValue.put(stackValue.type, instructionAdapter);
instructionAdapter.putfield(classType.getInternalName(), ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME,
@@ -190,29 +197,13 @@ public class ScriptCodegen extends MemberCodegen {
}
}
private void genMembers(@NotNull JetScript scriptDeclaration, @NotNull FieldOwnerContext context, @NotNull ClassBuilder classBuilder) {
private void genMembers(@NotNull FieldOwnerContext context, @NotNull ClassBuilder classBuilder) {
for (JetDeclaration decl : scriptDeclaration.getDeclarations()) {
genFunctionOrProperty(context, (JetTypeParameterListOwner) decl, classBuilder);
}
}
public void registerEarlierScripts(List<Pair<ScriptDescriptor, Type>> earlierScripts) {
for (Pair<ScriptDescriptor, Type> t : earlierScripts) {
ScriptDescriptor earlierDescriptor = t.first;
Type earlierClassName = t.second;
registerClassNameForScript(state.getBindingTrace(), earlierDescriptor, earlierClassName);
}
List<ScriptDescriptor> earlierScriptDescriptors = Lists.newArrayList();
for (Pair<ScriptDescriptor, Type> t : earlierScripts) {
ScriptDescriptor earlierDescriptor = t.first;
earlierScriptDescriptors.add(earlierDescriptor);
}
this.earlierScripts = earlierScriptDescriptors;
}
protected int getScriptIndex(@NotNull ScriptDescriptor scriptDescriptor) {
private int getScriptIndex(@NotNull ScriptDescriptor scriptDescriptor) {
int index = earlierScripts.indexOf(scriptDescriptor);
if (index < 0) {
throw new IllegalStateException("Unregistered script: " + scriptDescriptor);
@@ -223,29 +214,4 @@ public class ScriptCodegen extends MemberCodegen {
public String getScriptFieldName(@NotNull ScriptDescriptor scriptDescriptor) {
return "script$" + getScriptIndex(scriptDescriptor);
}
public void setScriptConstructorMethod(Method scriptConstructorMethod) {
this.scriptConstructorMethod = scriptConstructorMethod;
}
public Method getScriptConstructorMethod() {
return scriptConstructorMethod;
}
public void compileScript(
@NotNull JetScript script,
@NotNull Type classType,
@NotNull List<Pair<ScriptDescriptor, Type>> earlierScripts,
@NotNull CompilationErrorHandler errorHandler
) {
registerEarlierScripts(earlierScripts);
registerClassNameForScript(state.getBindingTrace(), script, classType);
state.beforeCompile();
KotlinCodegenFacade.generateNamespace(
state,
JetPsiUtil.getFQName((JetFile) script.getContainingFile()),
Collections.singleton((JetFile) script.getContainingFile()),
errorHandler);
}
}
@@ -16,6 +16,8 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.context.ClassContext;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
@@ -24,8 +26,15 @@ import org.jetbrains.jet.lang.psi.JetClassOrObject;
import static org.jetbrains.asm4.Opcodes.*;
public class TraitImplBodyCodegen extends ClassBodyCodegen {
public TraitImplBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassBuilder v, GenerationState state) {
super(aClass, context, v, state, null);
public TraitImplBodyCodegen(
@NotNull JetClassOrObject aClass,
@NotNull ClassContext context,
@NotNull ClassBuilder v,
@NotNull GenerationState state,
@Nullable MemberCodegen parentCodegen
) {
super(aClass, context, v, state, parentCodegen);
}
@Override
@@ -40,6 +49,7 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen {
v.visitSource(myClass.getContainingFile().getName(), null);
}
@NotNull
private String jvmName() {
return typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.TRAIT_IMPL).getInternalName();
}
@@ -187,7 +187,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
}
@NotNull
public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) {
public ScriptContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) {
return new ScriptContext(script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
}
@@ -18,10 +18,12 @@ package org.jetbrains.jet.codegen.state;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.jet.di.InjectorForJvmCodegen;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
@@ -47,9 +49,6 @@ public class GenerationState {
@NotNull
private final ClassFileFactory classFileFactory;
@NotNull
private final ScriptCodegen scriptCodegen;
@NotNull
private final Project project;
@@ -71,6 +70,9 @@ public class GenerationState {
private final boolean generateDeclaredClasses;
@Nullable
private List<ScriptDescriptor> earlierScriptsForReplInterpreter;
public GenerationState(Project project, ClassBuilderFactory builderFactory, BindingContext bindingContext, List<JetFile> files) {
this(project, builderFactory, Progress.DEAF, bindingContext, files, true, false, true);
}
@@ -97,7 +99,6 @@ public class GenerationState {
InjectorForJvmCodegen injector = new InjectorForJvmCodegen(typeMapper, this, builderFactory, project);
this.scriptCodegen = injector.getScriptCodegen();
this.intrinsics = injector.getIntrinsics();
this.classFileFactory = injector.getClassFileFactory();
@@ -131,11 +132,6 @@ public class GenerationState {
return files;
}
@NotNull
public ScriptCodegen getScriptCodegen() {
return scriptCodegen;
}
@NotNull
public BindingTrace getBindingTrace() {
return bindingTrace;
@@ -189,4 +185,13 @@ public class GenerationState {
public void destroy() {
}
@Nullable
public List<ScriptDescriptor> getEarlierScriptsForReplInterpreter() {
return earlierScriptsForReplInterpreter;
}
public void setEarlierScriptsForReplInterpreter(@Nullable List<ScriptDescriptor> earlierScriptsForReplInterpreter) {
this.earlierScriptsForReplInterpreter = earlierScriptsForReplInterpreter;
}
}
@@ -23,7 +23,6 @@ import com.intellij.openapi.project.Project;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.codegen.ClassBuilderMode;
import org.jetbrains.jet.codegen.ScriptCodegen;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.annotations.NotNull;
@@ -39,7 +38,6 @@ public class InjectorForJvmCodegen {
private final BindingTrace bindingTrace;
private final BindingContext bindingContext;
private final ClassBuilderMode classBuilderMode;
private final ScriptCodegen scriptCodegen;
private final IntrinsicMethods intrinsics;
private final ClassFileFactory classFileFactory;
@@ -56,12 +54,9 @@ public class InjectorForJvmCodegen {
this.bindingTrace = jetTypeMapper.getBindingTrace();
this.bindingContext = bindingTrace.getBindingContext();
this.classBuilderMode = classBuilderFactory.getClassBuilderMode();
this.scriptCodegen = new ScriptCodegen(getGenerationState());
this.intrinsics = new IntrinsicMethods();
this.classFileFactory = new ClassFileFactory(getGenerationState());
this.scriptCodegen.setClassFileFactory(classFileFactory);
this.classFileFactory.setBuilderFactory(classBuilderFactory);
intrinsics.init();
@@ -84,10 +79,6 @@ public class InjectorForJvmCodegen {
return this.project;
}
public ScriptCodegen getScriptCodegen() {
return this.scriptCodegen;
}
public IntrinsicMethods getIntrinsics() {
return this.intrinsics;
}
@@ -38,6 +38,7 @@ import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys;
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
import org.jetbrains.jet.codegen.ClassBuilderFactories;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.KotlinCodegenFacade;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.config.CompilerConfiguration;
import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm;
@@ -46,6 +47,8 @@ import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.NamespaceLikeBuilderDummy;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.psi.JetScript;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
@@ -67,7 +70,9 @@ import java.net.URLClassLoader;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.asmTypeByFqNameWithoutInnerClasses;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.registerClassNameForScript;
public class ReplInterpreter {
@@ -232,8 +237,9 @@ public class ReplInterpreter {
BindingContext bindingContext = AnalyzeExhaust.success(trace.getBindingContext(), module).getBindingContext();
GenerationState generationState = new GenerationState(psiFile.getProject(), ClassBuilderFactories.BINARIES,
bindingContext, Collections.singletonList(psiFile));
generationState.getScriptCodegen().compileScript(psiFile.getScript(), scriptClassType, earlierScripts,
CompilationErrorHandler.THROW_EXCEPTION);
compileScript(psiFile.getScript(), scriptClassType, earlierScripts, generationState,
CompilationErrorHandler.THROW_EXCEPTION);
for (String file : generationState.getFactory().files()) {
classLoader.addClass(JvmClassName.byInternalName(file.replaceFirst("\\.class$", "")), generationState.getFactory().asBytes(file));
@@ -317,4 +323,41 @@ public class ReplInterpreter {
public void dumpClasses(@NotNull PrintWriter out) {
classLoader.dumpClasses(out);
}
private static void registerEarlierScripts(
@NotNull GenerationState state,
@NotNull List<Pair<ScriptDescriptor, Type>> earlierScripts
) {
for (Pair<ScriptDescriptor, Type> t : earlierScripts) {
ScriptDescriptor earlierDescriptor = t.first;
Type earlierClassType = t.second;
registerClassNameForScript(state.getBindingTrace(), earlierDescriptor, earlierClassType);
}
List<ScriptDescriptor> earlierScriptDescriptors = Lists.newArrayList();
for (Pair<ScriptDescriptor, Type> t : earlierScripts) {
ScriptDescriptor earlierDescriptor = t.first;
earlierScriptDescriptors.add(earlierDescriptor);
}
state.setEarlierScriptsForReplInterpreter(earlierScriptDescriptors);
}
public static void compileScript(
@NotNull JetScript script,
@NotNull Type classType,
@NotNull List<Pair<ScriptDescriptor, Type>> earlierScripts,
@NotNull GenerationState state,
@NotNull CompilationErrorHandler errorHandler
) {
registerEarlierScripts(state, earlierScripts);
registerClassNameForScript(state.getBindingTrace(), script, classType);
state.beforeCompile();
KotlinCodegenFacade.generateNamespace(
state,
JetPsiUtil.getFQName((JetFile) script.getContainingFile()),
Collections.singleton((JetFile) script.getContainingFile()),
errorHandler);
}
}
@@ -61,7 +61,7 @@ public class ScriptGenTest extends CodegenTestCase {
try {
Class<?> scriptClass = loader.loadClass(scriptClassName);
Constructor constructor = getConstructor(scriptClass, factory.getState().getScriptCodegen().getScriptConstructorMethod());
Constructor constructor = getConstructor(scriptClass);
scriptInstance = constructor.newInstance(myFiles.getScriptParameterValues().toArray());
assertFalse("expecting at least one expectation", myFiles.getExpectedValues().isEmpty());
@@ -92,43 +92,12 @@ public class ScriptGenTest extends CodegenTestCase {
}
}
protected Constructor getConstructor(@NotNull Class<?> clazz, org.jetbrains.asm4.commons.Method method) {
if (!method.getName().equals("<init>")) {
throw new IllegalArgumentException("not constructor: " + method);
}
Class[] classes = new Class[method.getArgumentTypes().length];
for (int i = 0; i < classes.length; ++i) {
classes[i] = loadClassFromType(method.getArgumentTypes()[i]);
}
try {
return clazz.getConstructor(classes);
}
catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@NotNull
private Class<?> loadClassFromType(@NotNull Type type) {
try {
switch (type.getSort()) {
case Type.OBJECT:
return Class.forName(type.getClassName());
case Type.INT:
return int.class;
case Type.LONG:
return long.class;
default:
// AFAIK there is no way to create array class from class
if (type.getDescriptor().equals("[Ljava/lang/String;")) {
return String[].class;
}
throw new IllegalStateException("not implemented: " + type.getDescriptor());
}
}
catch (Exception e) {
throw ExceptionUtils.rethrow(e);
protected Constructor getConstructor(@NotNull Class<?> clazz) {
Constructor [] constructors = clazz.getConstructors();
if (constructors == null || constructors.length != 1) {
throw new IllegalArgumentException("Script class should have one constructor: " + clazz);
}
return constructors[0];
}
public void testHelloWorld() {
@@ -17,10 +17,7 @@
package org.jetbrains.jet.generators.injectors;
import com.intellij.openapi.project.Project;
import org.jetbrains.jet.codegen.ClassBuilderFactory;
import org.jetbrains.jet.codegen.ClassBuilderMode;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.ScriptCodegen;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
@@ -233,7 +230,6 @@ public class GenerateInjectors {
new GivenExpression("bindingTrace.getBindingContext()"));
generator.addField(false, ClassBuilderMode.class, "classBuilderMode",
new GivenExpression("classBuilderFactory.getClassBuilderMode()"));
generator.addPublicField(ScriptCodegen.class);
generator.addField(true, IntrinsicMethods.class, "intrinsics", null);
generator.addPublicField(ClassFileFactory.class);