LIGHT_CLASSES mode for scripts

- Do not generate constructor bodies
- Do not generate script class when package contents are requested
- NOT DONE: generate script class when its name is requested
This commit is contained in:
Andrey Breslav
2014-12-25 20:01:08 +03:00
parent 95f5e8d08c
commit 89e1588e13
8 changed files with 108 additions and 59 deletions
@@ -304,13 +304,17 @@ public class PackageCodegen {
}
else if (declaration instanceof JetClassOrObject) {
JetClassOrObject classOrObject = (JetClassOrObject) declaration;
if (state.getGenerateDeclaredClassFilter().shouldProcess(classOrObject)) {
if (state.getGenerateDeclaredClassFilter().shouldProcessClass(classOrObject)) {
generateClassOrObject(classOrObject);
}
}
else if (declaration instanceof JetScript) {
JetScript script = (JetScript) declaration;
// SCRIPT: generate script code, should be separate execution branch
ScriptCodegen.createScriptCodegen((JetScript) declaration, state, packagePartContext).generate();
if (state.getGenerateDeclaredClassFilter().shouldProcessScript(script)) {
ScriptCodegen.createScriptCodegen(script, state, packagePartContext).generate();
}
}
}
@@ -140,68 +140,73 @@ public class ScriptCodegen extends MemberCodegen<JetScript> {
ACC_PUBLIC, jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor(),
null, null);
mv.visitCode();
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode();
final InstructionAdapter iv = new InstructionAdapter(mv);
final InstructionAdapter iv = new InstructionAdapter(mv);
Type classType = typeMapper.mapType(classDescriptorForScript);
Type classType = typeMapper.mapType(classDescriptorForScript);
iv.load(0, classType);
iv.invokespecial("java/lang/Object", "<init>", "()V", false);
iv.load(0, classType);
iv.invokespecial("java/lang/Object", "<init>", "()V", false);
iv.load(0, classType);
iv.load(0, classType);
final FrameMap frameMap = new FrameMap();
frameMap.enterTemp(OBJECT_TYPE);
final FrameMap frameMap = new FrameMap();
frameMap.enterTemp(OBJECT_TYPE);
for (ScriptDescriptor importedScript : context.getEarlierScripts()) {
frameMap.enter(importedScript, OBJECT_TYPE);
}
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);
frameMap.enter(parameter, argTypes[i + add]);
}
generateInitializers(new Function0<ExpressionCodegen>() {
@Override
public ExpressionCodegen invoke() {
return new ExpressionCodegen(iv, frameMap, Type.VOID_TYPE, methodContext, state, ScriptCodegen.this);
for (ScriptDescriptor importedScript : context.getEarlierScripts()) {
frameMap.enter(importedScript, OBJECT_TYPE);
}
});
int offset = 1;
Type[] argTypes = jvmSignature.getAsmMethod().getArgumentTypes();
int add = 0;
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, earlierScript);
iv.load(0, classType);
iv.load(offset, earlierClassType);
offset += earlierClassType.getSize();
iv.putfield(classType.getInternalName(), context.getScriptFieldName(earlierScript), earlierClassType.getDescriptor());
for (int i = 0; i < scriptDescriptor.getScriptCodeDescriptor().getValueParameters().size(); i++) {
ValueParameterDescriptor parameter = scriptDescriptor.getScriptCodeDescriptor().getValueParameters().get(i);
frameMap.enter(parameter, argTypes[i + add]);
}
generateInitializers(new Function0<ExpressionCodegen>() {
@Override
public ExpressionCodegen invoke() {
return new ExpressionCodegen(iv, frameMap, Type.VOID_TYPE, methodContext, state, ScriptCodegen.this);
}
});
int offset = 1;
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, 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()) {
Type parameterType = typeMapper.mapType(parameter.getType());
iv.load(0, classType);
iv.load(offset, parameterType);
offset += parameterType.getSize();
iv.putfield(classType.getInternalName(), parameter.getName().getIdentifier(), parameterType.getDescriptor());
}
StackValue stackValue =
new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this)
.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);
}
for (ValueParameterDescriptor parameter : scriptDescriptor.getScriptCodeDescriptor().getValueParameters()) {
Type parameterType = typeMapper.mapType(parameter.getType());
iv.load(0, classType);
iv.load(offset, parameterType);
offset += parameterType.getSize();
iv.putfield(classType.getInternalName(), parameter.getName().getIdentifier(), parameterType.getDescriptor());
}
StackValue stackValue =
new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this).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);
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
@@ -214,7 +214,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
super.visitObjectDeclaration(declaration);
}
else {
if (!filter.shouldProcess(declaration)) return;
if (!filter.shouldProcessClass(declaration)) return;
ClassDescriptor classDescriptor = bindingContext.get(CLASS, declaration);
// working around a problem with shallow analysis
@@ -233,7 +233,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
@Override
public void visitClass(@NotNull JetClass klass) {
if (!filter.shouldProcess(klass)) return;
if (!filter.shouldProcessClass(klass)) return;
ClassDescriptor classDescriptor = bindingContext.get(CLASS, klass);
// working around a problem with shallow analysis
@@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.diagnostics.DiagnosticSink;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetScript;
import org.jetbrains.jet.lang.reflect.ReflectionTypes;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
@@ -42,11 +43,17 @@ import java.util.List;
public class GenerationState {
public interface GenerateClassFilter {
boolean shouldProcess(JetClassOrObject classOrObject);
boolean shouldProcessClass(JetClassOrObject classOrObject);
boolean shouldProcessScript(JetScript script);
GenerateClassFilter GENERATE_ALL = new GenerateClassFilter() {
@Override
public boolean shouldProcess(JetClassOrObject classOrObject) {
public boolean shouldProcessClass(JetClassOrObject classOrObject) {
return true;
}
@Override
public boolean shouldProcessScript(JetScript script) {
return true;
}
};
@@ -51,6 +51,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
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.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.Diagnostics;
@@ -110,11 +111,17 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
public GenerationState.GenerateClassFilter getGenerateClassFilter() {
return new GenerationState.GenerateClassFilter() {
@Override
public boolean shouldProcess(JetClassOrObject classOrObject) {
public boolean shouldProcessClass(JetClassOrObject classOrObject) {
// Top-level classes and such should not be generated for performance reasons.
// Local classes in top-level functions must still be generated
return JetPsiUtil.isLocal(classOrObject);
}
@Override
public boolean shouldProcessScript(JetScript script) {
// Scripts yield top-level classes, and should not be generated
return false;
}
};
}
@@ -215,7 +222,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
public GenerationState.GenerateClassFilter getGenerateClassFilter() {
return new GenerationState.GenerateClassFilter() {
@Override
public boolean shouldProcess(JetClassOrObject generatedClassOrObject) {
public boolean shouldProcessClass(JetClassOrObject generatedClassOrObject) {
// Trivial: generate and analyze class we are interested in.
if (generatedClassOrObject == classOrObject) return true;
@@ -246,6 +253,12 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
return false;
}
@Override
public boolean shouldProcessScript(JetScript script) {
// We generate all enclosing classes
return PsiTreeUtil.isAncestor(script, classOrObject, false);
}
};
}
@@ -0,0 +1,5 @@
// FILE: script.kts
annotation class Ann
[Ann]<!SYNTAX!><!>
@@ -0,0 +1,9 @@
package
public final class Script {
public constructor Script()
public final val rv: [ERROR : getBlockReturnedType returned null]
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -637,6 +637,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("DanglingInScript.kt")
public void testDanglingInScript() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/DanglingInScript.kt");
doTest(fileName);
}
@TestMetadata("DanglingMixed.kt")
public void testDanglingMixed() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/DanglingMixed.kt");