Script refactoring, backend: scripts are classes now, remove/refactor 'special code' dealing with scripts

This commit is contained in:
Pavel V. Talanov
2015-11-17 15:13:30 +03:00
parent d037068bba
commit 6563830584
17 changed files with 146 additions and 251 deletions
@@ -368,13 +368,6 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
iv.invokestatic(REFLECTION, "getOrCreateKotlinPackage",
Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE, getType(Class.class), getType(String.class)), false);
}
else if (container instanceof ScriptDescriptor) {
// TODO: correct container for scripts (KScript?)
StackValue value = generateClassLiteralReference(
state.getTypeMapper(), ((ScriptDescriptor) container).getClassDescriptor().getDefaultType()
);
value.put(K_CLASS_TYPE, iv);
}
else {
iv.aconst(null);
}
@@ -48,7 +48,6 @@ import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.ScriptCodeDescriptor;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
import org.jetbrains.kotlin.diagnostics.Errors;
@@ -311,9 +310,28 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
public void gen(KtElement expr, Type type) {
StackValue value = Type.VOID_TYPE.equals(type) ? genStatement(expr) : gen(expr);
// for repl store the result of the last line into special field
if (value.type != Type.VOID_TYPE && state.getShouldGenerateScriptResultValue()) {
ScriptContext context = getScriptContext();
if (expr == context.getLastStatement()) {
StackValue.Field resultValue = StackValue.field(context.getResultFieldInfo(), StackValue.LOCAL_0);
resultValue.store(value, v);
return;
}
}
value.put(type, v);
}
@NotNull
private ScriptContext getScriptContext() {
CodegenContext context = getContext();
while (!(context instanceof ScriptContext)) {
context = context.getParentContext();
}
return (ScriptContext) context;
}
public StackValue genLazy(KtElement expr, Type type) {
StackValue value = gen(expr);
return StackValue.coercion(value, type);
@@ -1968,21 +1986,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (localOrCaptured != null) {
return localOrCaptured;
}
DeclarationDescriptor container = descriptor.getContainingDeclaration();
if (descriptor instanceof ValueParameterDescriptor && container instanceof ScriptCodeDescriptor) {
ScriptCodeDescriptor scriptCodeDescriptor = (ScriptCodeDescriptor) container;
ScriptDescriptor scriptDescriptor = (ScriptDescriptor) scriptCodeDescriptor.getContainingDeclaration();
Type scriptClassType = asmTypeForScriptDescriptor(bindingContext, scriptDescriptor);
ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) descriptor;
ClassDescriptor scriptClass = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
//noinspection ConstantConditions
StackValue script = StackValue.thisOrOuter(this, scriptClass, false, false);
Type fieldType = typeMapper.mapType(valueParameterDescriptor);
return StackValue.field(fieldType, scriptClassType, valueParameterDescriptor.getName().getIdentifier(), false, script,
valueParameterDescriptor);
}
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
}
@@ -2496,14 +2499,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return StackValue.singleton(receiverDescriptor, typeMapper);
}
}
else if (receiverDescriptor instanceof ScriptDescriptor) {
return generateScriptReceiver
((ScriptDescriptor) receiverDescriptor);
}
else {
return StackValue.thisOrOuter(this, receiverDescriptor, isSuper,
receiverValue instanceof CastImplicitClassReceiver || isEnumEntry(receiverDescriptor));
}
}
else if (receiverValue instanceof ScriptReceiver) {
return generateScript((ScriptReceiver) receiverValue);
}
else if (receiverValue instanceof ExtensionReceiver) {
return generateReceiver(((ExtensionReceiver) receiverValue).getDeclarationDescriptor());
}
@@ -2520,7 +2524,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return context.generateReceiver(descriptor, state, false);
}
private StackValue generateScript(@NotNull ScriptReceiver receiver) {
@NotNull
private StackValue generateScriptReceiver(@NotNull ScriptDescriptor receiver) {
CodegenContext cur = context;
StackValue result = StackValue.LOCAL_0;
boolean inStartConstructorContext = cur instanceof ConstructorContext;
@@ -2532,17 +2537,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (cur instanceof ScriptContext) {
ScriptContext scriptContext = (ScriptContext) cur;
ScriptDescriptor receiverDeclarationDescriptor = receiver.getDeclarationDescriptor();
if (scriptContext.getScriptDescriptor() == receiverDeclarationDescriptor) {
if (scriptContext.getScriptDescriptor() == receiver) {
//TODO lazy
return result;
}
else {
Type currentScriptType = asmTypeForScriptDescriptor(bindingContext, scriptContext.getScriptDescriptor());
Type classType = asmTypeForScriptDescriptor(bindingContext, receiverDeclarationDescriptor);
String fieldName = scriptContext.getScriptFieldName(receiverDeclarationDescriptor);
return StackValue.field(classType, currentScriptType, fieldName, false, result, receiverDeclarationDescriptor);
}
Type currentScriptType = typeMapper.mapType(scriptContext.getScriptDescriptor());
Type classType = typeMapper.mapType(receiver);
String fieldName = scriptContext.getScriptFieldName(receiver);
return StackValue.field(classType, currentScriptType, fieldName, false, result, receiver);
}
result = cur.getOuterExpression(result, false);
@@ -2558,7 +2560,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
throw new UnsupportedOperationException();
}
@NotNull
public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
return generateThisOrOuter(calleeContainingClass, isSuper, false);
@@ -3321,19 +3322,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
Type varType = asmType(variableDescriptor.getType());
StackValue storeTo;
if (KtPsiUtil.isScriptDeclaration(variableDeclaration)) {
KtScript scriptPsi = KtPsiUtil.getScript(variableDeclaration);
assert scriptPsi != null;
Type scriptClassType = asmTypeForScriptPsi(bindingContext, scriptPsi);
storeTo = StackValue.field(varType, scriptClassType, variableDeclaration.getName(), false, StackValue.LOCAL_0, variableDescriptor);
}
else if (sharedVarType == null) {
storeTo = StackValue.local(index, varType);
}
else {
storeTo = StackValue.shared(index, varType);
}
StackValue storeTo = sharedVarType == null ? StackValue.local(index, varType) : StackValue.shared(index, varType);
storeTo.store(initializer, v);
}
@@ -24,40 +24,20 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtScript;
import org.jetbrains.kotlin.resolve.ScriptNameUtil;
import org.jetbrains.org.objectweb.asm.Type;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.registerClassNameForScript;
public class KotlinCodegenFacade {
public static void prepareForCompilation(@NotNull GenerationState state) {
for (KtFile file : state.getFiles()) {
if (file.isScript()) {
KtScript script = file.getScript();
assert script != null;
FqName name = ScriptNameUtil.classNameForScript(script);
Type type = AsmUtil.asmTypeByFqNameWithoutInnerClasses(name);
registerClassNameForScript(state.getBindingTrace(), script, type, state.getFileClassesProvider());
}
}
state.beforeCompile();
}
public static void compileCorrectFiles(
@NotNull GenerationState state,
@NotNull CompilationErrorHandler errorHandler
) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
prepareForCompilation(state);
state.beforeCompile();
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
@@ -273,13 +273,8 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
String outerClassInternalName = null;
if (containing instanceof ClassDescriptor) {
outerClassInternalName = typeMapper.mapClass((ClassDescriptor) containing).getInternalName();
} /* disabled cause of KT-7775
else if (containing instanceof ScriptDescriptor) {
outerClassInternalName = asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) containing).getInternalName();
}*/
}
String innerName = innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName();
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
}
@@ -320,10 +315,7 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
return FileClasses.getFileClassType(fileClassesProvider, element.getContainingKtFile());
}
}
/*disabled cause of KT-7775
else if (outermost instanceof ScriptContext) {
return asmTypeForScriptDescriptor(bindingContext, ((ScriptContext) outermost).getScriptDescriptor());
}*/
return null;
}
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.ScriptReceiver
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
@@ -52,15 +51,7 @@ public class PropertyReferenceCodegen(
) : MemberCodegen<KtElement>(state, parentCodegen, context, expression, classBuilder) {
private val asmType = typeMapper.mapClass(classDescriptor)
private val dispatchReceiverType =
when {
dispatchReceiver is ScriptReceiver -> {
// TODO: fix receiver for scripts, see ScriptReceiver#getType
dispatchReceiver.declarationDescriptor.classDescriptor.defaultType
}
dispatchReceiver.exists() -> dispatchReceiver.type
else -> null
}
private val dispatchReceiverType = if (dispatchReceiver.exists()) dispatchReceiver.type else null
private val extensionReceiverType = target.extensionReceiverParameter?.type
@@ -23,12 +23,11 @@ import org.jetbrains.kotlin.codegen.context.CodegenContext;
import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.context.ScriptContext;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
@@ -38,8 +37,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLASS_FOR_SCRIPT;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForScriptDescriptor;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
@@ -55,18 +52,16 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
ScriptDescriptor scriptDescriptor = bindingContext.get(BindingContext.SCRIPT, declaration);
assert scriptDescriptor != null;
ClassDescriptor classDescriptorForScript = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
assert classDescriptorForScript != null;
Type classType = state.getTypeMapper().mapType(scriptDescriptor);
Type classType = asmTypeForScriptDescriptor(bindingContext, scriptDescriptor);
ClassBuilder builder = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(declaration, classDescriptorForScript),
ClassBuilder builder = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(declaration, scriptDescriptor),
classType, declaration.getContainingFile());
List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter();
ScriptContext scriptContext = parentContext.intoScript(
scriptDescriptor,
earlierScripts == null ? Collections.<ScriptDescriptor>emptyList() : earlierScripts,
classDescriptorForScript
scriptDescriptor,
state.getTypeMapper()
);
return new ScriptCodegen(declaration, state, scriptContext, builder);
}
@@ -104,8 +99,8 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
protected void generateBody() {
genMembers();
genFieldsForParameters(scriptDescriptor, v);
genConstructor(scriptDescriptor, context.getContextDescriptor(), v,
context.intoFunction(scriptDescriptor.getScriptCodeDescriptor()));
genConstructor(scriptDescriptor, v,
context.intoFunction(scriptDescriptor.getUnsubstitutedPrimaryConstructor()));
}
@Override
@@ -115,22 +110,25 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
private void genConstructor(
@NotNull ScriptDescriptor scriptDescriptor,
@NotNull ClassDescriptor classDescriptorForScript,
@NotNull ClassBuilder classBuilder,
@NotNull MethodContext methodContext
) {
//noinspection ConstantConditions
Type blockType = typeMapper.mapType(scriptDescriptor.getScriptCodeDescriptor().getReturnType());
PropertyDescriptor scriptResultProperty = scriptDescriptor.getScriptResultProperty();
classBuilder.newField(JvmDeclarationOriginKt.OtherOrigin(scriptResultProperty),
ACC_PUBLIC | ACC_FINAL, scriptResultProperty.getName().asString(),
blockType.getDescriptor(), null, null);
JvmMethodSignature jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, context.getEarlierScripts());
if (state.getShouldGenerateScriptResultValue()) {
FieldInfo resultFieldInfo = context.getResultFieldInfo();
classBuilder.newField(
JvmDeclarationOrigin.NO_ORIGIN,
ACC_PUBLIC | ACC_FINAL,
resultFieldInfo.getFieldName(),
resultFieldInfo.getFieldType().getDescriptor(),
null,
null
);
}
MethodVisitor mv = classBuilder.newMethod(
JvmDeclarationOriginKt.OtherOrigin(scriptDeclaration, scriptDescriptor.getClassDescriptor().getUnsubstitutedPrimaryConstructor()),
JvmDeclarationOriginKt.OtherOrigin(scriptDeclaration, scriptDescriptor.getUnsubstitutedPrimaryConstructor()),
ACC_PUBLIC, jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor(),
null, null);
@@ -139,7 +137,7 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
InstructionAdapter iv = new InstructionAdapter(mv);
Type classType = typeMapper.mapType(classDescriptorForScript);
Type classType = typeMapper.mapType(scriptDescriptor);
iv.load(0, classType);
iv.invokespecial("java/lang/Object", "<init>", "()V", false);
@@ -156,22 +154,23 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
Type[] argTypes = jvmSignature.getAsmMethod().getArgumentTypes();
int add = 0;
for (int i = 0; i < scriptDescriptor.getScriptCodeDescriptor().getValueParameters().size(); i++) {
ValueParameterDescriptor parameter = scriptDescriptor.getScriptCodeDescriptor().getValueParameters().get(i);
List<ValueParameterDescriptor> valueParameters = scriptDescriptor.getUnsubstitutedPrimaryConstructor().getValueParameters();
for (int i = 0; i < valueParameters.size(); i++) {
ValueParameterDescriptor parameter = valueParameters.get(i);
frameMap.enter(parameter, argTypes[i + add]);
}
int offset = 1;
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, earlierScript);
Type earlierClassType = typeMapper.mapClass(earlierScript);
iv.load(0, classType);
iv.load(offset, earlierClassType);
offset += earlierClassType.getSize();
iv.putfield(classType.getInternalName(), context.getScriptFieldName(earlierScript), earlierClassType.getDescriptor());
}
for (ValueParameterDescriptor parameter : scriptDescriptor.getScriptCodeDescriptor().getValueParameters()) {
for (ValueParameterDescriptor parameter : valueParameters) {
Type parameterType = typeMapper.mapType(parameter.getType());
iv.load(0, classType);
iv.load(offset, parameterType);
@@ -188,16 +187,6 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
}
});
StackValue stackValue = codegen.gen(scriptDeclaration.getBlockExpression());
if (stackValue.type != Type.VOID_TYPE) {
StackValue.Field resultValue = StackValue
.field(blockType, classType, ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME, false, StackValue.LOCAL_0);
resultValue.store(stackValue, iv);
}
else {
stackValue.put(blockType, iv);
}
iv.areturn(Type.VOID_TYPE);
}
@@ -207,12 +196,12 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
private void genFieldsForParameters(@NotNull ScriptDescriptor script, @NotNull ClassBuilder classBuilder) {
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
Type earlierClassName = asmTypeForScriptDescriptor(bindingContext, earlierScript);
int access = ACC_PRIVATE | ACC_FINAL;
Type earlierClassName = typeMapper.mapType(earlierScript);
int access = ACC_PUBLIC | ACC_FINAL;
classBuilder.newField(NO_ORIGIN, access, context.getScriptFieldName(earlierScript), earlierClassName.getDescriptor(), null, null);
}
for (ValueParameterDescriptor parameter : script.getScriptCodeDescriptor().getValueParameters()) {
for (ValueParameterDescriptor parameter : script.getUnsubstitutedPrimaryConstructor().getValueParameters()) {
Type parameterType = typeMapper.mapType(parameter);
int access = ACC_PUBLIC | ACC_FINAL;
classBuilder.newField(JvmDeclarationOriginKt.OtherOrigin(parameter), access, parameter.getName().getIdentifier(), parameterType.getDescriptor(), null, null);
@@ -235,8 +235,8 @@ public abstract class StackValue {
}
@NotNull
private static Field field(@NotNull FieldInfo info) {
return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), true, none());
public static Field field(@NotNull FieldInfo info, @NotNull StackValue receiver) {
return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), info.isStatic(), receiver);
}
@NotNull
@@ -593,15 +593,15 @@ public abstract class StackValue {
@NotNull
public static Field singleton(@NotNull ClassDescriptor classDescriptor, @NotNull JetTypeMapper typeMapper) {
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper));
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper), none());
}
public static Field singletonViaInstance(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper, false));
return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper, false), none());
}
public static Field oldSingleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper, true));
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper, true), none());
}
public static StackValue operation(Type type, Function1<InstructionAdapter, Unit> lambda) {
@@ -158,24 +158,20 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
element.acceptChildren(this);
}
@Override
public void visitScript(@NotNull KtScript script) {
classStack.push(bindingContext.get(SCRIPT, script));
nameStack.push(AsmUtil.internalNameByFqNameWithoutInnerClasses(script.getFqName()));
script.acceptChildren(this);
nameStack.pop();
classStack.pop();
}
@Override
public void visitKtFile(@NotNull KtFile file) {
if (file.isScript()) {
// TODO: replace with visitScript override
//noinspection ConstantConditions
ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, bindingContext.get(SCRIPT, file.getScript()));
classStack.push(classDescriptor);
//noinspection ConstantConditions
nameStack.push(asmTypeForScriptPsi(bindingContext, file.getScript()).getInternalName());
}
else {
nameStack.push(AsmUtil.internalNameByFqNameWithoutInnerClasses(file.getPackageFqName()));
}
nameStack.push(AsmUtil.internalNameByFqNameWithoutInnerClasses(file.getPackageFqName()));
file.acceptChildren(this);
nameStack.pop();
if (file.isScript()) {
classStack.pop();
}
}
@Override
@@ -386,7 +382,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
String peek = peekFromStack(nameStack);
String name = safeIdentifier(descriptor.getName()).asString();
if (containingDeclaration instanceof ClassDescriptor || containingDeclaration instanceof ScriptDescriptor) {
if (containingDeclaration instanceof ClassDescriptor) {
return peek + '$' + name;
}
else if (containingDeclaration instanceof PackageFragmentDescriptor) {
@@ -24,17 +24,13 @@ import org.jetbrains.kotlin.codegen.SamType;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl;
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.util.slicedMap.BasicWritableSlice;
import org.jetbrains.kotlin.util.slicedMap.Slices;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
@@ -43,15 +39,12 @@ import org.jetbrains.org.objectweb.asm.Type;
import java.util.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
public class CodegenBinding {
public static final WritableSlice<ClassDescriptor, MutableClosure> CLOSURE = Slices.createSimpleSlice();
public static final WritableSlice<CallableDescriptor, ClassDescriptor> CLASS_FOR_CALLABLE = Slices.createSimpleSlice();
public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice();
public static final WritableSlice<ClassDescriptor, Type> ASM_TYPE = Slices.createSimpleSlice();
public static final WritableSlice<ClassDescriptor, Boolean> ENUM_ENTRY_CLASS_NEED_SUBCLASS = Slices.createSimpleSetSlice();
@@ -89,22 +82,6 @@ public class CodegenBinding {
return Boolean.TRUE.equals(bindingContext.get(ENUM_ENTRY_CLASS_NEED_SUBCLASS, classDescriptor));
}
@NotNull
public static Type asmTypeForScriptDescriptor(BindingContext bindingContext, @NotNull ScriptDescriptor scriptDescriptor) {
ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
//noinspection ConstantConditions
return getAsmType(bindingContext, classDescriptor);
}
@NotNull
public static Type asmTypeForScriptPsi(BindingContext bindingContext, @NotNull KtScript script) {
ScriptDescriptor scriptDescriptor = bindingContext.get(SCRIPT, script);
if (scriptDescriptor == null) {
throw new IllegalStateException("Script descriptor not found by PSI " + script);
}
return asmTypeForScriptDescriptor(bindingContext, scriptDescriptor);
}
@NotNull
public static ClassDescriptor anonymousClassForCallable(
@NotNull BindingContext bindingContext,
@@ -163,7 +140,7 @@ public class CodegenBinding {
@NotNull Type asmType,
@NotNull JvmFileClassesProvider fileClassesManager
) {
KtElement element = (KtElement) descriptorToDeclaration(classDescriptor);
KtElement element = (KtElement) DescriptorToSourceUtils.descriptorToDeclaration(classDescriptor);
assert element != null : "No source element for " + classDescriptor;
MutableClosure closure = new MutableClosure(classDescriptor, enclosing);
@@ -196,29 +173,6 @@ public class CodegenBinding {
innerClasses.add(inner);
}
public static void registerClassNameForScript(
@NotNull BindingTrace trace,
@NotNull KtScript script,
@NotNull Type asmType,
@NotNull JvmFileClassesProvider fileClassesManager
) {
ScriptDescriptor descriptor = trace.getBindingContext().get(SCRIPT, script);
if (descriptor == null) {
throw new IllegalStateException("Script descriptor is not found for PSI: " + PsiUtilsKt.getElementTextWithContext(script));
}
String simpleName = asmType.getInternalName().substring(asmType.getInternalName().lastIndexOf('/') + 1);
ClassDescriptorImpl classDescriptor =
new ClassDescriptorImpl(descriptor, Name.special("<script-" + simpleName + ">"), Modality.FINAL,
Collections.singleton(DescriptorUtilsKt.getBuiltIns(descriptor).getAnyType()),
KotlinSourceElementKt.toSourceElement(script));
classDescriptor.initialize(MemberScope.Empty.INSTANCE, Collections.<ConstructorDescriptor>emptySet(), null);
recordClosure(trace, classDescriptor, null, asmType, fileClassesManager);
trace.record(CLASS_FOR_SCRIPT, descriptor, classDescriptor);
}
@NotNull
private static Collection<KtFile> allFilesInPackages(BindingContext bindingContext, Collection<KtFile> files) {
// todo: we use Set and add given files but ignoring other scripts because something non-clear kept in binding
@@ -315,9 +315,10 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
public ScriptContext intoScript(
@NotNull ScriptDescriptor script,
@NotNull List<ScriptDescriptor> earlierScripts,
@NotNull ClassDescriptor classDescriptor
@NotNull ClassDescriptor classDescriptor,
@NotNull JetTypeMapper typeMapper
) {
return new ScriptContext(script, earlierScripts, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
return new ScriptContext(typeMapper, script, earlierScripts, classDescriptor, this);
}
@NotNull
@@ -16,30 +16,48 @@
package org.jetbrains.kotlin.codegen.context;
import kotlin.CollectionsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.FieldInfo;
import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
import org.jetbrains.kotlin.psi.KtClassInitializer;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtScript;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import java.util.List;
public class ScriptContext extends FieldOwnerContext<ClassDescriptor> {
public class ScriptContext extends ClassContext {
private final ScriptDescriptor scriptDescriptor;
private final List<ScriptDescriptor> earlierScripts;
private final KtExpression lastStatement;
public ScriptContext(
@NotNull JetTypeMapper typeMapper,
@NotNull ScriptDescriptor scriptDescriptor,
@NotNull List<ScriptDescriptor> earlierScripts,
@NotNull ClassDescriptor contextDescriptor,
@NotNull OwnerKind contextKind,
@Nullable CodegenContext parentContext,
@Nullable MutableClosure closure
@Nullable CodegenContext parentContext
) {
super(contextDescriptor, contextKind, parentContext, closure, contextDescriptor, null);
super(typeMapper, contextDescriptor, OwnerKind.IMPLEMENTATION, parentContext, null);
this.scriptDescriptor = scriptDescriptor;
this.earlierScripts = earlierScripts;
KtScript script = (KtScript) DescriptorToSourceUtils.getSourceFromDescriptor(scriptDescriptor);
assert script != null : "Declaration should be present for script: " + scriptDescriptor;
KtDeclaration lastDeclaration = CollectionsKt.lastOrNull(script.getDeclarations());
if (lastDeclaration instanceof KtClassInitializer) {
this.lastStatement = ((KtClassInitializer) lastDeclaration).getBody();
}
else {
this.lastStatement = null;
}
}
@NotNull
@@ -47,6 +65,15 @@ public class ScriptContext extends FieldOwnerContext<ClassDescriptor> {
return scriptDescriptor;
}
@NotNull
public FieldInfo getResultFieldInfo() {
assert getState().getShouldGenerateScriptResultValue() : "Should not be called unless 'scriptResultFieldName' is set";
GenerationState state = getState();
String scriptResultFieldName = state.getScriptResultFieldName();
assert scriptResultFieldName != null;
return FieldInfo.createForHiddenField(state.getTypeMapper().mapClass(scriptDescriptor), AsmTypes.OBJECT_TYPE, scriptResultFieldName);
}
@NotNull
public List<ScriptDescriptor> getEarlierScripts() {
return earlierScripts;
@@ -61,6 +88,11 @@ public class ScriptContext extends FieldOwnerContext<ClassDescriptor> {
return "script$" + (index + 1);
}
@Nullable
public KtExpression getLastStatement() {
return lastStatement;
}
@Override
public String toString() {
return "Script: " + getContextDescriptor().getName().asString();
@@ -62,7 +62,6 @@ import java.util.*;
import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLASS_FOR_SCRIPT;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getConstant;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
@@ -598,17 +597,15 @@ public class InlineCodegen extends CallGenerator {
CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state, sourceFile);
if (descriptor instanceof ClassDescriptor) {
OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION;
return parent.intoClass((ClassDescriptor) descriptor, kind, state);
}
else if (descriptor instanceof ScriptDescriptor) {
ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, (ScriptDescriptor) descriptor);
assert classDescriptorForScript != null : "Can't find class for script: " + descriptor;
if (descriptor instanceof ScriptDescriptor) {
List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter();
return parent.intoScript((ScriptDescriptor) descriptor,
earlierScripts == null ? Collections.emptyList() : earlierScripts,
classDescriptorForScript);
(ClassDescriptor) descriptor, state.getTypeMapper());
}
else if (descriptor instanceof ClassDescriptor) {
OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION;
return parent.intoClass((ClassDescriptor) descriptor, kind, state);
}
else if (descriptor instanceof FunctionDescriptor) {
return parent.intoFunction((FunctionDescriptor) descriptor);
@@ -101,6 +101,8 @@ public class GenerationState @JvmOverloads constructor(
public val inlineCycleReporter: InlineCycleReporter = InlineCycleReporter(diagnostics)
public val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this)
public var earlierScriptsForReplInterpreter: List<ScriptDescriptor>? = null
public var scriptResultFieldName: String? = null
public val shouldGenerateScriptResultValue: Boolean get() = scriptResultFieldName != null
public val reflectionTypes: ReflectionTypes = ReflectionTypes(module)
public val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes()
public val factory: ClassFileFactory
@@ -169,9 +169,6 @@ public class JetTypeMapper {
else if (container instanceof ClassDescriptor) {
return mapClass((ClassDescriptor) container);
}
else if (container instanceof ScriptDescriptor) {
return asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) container);
}
else {
throw new UnsupportedOperationException("Don't know how to map owner for " + descriptor);
}
@@ -580,10 +577,6 @@ public class JetTypeMapper {
return fqName.isRoot() ? name : fqName.asString().replace('.', '/') + '/' + name;
}
if (container instanceof ScriptDescriptor) {
return asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) container).getInternalName() + "$" + name;
}
assert container instanceof ClassDescriptor : "Unexpected container: " + container + " for " + klass;
String containerInternalName = computeAsmTypeImpl((ClassDescriptor) container);
@@ -1392,12 +1385,10 @@ public class JetTypeMapper {
sw.writeParametersStart();
for (ScriptDescriptor importedScript : importedScripts) {
ClassDescriptor descriptor = bindingContext.get(CLASS_FOR_SCRIPT, importedScript);
assert descriptor != null : "Script not found: " + importedScript;
writeParameter(sw, descriptor.getDefaultType());
writeParameter(sw, importedScript.getDefaultType());
}
for (ValueParameterDescriptor valueParameter : script.getScriptCodeDescriptor().getValueParameters()) {
for (ValueParameterDescriptor valueParameter : script.getUnsubstitutedPrimaryConstructor().getValueParameters()) {
writeParameter(sw, valueParameter.getType());
}
@@ -22,7 +22,6 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.impl.PsiFileFactoryImpl;
import com.intellij.psi.search.ProjectScope;
@@ -30,7 +29,6 @@ import com.intellij.testFramework.LightVirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport;
import org.jetbrains.kotlin.cli.common.messages.DiagnosticMessageReporter;
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport;
@@ -67,8 +65,8 @@ import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM;
import org.jetbrains.kotlin.resolve.lazy.ResolveSession;
import org.jetbrains.kotlin.resolve.lazy.data.JetClassLikeInfo;
import org.jetbrains.kotlin.resolve.lazy.declarations.*;
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import org.jetbrains.org.objectweb.asm.Type;
@@ -85,10 +83,10 @@ import java.util.Collections;
import java.util.List;
import static org.jetbrains.kotlin.codegen.AsmUtil.asmTypeByFqNameWithoutInnerClasses;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.registerClassNameForScript;
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
public class ReplInterpreter {
private static final String SCRIPT_RESULT_FIELD_NAME = "$$result";
private int lineNumber = 0;
@Nullable
@@ -309,13 +307,14 @@ public class ReplInterpreter {
List<Pair<ScriptDescriptor, Type>> earlierScripts = Lists.newArrayList();
for (EarlierLine earlierLine : earlierLines) {
//TODO_R: not needed
earlierScripts.add(Pair.create(earlierLine.getScriptDescriptor(), earlierLine.getClassType()));
}
GenerationState state = new GenerationState(psiFile.getProject(), ClassBuilderFactories.BINARIES,
module, trace.getBindingContext(), Collections.singletonList(psiFile));
compileScript(psiFile.getScript(), scriptClassType, earlierScripts, state, CompilationErrorHandler.THROW_EXCEPTION);
compileScript(psiFile.getScript(), earlierScripts, state, CompilationErrorHandler.THROW_EXCEPTION);
for (OutputFile outputFile : state.getFactory().asList()) {
if(outputFile.getRelativePath().endsWith(".class")) {
@@ -347,14 +346,13 @@ public class ReplInterpreter {
setReplScriptExecuting(false);
}
Field rvField = scriptClass.getDeclaredField("rv");
Field rvField = scriptClass.getDeclaredField(SCRIPT_RESULT_FIELD_NAME);
rvField.setAccessible(true);
Object rv = rvField.get(scriptInstance);
earlierLines.add(new EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance, scriptClassType));
KotlinType returnType = scriptDescriptor.getScriptCodeDescriptor().getReturnType();
return LineResult.successful(rv, returnType != null && KotlinBuiltIns.isUnit(returnType));
return LineResult.successful(rv, false);
}
catch (Throwable e) {
@SuppressWarnings("UseOfSystemOutOrSystemErr")
@@ -415,12 +413,8 @@ public class ReplInterpreter {
return null;
}
ScriptDescriptor scriptDescriptor = context.getScripts().get(psiFile.getScript());
lastLineScope = trace.get(BindingContext.SCRIPT_SCOPE, scriptDescriptor);
if (lastLineScope == null) {
throw new IllegalStateException("last line scope is not initialized");
}
LazyScriptDescriptor scriptDescriptor = context.getScripts().get(psiFile.getScript());
lastLineScope = scriptDescriptor.getScopeForInitializerResolution();
return scriptDescriptor;
}
@@ -435,26 +429,19 @@ public class ReplInterpreter {
List<ScriptDescriptor> earlierScriptDescriptors = new ArrayList<ScriptDescriptor>(earlierScripts.size());
for (Pair<ScriptDescriptor, Type> pair : earlierScripts) {
ScriptDescriptor earlierDescriptor = pair.first;
Type earlierClassType = pair.second;
PsiElement jetScript = descriptorToDeclaration(earlierDescriptor);
if (jetScript != null) {
registerClassNameForScript(state.getBindingTrace(), (KtScript) jetScript, earlierClassType, state.getFileClassesProvider());
earlierScriptDescriptors.add(earlierDescriptor);
}
earlierScriptDescriptors.add(earlierDescriptor);
}
state.setEarlierScriptsForReplInterpreter(earlierScriptDescriptors);
}
public static void compileScript(
@NotNull KtScript script,
@NotNull Type classType,
@NotNull List<Pair<ScriptDescriptor, Type>> earlierScripts,
@NotNull GenerationState state,
@NotNull CompilationErrorHandler errorHandler
) {
state.setScriptResultFieldName(SCRIPT_RESULT_FIELD_NAME);
registerEarlierScripts(state, earlierScripts);
registerClassNameForScript(state.getBindingTrace(), script, classType, state.getFileClassesProvider());
state.beforeCompile();
KotlinCodegenFacade.generatePackage(
@@ -51,6 +51,7 @@ public class JvmDeclarationOrigin(
public val descriptor: DeclarationDescriptor?
) {
companion object {
@JvmField
public val NO_ORIGIN: JvmDeclarationOrigin = JvmDeclarationOrigin(OTHER, null, null)
}
}
@@ -98,7 +98,7 @@ abstract class LightClassDataProvider<T : WithFileStubAndExtraDiagnostics>(
/*disableOptimization=*/false,
/*useTypeTableInSerializer=*/false,
forExtraDiagnostics)
KotlinCodegenFacade.prepareForCompilation(state)
state.beforeCompile()
bindingContext = state.bindingContext