From ac65aebb198242d3f9a8554d835f3ac5c9630ed0 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Tue, 24 Jul 2018 15:19:34 +0200 Subject: [PATCH] Direct mapping of script implicit receivers and env vars to parameters --- .../kotlin/codegen/PropertyCodegen.java | 43 +------------------ .../jetbrains/kotlin/codegen/ScriptCodegen.kt | 43 ++++++++----------- .../kotlin/codegen/context/ScriptContext.kt | 17 +++++++- .../descriptors/LazyScriptClassMemberScope.kt | 25 +++++------ .../ScriptEnvironmentPropertyDescriptor.kt | 4 +- .../AbstractCustomScriptCodegenTest.kt | 10 ++--- 6 files changed, 53 insertions(+), 89 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 48f850bfe12..cc66b07e189 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -33,11 +33,9 @@ import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt; import org.jetbrains.kotlin.resolve.constants.ConstantValue; -import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; -import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentPropertyDescriptor; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor; import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.types.ErrorUtils; @@ -521,10 +519,7 @@ public class PropertyCodegen { FunctionGenerationStrategy strategy; if (accessor == null || !accessor.hasBody()) { - if (accessorDescriptor.getCorrespondingProperty() instanceof ScriptEnvironmentPropertyDescriptor) { - strategy = new ScriptEnvPropertyAccessorStrategy(state, accessorDescriptor); - } - else if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) { + if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) { strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor); } else { @@ -637,42 +632,6 @@ public class PropertyCodegen { } } - static class ScriptEnvPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased { - public static final Type MAP_IFACE_TYPE = Type.getObjectType("java/util/Map"); - public static final String MAP_FIELD_NAME = "$scriptEnvironment"; - private final PropertyAccessorDescriptor propertyAccessorDescriptor; - - public ScriptEnvPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) { - super(state); - this.propertyAccessorDescriptor = descriptor; - } - - @Override - public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { - InstructionAdapter v = codegen.v; - - Type scriptType = state.getTypeMapper().mapOwner(propertyAccessorDescriptor); - String scriptInternalName = scriptType.getInternalName(); - v.load(0, scriptType); - v.getfield(scriptInternalName, MAP_FIELD_NAME, MAP_IFACE_TYPE.getDescriptor()); - v.aconst(propertyAccessorDescriptor.getCorrespondingProperty().getName().asString()); - if (propertyAccessorDescriptor instanceof PropertyGetterDescriptor) { - v.invokeinterface(MAP_IFACE_TYPE.getInternalName(), "get", - Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE)); - } - else { - Type valueType = state.getTypeMapper().mapType(propertyAccessorDescriptor.getCorrespondingProperty()); - v.load(1, valueType); - StackValue.coerce(valueType, AsmTypes.OBJECT_TYPE, v); - v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_TYPE.getInternalName(), "put", - Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE), true); - } - Type returnType = state.getTypeMapper().mapReturnType(propertyAccessorDescriptor); - StackValue.coerce(AsmTypes.OBJECT_TYPE, returnType, v); - v.areturn(returnType); - } - } - public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) { ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt index 2021873743e..e0bf4d4d8fd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces -import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN @@ -61,10 +60,6 @@ class ScriptCodegen private constructor( override fun generateSyntheticPartsBeforeBody() { generatePropertyMetadataArrayFieldIfNeeded(classAsmType) - scriptContext.scriptDescriptor.scriptEnvironmentProperties.forEach { - propertyCodegen.generateGetter(null, it, null) - propertyCodegen.generateSetter(null, it, null) - } } override fun generateSyntheticPartsAfterBody() {} @@ -127,6 +122,12 @@ class ScriptCodegen private constructor( field.store(value, iv) } + fun genFieldFromParam(fieldClassType: Type, paramIndex: Int, name: String) { + val value = StackValue.local(paramIndex, fieldClassType) + val field = StackValue.field(fieldClassType, classType, name, false, StackValue.local(0, classType)) + field.store(value, iv) + } + if (!scriptContext.earlierScripts.isEmpty()) { val scriptsParamIndex = frameMap.enterTemp(AsmUtil.getArrayType(OBJECT_TYPE)) @@ -145,15 +146,11 @@ class ScriptCodegen private constructor( iv.load(0, classType) - fun Int.incrementIf(cond: Boolean): Int = if (cond) plus(1) else this - val valueParamStart = 1 - .incrementIf(scriptContext.earlierScripts.isNotEmpty()) - val valueParameters = scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters for (superclassParam in ctorDesc.valueParameters) { val valueParam = valueParameters.first { it.name == superclassParam.name } val paramType = typeMapper.mapType(valueParam.type) - iv.load(valueParam!!.index + valueParamStart, paramType) + iv.load(valueParam!!.index + scriptContext.ctorValueParametersStart + 1, paramType) frameMap.enterTemp(paramType) } @@ -167,21 +164,17 @@ class ScriptCodegen private constructor( } iv.load(0, classType) - if (scriptDefinition.implicitReceivers.isNotEmpty()) { + scriptDescriptor.implicitReceivers.forEachIndexed { receiverIndex, receiver -> val receiversParamIndex = frameMap.enterTemp(AsmUtil.getArrayType(OBJECT_TYPE)) - - scriptContext.receiverDescriptors.forEachIndexed { receiverIndex, receiver -> - val name = scriptContext.getImplicitReceiverName(receiverIndex) - genFieldFromArrayElement(receiver, receiversParamIndex, receiverIndex, name) - } + val name = scriptContext.getImplicitReceiverName(receiverIndex) + genFieldFromParam(typeMapper.mapClass(receiver), receiversParamIndex, name) } - if (scriptDefinition.environmentVariables.isNotEmpty()) { - val envParamIndex = frameMap.enterTemp(AsmTypes.OBJECT_TYPE) - val mapType = PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_IFACE_TYPE - iv.load(0, classType) - iv.load(envParamIndex, mapType) - iv.putfield(classType.internalName, PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_FIELD_NAME, mapType.descriptor) + scriptDescriptor.scriptEnvironmentProperties.forEachIndexed { envVarIndex, envVar -> + val fieldClassType = typeMapper.mapType(envVar) + val envVarParamIndex = frameMap.enterTemp(fieldClassType) + val name = scriptContext.getEnvironmentVarName(envVarIndex) + genFieldFromParam(fieldClassType, envVarParamIndex, name) } val codegen = ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this) @@ -216,12 +209,12 @@ class ScriptCodegen private constructor( null ) } - if (scriptContext.scriptDescriptor.scriptEnvironmentProperties.isNotEmpty()) { + for (envVarIndex in scriptDescriptor.scriptEnvironmentProperties.indices) { classBuilder.newField( NO_ORIGIN, ACC_PUBLIC or ACC_FINAL, - PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_FIELD_NAME, - PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_IFACE_TYPE.descriptor, + scriptContext.getEnvironmentVarName(envVarIndex), + scriptContext.getEnvironmentVarType(envVarIndex).descriptor, null, null ) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ScriptContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ScriptContext.kt index e953d5cef24..2422c6f95ae 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ScriptContext.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/ScriptContext.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentDescriptor import org.jetbrains.org.objectweb.asm.Type @@ -64,7 +65,16 @@ class ScriptContext( } } - fun getImplicitReceiverName(index: Int): String = "\$\$implicitReceiver$index" + val ctorValueParametersStart = if (earlierScripts.isNotEmpty()) 1 else 0 + + private val ctorImplicitReceiversParametersStart = + ctorValueParametersStart + (scriptDescriptor.getSuperClassNotAny()?.unsubstitutedPrimaryConstructor?.valueParameters?.size ?: 0) + + private val ctorEnvironmentVarsParametersStart = + ctorImplicitReceiversParametersStart + scriptDescriptor.implicitReceivers.size + + fun getImplicitReceiverName(index: Int): String = + scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters[ctorImplicitReceiversParametersStart + index].name.identifier fun getImplicitReceiverType(index: Int): Type? { val receivers = script.kotlinScriptDefinition.value.implicitReceivers @@ -72,6 +82,11 @@ class ScriptContext( return kClass?.java?.classId?.let(AsmUtil::asmTypeByClassId) } + fun getEnvironmentVarName(index: Int): String = + scriptDescriptor.unsubstitutedPrimaryConstructor.valueParameters[ctorEnvironmentVarsParametersStart + index].name.identifier + + fun getEnvironmentVarType(index: Int): Type = typeMapper.mapType(scriptDescriptor.scriptEnvironmentProperties[index].type) + fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue { if (thisOrOuterClass is ScriptEnvironmentDescriptor) { return prefix ?: StackValue.LOCAL_0 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyScriptClassMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyScriptClassMemberScope.kt index 9071174eff7..34fc5687e6f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyScriptClassMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyScriptClassMemberScope.kt @@ -22,10 +22,10 @@ import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.lazy.ResolveSession import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider -import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.KotlinTypeFactory import org.jetbrains.kotlin.types.typeUtil.asTypeProjection class LazyScriptClassMemberScope( @@ -39,16 +39,13 @@ class LazyScriptClassMemberScope( val baseClass = scriptDescriptor.baseClassDescriptor() val baseConstructorDescriptor = baseClass?.unsubstitutedPrimaryConstructor if (baseConstructorDescriptor != null) { - val builtIns = scriptDescriptor.builtIns - val implicitReceiversParamType = - if (scriptDescriptor.scriptDefinition().implicitReceivers.isEmpty()) null - else { - "implicitReceivers" to builtIns.array.substitute(builtIns.anyType)!! + val implicitReceiversParamTypes = + scriptDescriptor.implicitReceivers.mapIndexed { idx, receiver -> + "$IMPLICIT_RECEIVER_PARAM_NAME_PREFIX$idx" to receiver.defaultType } - val environmentVarsParamType = - if (scriptDescriptor.scriptDefinition().environmentVariables.isEmpty()) null - else { - "environmentVariables" to builtIns.map.substitute(builtIns.stringType, builtIns.nullableAnyType)!! + val environmentVarsParamTypes = + scriptDescriptor.scriptEnvironmentProperties.map { + it.name.identifier to it.type } val annotations = baseConstructorDescriptor.annotations val constructorDescriptor = ClassConstructorDescriptorImpl.create( @@ -56,7 +53,7 @@ class LazyScriptClassMemberScope( ) var paramsIndexBase = baseConstructorDescriptor.valueParameters.lastIndex + 1 val syntheticParameters = - listOf(implicitReceiversParamType, environmentVarsParamType).mapNotNull { param: Pair? -> + (implicitReceiversParamTypes + environmentVarsParamTypes).mapNotNull { param: Pair -> if (param == null) null else ValueParameterDescriptorImpl( constructorDescriptor, @@ -95,6 +92,10 @@ class LazyScriptClassMemberScope( override fun createPropertiesFromPrimaryConstructorParameters(name: Name, result: MutableSet) { } + + companion object { + const val IMPLICIT_RECEIVER_PARAM_NAME_PREFIX = "\$\$implicitReceiver" + } } private fun ClassDescriptor.substitute(vararg types: KotlinType): KotlinType? = diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/script/ScriptEnvironmentPropertyDescriptor.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/script/ScriptEnvironmentPropertyDescriptor.kt index d47fa889ee9..763e221a410 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/script/ScriptEnvironmentPropertyDescriptor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/script/ScriptEnvironmentPropertyDescriptor.kt @@ -22,8 +22,8 @@ class ScriptEnvironmentPropertyDescriptor( script, null, Annotations.EMPTY, - Modality.OPEN, - Visibilities.PUBLIC, + Modality.FINAL, + Visibilities.PRIVATE, isVar, name, CallableMemberDescriptor.Kind.SYNTHESIZED, diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt b/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt index 790a83f3d85..0339b8b9ddf 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt @@ -92,14 +92,10 @@ abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() { private fun runScript(scriptClass: Class<*>, receivers: List, environmentVars: Map, scriptParams: List): Any? { - val ctorParams = arrayListOf() - if (receivers.isNotEmpty()) { - ctorParams.add(receivers.toTypedArray()) - } - if (environmentVars.isNotEmpty()) { - ctorParams.add(environmentVars) - } + val ctorParams = arrayListOf() ctorParams.addAll(scriptParams) + ctorParams.addAll(receivers) + ctorParams.addAll(environmentVars.values) val constructor = scriptClass.constructors[0] return constructor.newInstance(*ctorParams.toTypedArray())