J2K: Script Codegen (step 2)
This commit is contained in:
@@ -3,229 +3,201 @@
|
|||||||
* that can be found in the license/LICENSE.txt file.
|
* that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen;
|
package org.jetbrains.kotlin.codegen
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||||
import org.jetbrains.kotlin.codegen.context.ScriptContext;
|
import org.jetbrains.kotlin.codegen.context.ScriptContext
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
|
||||||
import java.util.List;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
|
class ScriptCodegen private constructor(
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
private val scriptDeclaration: KtScript,
|
||||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
state: GenerationState,
|
||||||
|
private val scriptContext: ScriptContext,
|
||||||
|
builder: ClassBuilder
|
||||||
|
) : MemberCodegen<KtScript>(state, null, scriptContext, scriptDeclaration, builder) {
|
||||||
|
private val scriptDescriptor = scriptContext.scriptDescriptor
|
||||||
|
private val classAsmType = typeMapper.mapClass(scriptContext.contextDescriptor)
|
||||||
|
|
||||||
public class ScriptCodegen extends MemberCodegen<KtScript> {
|
override fun generateDeclaration() {
|
||||||
|
v.defineClass(
|
||||||
|
scriptDeclaration,
|
||||||
|
state.classFileVersion,
|
||||||
|
ACC_PUBLIC or ACC_SUPER,
|
||||||
|
classAsmType.internalName,
|
||||||
|
null,
|
||||||
|
typeMapper.mapSupertype(scriptDescriptor.getSuperClassOrAny().defaultType, null).internalName,
|
||||||
|
mapSupertypesNames(typeMapper, scriptDescriptor.getSuperInterfaces(), null)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
public static ScriptCodegen createScriptCodegen(
|
override fun generateBody() {
|
||||||
@NotNull KtScript declaration,
|
genMembers()
|
||||||
@NotNull GenerationState state,
|
genFieldsForParameters(v)
|
||||||
@NotNull CodegenContext parentContext
|
genConstructor(scriptDescriptor, v, scriptContext.intoFunction(scriptDescriptor.unsubstitutedPrimaryConstructor))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateSyntheticPartsBeforeBody() {
|
||||||
|
generatePropertyMetadataArrayFieldIfNeeded(classAsmType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateSyntheticPartsAfterBody() {}
|
||||||
|
|
||||||
|
override fun generateKotlinMetadataAnnotation() {
|
||||||
|
generateKotlinClassMetadataAnnotation(scriptDescriptor, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun genConstructor(
|
||||||
|
scriptDescriptor: ScriptDescriptor,
|
||||||
|
classBuilder: ClassBuilder,
|
||||||
|
methodContext: MethodContext
|
||||||
) {
|
) {
|
||||||
BindingContext bindingContext = state.getBindingContext();
|
val jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, scriptContext.earlierScripts)
|
||||||
ScriptDescriptor scriptDescriptor = bindingContext.get(BindingContext.SCRIPT, declaration);
|
|
||||||
assert scriptDescriptor != null;
|
|
||||||
|
|
||||||
Type classType = state.getTypeMapper().mapType(scriptDescriptor);
|
if (state.replSpecific.shouldGenerateScriptResultValue) {
|
||||||
|
val resultFieldInfo = scriptContext.resultFieldInfo
|
||||||
ClassBuilder builder = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(declaration, scriptDescriptor),
|
|
||||||
classType, declaration.getContainingFile());
|
|
||||||
List<ScriptDescriptor> earlierScripts = state.getReplSpecific().getEarlierScriptsForReplInterpreter();
|
|
||||||
ScriptContext scriptContext = parentContext.intoScript(
|
|
||||||
scriptDescriptor,
|
|
||||||
earlierScripts == null ? Collections.emptyList() : earlierScripts,
|
|
||||||
scriptDescriptor,
|
|
||||||
state.getTypeMapper()
|
|
||||||
);
|
|
||||||
return new ScriptCodegen(declaration, state, scriptContext, builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final KtScript scriptDeclaration;
|
|
||||||
private final ScriptContext context;
|
|
||||||
private final ScriptDescriptor scriptDescriptor;
|
|
||||||
private final Type classAsmType;
|
|
||||||
|
|
||||||
private ScriptCodegen(
|
|
||||||
@NotNull KtScript scriptDeclaration,
|
|
||||||
@NotNull GenerationState state,
|
|
||||||
@NotNull ScriptContext context,
|
|
||||||
@NotNull ClassBuilder builder
|
|
||||||
) {
|
|
||||||
super(state, null, context, scriptDeclaration, builder);
|
|
||||||
this.scriptDeclaration = scriptDeclaration;
|
|
||||||
this.context = context;
|
|
||||||
this.scriptDescriptor = context.getScriptDescriptor();
|
|
||||||
classAsmType = typeMapper.mapClass(context.getContextDescriptor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void generateDeclaration() {
|
|
||||||
v.defineClass(scriptDeclaration,
|
|
||||||
state.getClassFileVersion(),
|
|
||||||
ACC_PUBLIC | ACC_SUPER,
|
|
||||||
classAsmType.getInternalName(),
|
|
||||||
null,
|
|
||||||
typeMapper.mapSupertype(DescriptorUtilsKt.getSuperClassOrAny(scriptDescriptor).getDefaultType(), null).getInternalName(),
|
|
||||||
CodegenUtilKt.mapSupertypesNames(typeMapper, DescriptorUtilsKt.getSuperInterfaces(scriptDescriptor), null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void generateBody() {
|
|
||||||
genMembers();
|
|
||||||
genFieldsForParameters(v);
|
|
||||||
genConstructor(scriptDescriptor, v,
|
|
||||||
context.intoFunction(scriptDescriptor.getUnsubstitutedPrimaryConstructor()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void generateSyntheticPartsBeforeBody() {
|
|
||||||
generatePropertyMetadataArrayFieldIfNeeded(classAsmType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void generateSyntheticPartsAfterBody() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void generateKotlinMetadataAnnotation() {
|
|
||||||
generateKotlinClassMetadataAnnotation(scriptDescriptor, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void genConstructor(
|
|
||||||
@NotNull ScriptDescriptor scriptDescriptor,
|
|
||||||
@NotNull ClassBuilder classBuilder,
|
|
||||||
@NotNull MethodContext methodContext
|
|
||||||
) {
|
|
||||||
JvmMethodSignature jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, context.getEarlierScripts());
|
|
||||||
|
|
||||||
if (state.getReplSpecific().getShouldGenerateScriptResultValue()) {
|
|
||||||
FieldInfo resultFieldInfo = context.getResultFieldInfo();
|
|
||||||
classBuilder.newField(
|
classBuilder.newField(
|
||||||
JvmDeclarationOrigin.NO_ORIGIN,
|
JvmDeclarationOrigin.NO_ORIGIN,
|
||||||
ACC_PUBLIC | ACC_FINAL,
|
ACC_PUBLIC or ACC_FINAL,
|
||||||
resultFieldInfo.getFieldName(),
|
resultFieldInfo.fieldName,
|
||||||
resultFieldInfo.getFieldType().getDescriptor(),
|
resultFieldInfo.fieldType.descriptor,
|
||||||
null,
|
null, null)
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodVisitor mv = classBuilder.newMethod(
|
val mv = classBuilder.newMethod(
|
||||||
JvmDeclarationOriginKt.OtherOrigin(scriptDeclaration, scriptDescriptor.getUnsubstitutedPrimaryConstructor()),
|
OtherOrigin(scriptDeclaration, scriptDescriptor.unsubstitutedPrimaryConstructor),
|
||||||
ACC_PUBLIC, jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor(),
|
ACC_PUBLIC, jvmSignature.asmMethod.name, jvmSignature.asmMethod.descriptor, null, null)
|
||||||
null, null);
|
|
||||||
|
|
||||||
if (state.getClassBuilderMode().generateBodies) {
|
if (state.classBuilderMode.generateBodies) {
|
||||||
mv.visitCode();
|
mv.visitCode()
|
||||||
|
|
||||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
val iv = InstructionAdapter(mv)
|
||||||
|
|
||||||
Type classType = typeMapper.mapType(scriptDescriptor);
|
val classType = typeMapper.mapType(scriptDescriptor)
|
||||||
|
|
||||||
ClassDescriptor superclass = DescriptorUtilsKt.getSuperClassNotAny(scriptDescriptor);
|
val superclass = scriptDescriptor.getSuperClassNotAny()
|
||||||
// TODO: throw if class is not found)
|
// TODO: throw if class is not found)
|
||||||
|
|
||||||
if (superclass == null) {
|
if (superclass == null) {
|
||||||
iv.load(0, classType);
|
iv.load(0, classType)
|
||||||
iv.invokespecial("java/lang/Object", "<init>", "()V", false);
|
iv.invokespecial("java/lang/Object", "<init>", "()V", false)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ConstructorDescriptor ctorDesc = superclass.getUnsubstitutedPrimaryConstructor();
|
val ctorDesc = superclass.unsubstitutedPrimaryConstructor
|
||||||
if (ctorDesc == null) throw new RuntimeException("Primary constructor not found for script template " + superclass.toString());
|
?: throw RuntimeException("Primary constructor not found for script template " + superclass.toString())
|
||||||
|
|
||||||
iv.load(0, classType);
|
iv.load(0, classType)
|
||||||
|
|
||||||
int valueParamStart = context.getEarlierScripts().isEmpty() ? 1 : 2; // this + array of earlier scripts if not empty
|
val valueParamStart = if (scriptContext.earlierScripts.isEmpty()) 1 else 2 // this + array of earlier scripts if not empty
|
||||||
|
|
||||||
List<ValueParameterDescriptor> valueParameters = scriptDescriptor.getUnsubstitutedPrimaryConstructor().getValueParameters();
|
val valueParameters = scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters
|
||||||
for (ValueParameterDescriptor superclassParam: ctorDesc.getValueParameters()) {
|
for (superclassParam in ctorDesc.valueParameters) {
|
||||||
ValueParameterDescriptor valueParam = null;
|
val valueParam = valueParameters.first { it.name == superclassParam.name }
|
||||||
for (ValueParameterDescriptor vpd: valueParameters) {
|
iv.load(valueParam!!.index + valueParamStart, typeMapper.mapType(valueParam.type))
|
||||||
if (vpd.getName().equals(superclassParam.getName())) {
|
|
||||||
valueParam = vpd;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert valueParam != null;
|
|
||||||
iv.load(valueParam.getIndex() + valueParamStart, typeMapper.mapType(valueParam.getType()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CallableMethod ctorMethod = typeMapper.mapToCallableMethod(ctorDesc, false);
|
val ctorMethod = typeMapper.mapToCallableMethod(ctorDesc, false)
|
||||||
String sig = ctorMethod.getAsmMethod().getDescriptor();
|
val sig = ctorMethod.getAsmMethod().descriptor
|
||||||
|
|
||||||
iv.invokespecial(
|
iv.invokespecial(
|
||||||
typeMapper.mapSupertype(superclass.getDefaultType(), null).getInternalName(),
|
typeMapper.mapSupertype(superclass.defaultType, null).internalName,
|
||||||
"<init>", sig, false);
|
"<init>", sig, false)
|
||||||
}
|
}
|
||||||
iv.load(0, classType);
|
iv.load(0, classType)
|
||||||
|
|
||||||
FrameMap frameMap = new FrameMap();
|
val frameMap = FrameMap()
|
||||||
frameMap.enterTemp(OBJECT_TYPE);
|
frameMap.enterTemp(OBJECT_TYPE)
|
||||||
|
|
||||||
|
|
||||||
if (!context.getEarlierScripts().isEmpty()) {
|
if (!scriptContext.earlierScripts.isEmpty()) {
|
||||||
int scriptsParamIndex = frameMap.enterTemp(AsmUtil.getArrayType(OBJECT_TYPE));
|
val scriptsParamIndex = frameMap.enterTemp(AsmUtil.getArrayType(OBJECT_TYPE))
|
||||||
|
|
||||||
int earlierScriptIndex = 0;
|
var earlierScriptIndex = 0
|
||||||
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
|
for (earlierScript in scriptContext.earlierScripts) {
|
||||||
Type earlierClassType = typeMapper.mapClass(earlierScript);
|
val earlierClassType = typeMapper.mapClass(earlierScript)
|
||||||
iv.load(0, classType);
|
iv.load(0, classType)
|
||||||
iv.load(scriptsParamIndex, earlierClassType);
|
iv.load(scriptsParamIndex, earlierClassType)
|
||||||
iv.aconst(earlierScriptIndex++);
|
iv.aconst(earlierScriptIndex++)
|
||||||
iv.aload(OBJECT_TYPE);
|
iv.aload(OBJECT_TYPE)
|
||||||
iv.checkcast(earlierClassType);
|
iv.checkcast(earlierClassType)
|
||||||
iv.putfield(classType.getInternalName(), context.getScriptFieldName(earlierScript), earlierClassType.getDescriptor());
|
iv.putfield(classType.internalName, scriptContext.getScriptFieldName(earlierScript), earlierClassType.descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this);
|
val codegen = ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this)
|
||||||
|
|
||||||
generateInitializers(() -> codegen);
|
generateInitializers { codegen }
|
||||||
|
|
||||||
iv.areturn(Type.VOID_TYPE);
|
iv.areturn(Type.VOID_TYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
mv.visitMaxs(-1, -1);
|
mv.visitMaxs(-1, -1)
|
||||||
mv.visitEnd();
|
mv.visitEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
private void genFieldsForParameters(@NotNull ClassBuilder classBuilder) {
|
private fun genFieldsForParameters(classBuilder: ClassBuilder) {
|
||||||
for (ScriptDescriptor earlierScript : context.getEarlierScripts()) {
|
for (earlierScript in scriptContext.earlierScripts) {
|
||||||
Type earlierClassName = typeMapper.mapType(earlierScript);
|
val earlierClassName = typeMapper.mapType(earlierScript)
|
||||||
int access = ACC_PUBLIC | ACC_FINAL;
|
val access = ACC_PUBLIC or ACC_FINAL
|
||||||
classBuilder.newField(NO_ORIGIN, access, context.getScriptFieldName(earlierScript), earlierClassName.getDescriptor(), null, null);
|
classBuilder.newField(NO_ORIGIN, access, scriptContext.getScriptFieldName(earlierScript), earlierClassName.descriptor, null, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void genMembers() {
|
private fun genMembers() {
|
||||||
for (KtDeclaration declaration : scriptDeclaration.getDeclarations()) {
|
for (declaration in scriptDeclaration.declarations) {
|
||||||
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) {
|
if (declaration is KtProperty || declaration is KtNamedFunction || declaration is KtTypeAlias) {
|
||||||
genSimpleMember(declaration);
|
genSimpleMember(declaration)
|
||||||
}
|
}
|
||||||
else if (declaration instanceof KtClassOrObject) {
|
else if (declaration is KtClassOrObject) {
|
||||||
genClassOrObject((KtClassOrObject) declaration);
|
genClassOrObject(declaration)
|
||||||
}
|
}
|
||||||
else if (declaration instanceof KtDestructuringDeclaration) {
|
else if (declaration is KtDestructuringDeclaration) {
|
||||||
for (KtDestructuringDeclarationEntry entry : ((KtDestructuringDeclaration) declaration).getEntries()) {
|
for (entry in declaration.entries) {
|
||||||
genSimpleMember(entry);
|
genSimpleMember(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun createScriptCodegen(
|
||||||
|
declaration: KtScript,
|
||||||
|
state: GenerationState,
|
||||||
|
parentContext: CodegenContext<*>
|
||||||
|
): ScriptCodegen {
|
||||||
|
val bindingContext = state.bindingContext
|
||||||
|
val scriptDescriptor = bindingContext.get<PsiElement, ScriptDescriptor>(BindingContext.SCRIPT, declaration)!!
|
||||||
|
|
||||||
|
val classType = state.typeMapper.mapType(scriptDescriptor)
|
||||||
|
|
||||||
|
val builder = state.factory.newVisitor(
|
||||||
|
OtherOrigin(declaration, scriptDescriptor), classType, declaration.containingFile)
|
||||||
|
|
||||||
|
val earlierScripts = state.replSpecific.earlierScriptsForReplInterpreter
|
||||||
|
|
||||||
|
val scriptContext = parentContext.intoScript(
|
||||||
|
scriptDescriptor,
|
||||||
|
earlierScripts ?: emptyList(),
|
||||||
|
scriptDescriptor,
|
||||||
|
state.typeMapper
|
||||||
|
)
|
||||||
|
|
||||||
|
return ScriptCodegen(declaration, state, scriptContext, builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user