Direct mapping of script implicit receivers and env vars to parameters

This commit is contained in:
Ilya Chernikov
2018-07-24 15:19:34 +02:00
parent e1ee31b4ce
commit ac65aebb19
6 changed files with 53 additions and 89 deletions
@@ -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();
@@ -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
)
@@ -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