[JS IR BE] Code clean up
- Remove hacks for unbound symbols in TypeOperatorLowering - Replace hacker intrinsics with dynamic operations - Fix return type for `Object$create` intrinsic
This commit is contained in:
@@ -8,14 +8,16 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addTypeParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeBuilder
|
||||
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.isLong
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.findDeclaration
|
||||
@@ -86,14 +88,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val jsBitShiftRU = binOpInt("jsBitShiftRU")
|
||||
val jsBitShiftL = binOpInt("jsBitShiftL")
|
||||
|
||||
|
||||
// KFunction operations:
|
||||
|
||||
val jsName = unOp("kCallableName", irBuiltIns.string)
|
||||
val jsPropertyGet = binOp("kPropertyGet")
|
||||
val jsPropertySet = tripleOp("kPropertySet", irBuiltIns.unit)
|
||||
|
||||
|
||||
// Type checks:
|
||||
|
||||
val jsInstanceOf = binOpBool("jsInstanceOf")
|
||||
@@ -145,8 +139,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
// Other:
|
||||
|
||||
val jsObjectCreate = defineObjectCreateIntrinsic() // Object.create
|
||||
val jsGetJSField = defineGetJSPropertyIntrinsic() // TODO: Replace with dynamic operators
|
||||
val jsSetJSField = defineSetJSPropertyIntrinsic() // TODO: Replace with dynamic operators
|
||||
val jsCode = getInternalFunction("js") // js("<code>")
|
||||
val jsHashCode = getInternalFunction("hashCode")
|
||||
val jsGetObjectHashCode = getInternalFunction("getObjectHashCode")
|
||||
@@ -295,90 +287,42 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
// TODO: unify how we create intrinsic symbols
|
||||
private fun defineObjectCreateIntrinsic(): IrSimpleFunction {
|
||||
return JsIrBuilder.buildFunction(
|
||||
"Object\$create",
|
||||
returnType = irBuiltIns.anyType,
|
||||
parent = externalPackageFragment,
|
||||
isInline = true,
|
||||
return externalPackageFragment.addFunction {
|
||||
name = Name.identifier("Object\$create")
|
||||
origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB
|
||||
).also {
|
||||
val typeParameter = JsIrBuilder.buildTypeParameter(Name.identifier("T"), 0, true)
|
||||
typeParameter.parent = it
|
||||
typeParameter.superTypes += irBuiltIns.anyType
|
||||
it.typeParameters += typeParameter
|
||||
externalPackageFragment.declarations += it
|
||||
}.apply {
|
||||
returnType = addTypeParameter("T", irBuiltIns.anyType).defaultType
|
||||
}
|
||||
}
|
||||
|
||||
private fun defineGetJSPropertyIntrinsic() =
|
||||
JsIrBuilder.buildFunction(
|
||||
"\$getJSProperty\$",
|
||||
returnType = irBuiltIns.anyNType,
|
||||
parent = externalPackageFragment,
|
||||
private fun defineJsBindIntrinsic(): IrSimpleFunction {
|
||||
return externalPackageFragment.addFunction {
|
||||
name = Name.identifier("\$jsBind\$")
|
||||
origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB
|
||||
).also {
|
||||
listOf("receiver", "fieldName").mapIndexedTo(it.valueParameters) { i, p ->
|
||||
JsIrBuilder.buildValueParameter(p, i, irBuiltIns.anyType).also { v -> v.parent = it }
|
||||
}
|
||||
externalPackageFragment.declarations += it
|
||||
}
|
||||
|
||||
private fun defineJsBindIntrinsic() =
|
||||
JsIrBuilder.buildFunction(
|
||||
"\$jsBind\$",
|
||||
returnType = irBuiltIns.anyNType,
|
||||
parent = externalPackageFragment,
|
||||
origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB
|
||||
).also {
|
||||
listOf("receiver", "target").mapIndexedTo(it.valueParameters) { i, p ->
|
||||
JsIrBuilder.buildValueParameter(p, i, irBuiltIns.anyType).also { v -> v.parent = it }
|
||||
}
|
||||
externalPackageFragment.declarations += it
|
||||
returnType = irBuiltIns.anyNType
|
||||
}.apply {
|
||||
listOf("receiver", "target").forEach { addValueParameter(it, irBuiltIns.anyType) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun defineJsSliceIntrinsic(): IrSimpleFunction {
|
||||
val typeParameter = JsIrBuilder.buildTypeParameter(Name.identifier("A"), 0, true).apply {
|
||||
superTypes += irBuiltIns.anyType
|
||||
}
|
||||
val type = IrSimpleTypeBuilder().run {
|
||||
classifier = typeParameter.symbol
|
||||
buildSimpleType()
|
||||
}
|
||||
|
||||
return JsIrBuilder.buildFunction(
|
||||
"slice",
|
||||
returnType = type,
|
||||
parent = externalPackageFragment,
|
||||
return externalPackageFragment.addFunction {
|
||||
name = Name.identifier("slice")
|
||||
origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB
|
||||
).also {
|
||||
it.typeParameters += typeParameter.also { t -> t.parent = it }
|
||||
it.valueParameters += JsIrBuilder.buildValueParameter("a", 0, type).also { v -> v.parent = it }
|
||||
externalPackageFragment.declarations += it
|
||||
}.apply {
|
||||
val aType = addTypeParameter("A", irBuiltIns.anyType).defaultType
|
||||
returnType = aType
|
||||
addValueParameter("a", aType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun defineSetJSPropertyIntrinsic() =
|
||||
JsIrBuilder.buildFunction(
|
||||
"\$setJSProperty\$",
|
||||
returnType = irBuiltIns.unitType,
|
||||
parent = externalPackageFragment,
|
||||
private fun defineUnreachableIntrinsic(): IrSimpleFunction {
|
||||
return externalPackageFragment.addFunction {
|
||||
name = Name.identifier(Namer.UNREACHABLE_NAME)
|
||||
origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB
|
||||
).also {
|
||||
listOf("receiver", "fieldName", "fieldValue").mapIndexedTo(it.valueParameters) { i, p ->
|
||||
JsIrBuilder.buildValueParameter(p, i, irBuiltIns.anyType).also { v -> v.parent = it }
|
||||
}
|
||||
externalPackageFragment.declarations += it
|
||||
}
|
||||
|
||||
private fun defineUnreachableIntrinsic() =
|
||||
JsIrBuilder.buildFunction(
|
||||
Namer.UNREACHABLE_NAME,
|
||||
returnType = irBuiltIns.nothingType,
|
||||
parent = externalPackageFragment,
|
||||
origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB
|
||||
).also {
|
||||
externalPackageFragment.declarations += it
|
||||
returnType = irBuiltIns.nothingType
|
||||
}
|
||||
}
|
||||
|
||||
private fun unOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
|
||||
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN)) }
|
||||
|
||||
+22
-36
@@ -20,9 +20,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
||||
@@ -45,11 +43,7 @@ data class CallableReferenceKey(
|
||||
|
||||
// TODO: generate $metadata$ property and fill it with corresponding KFunction/KProperty interface
|
||||
class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val callableNameConst get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KCALLABLE_NAME)
|
||||
private val getterConst get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_GET)
|
||||
private val setterConst get() = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_SET)
|
||||
private val callableToFactoryFunction = context.callableReferencesCache
|
||||
|
||||
private val newDeclarations = mutableListOf<IrDeclaration>()
|
||||
private val implicitDeclarationFile = context.implicitDeclarationFile
|
||||
|
||||
@@ -170,11 +164,10 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
val irVar = JsIrBuilder.buildVar(irClosureReference.type, factoryFunction, initializer = irClosureReference)
|
||||
|
||||
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
|
||||
val irSetName = JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
|
||||
putValueArgument(1, callableNameConst)
|
||||
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration)))
|
||||
val irSetName = setDynamicProperty(irVar.symbol, Namer.KCALLABLE_NAME) {
|
||||
JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration))
|
||||
}
|
||||
|
||||
Pair(listOf(closureFunction, irVar, irSetName), irVar.symbol)
|
||||
}
|
||||
|
||||
@@ -221,10 +214,8 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
|
||||
statements += irVar
|
||||
|
||||
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
|
||||
putValueArgument(1, getterConst)
|
||||
putValueArgument(2, JsIrBuilder.buildGetValue(irVar.symbol))
|
||||
statements += setDynamicProperty(irVar.symbol, Namer.KPROPERTY_GET) {
|
||||
JsIrBuilder.buildGetValue(irVar.symbol)
|
||||
}
|
||||
|
||||
if (setterFunction != null) {
|
||||
@@ -232,22 +223,14 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
val setterFunctionTypeSymbol = context.ir.symbols.functionN(setterFunction.valueParameters.size + 1)
|
||||
val setterFunctionIrType = IrSimpleTypeImpl(setterFunctionTypeSymbol, false, emptyList(), emptyList())
|
||||
val irSetReference = JsIrBuilder.buildFunctionReference(setterFunctionIrType, setterFunction.symbol)
|
||||
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
|
||||
putValueArgument(1, setterConst)
|
||||
putValueArgument(2, irSetReference)
|
||||
}
|
||||
statements += setDynamicProperty(irVar.symbol, Namer.KPROPERTY_SET) { irSetReference }
|
||||
}
|
||||
|
||||
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
|
||||
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
|
||||
putValueArgument(1, callableNameConst)
|
||||
putValueArgument(
|
||||
2, JsIrBuilder.buildString(
|
||||
context.irBuiltIns.stringType,
|
||||
getReferenceName(getterDeclaration.correspondingPropertySymbol!!.owner)
|
||||
)
|
||||
statements += setDynamicProperty(irVar.symbol, Namer.KCALLABLE_NAME) {
|
||||
JsIrBuilder.buildString(
|
||||
context.irBuiltIns.stringType,
|
||||
getReferenceName(getterDeclaration.correspondingPropertySymbol!!.owner)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -291,16 +274,12 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
|
||||
statements += irVar
|
||||
|
||||
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
|
||||
putValueArgument(1, getterConst)
|
||||
putValueArgument(2, JsIrBuilder.buildGetValue(irVarSymbol))
|
||||
statements += setDynamicProperty(irVarSymbol, Namer.KPROPERTY_GET) {
|
||||
JsIrBuilder.buildGetValue(irVarSymbol)
|
||||
}
|
||||
|
||||
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
|
||||
putValueArgument(1, callableNameConst)
|
||||
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration)))
|
||||
statements += setDynamicProperty(irVarSymbol, Namer.KCALLABLE_NAME) {
|
||||
JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration))
|
||||
}
|
||||
|
||||
Pair(statements, irVarSymbol)
|
||||
@@ -572,4 +551,11 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
|
||||
return closureFunction
|
||||
}
|
||||
|
||||
private inline fun setDynamicProperty(r: IrValueSymbol, property: String, value: () -> IrExpression): IrStatement {
|
||||
return IrDynamicOperatorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, IrDynamicOperator.EQ).apply {
|
||||
receiver = IrDynamicMemberExpressionImpl(startOffset, endOffset, context.dynamicType, property, JsIrBuilder.buildGetValue(r))
|
||||
arguments += value()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-15
@@ -45,7 +45,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
private val isInterfaceSymbol get() = context.intrinsics.isInterfaceSymbol
|
||||
private val isArraySymbol get() = context.intrinsics.isArraySymbol
|
||||
private val isSuspenfFunctionSymbol = context.intrinsics.isSuspendFunctionSymbol
|
||||
private val isSuspendFunctionSymbol = context.intrinsics.isSuspendFunctionSymbol
|
||||
// private val isCharSymbol get() = context.intrinsics.isCharSymbol
|
||||
private val isObjectSymbol get() = context.intrinsics.isObjectSymbol
|
||||
|
||||
@@ -188,14 +188,6 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
}
|
||||
|
||||
private fun generateTypeCheck(argument: () -> IrExpressionWithCopy, toType: IrType): IrExpression {
|
||||
|
||||
// TODO: Fix unbound symbols (in inline)
|
||||
toType.classifierOrNull?.apply {
|
||||
if (!isBound) {
|
||||
return argument()
|
||||
}
|
||||
}
|
||||
|
||||
val toNotNullable = toType.makeNotNull()
|
||||
val argumentInstance = argument()
|
||||
val instanceCheck = generateTypeCheckNonNull(argumentInstance, toNotNullable)
|
||||
@@ -248,11 +240,6 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val typeParameterSymbol =
|
||||
(toType.classifierOrNull as? IrTypeParameterSymbol) ?: error("expected type parameter, but $toType")
|
||||
|
||||
// TODO: Stop creating unbound symbols inline:
|
||||
// DeepCopyIrTreeWithDescriptors.copy() -> ... -> ClassifierDescriptor.getSymbol()
|
||||
if (!typeParameterSymbol.isBound) {
|
||||
return argument
|
||||
}
|
||||
val typeParameter = typeParameterSymbol.owner
|
||||
|
||||
// TODO either remove functions with reified type parameters or support this case
|
||||
@@ -270,7 +257,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val arity = (toType.classifierOrFail.owner as IrClass).typeParameters.size - 1 // drop return type
|
||||
|
||||
val irBuiltIns = context.irBuiltIns
|
||||
return JsIrBuilder.buildCall(isSuspenfFunctionSymbol, irBuiltIns.booleanType).apply {
|
||||
return JsIrBuilder.buildCall(isSuspendFunctionSymbol, irBuiltIns.booleanType).apply {
|
||||
putValueArgument(0, argument)
|
||||
putValueArgument(1, JsIrBuilder.buildInt(irBuiltIns.intType, arity))
|
||||
}
|
||||
|
||||
+1
-43
@@ -87,27 +87,6 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
|
||||
}
|
||||
|
||||
add(intrinsics.jsGetJSField) { call, context ->
|
||||
val args = translateCallArguments(call, context)
|
||||
val receiver = args[0]
|
||||
val fieldName = args[1] as JsStringLiteral
|
||||
|
||||
val fieldNameLiteral = fieldName.value!!
|
||||
|
||||
JsNameRef(fieldNameLiteral, receiver)
|
||||
}
|
||||
|
||||
add(intrinsics.jsSetJSField) { call, context ->
|
||||
val args = translateCallArguments(call, context)
|
||||
val receiver = args[0]
|
||||
val fieldName = args[1] as JsStringLiteral
|
||||
val fieldValue = args[2]
|
||||
|
||||
val fieldNameLiteral = fieldName.value!!
|
||||
|
||||
jsAssignment(JsNameRef(fieldNameLiteral, receiver), fieldValue)
|
||||
}
|
||||
|
||||
add(intrinsics.jsClass) { call, context ->
|
||||
val classifier: IrClassifierSymbol = call.getTypeArgument(0)!!.classifierOrFail
|
||||
val owner = classifier.owner
|
||||
@@ -126,32 +105,11 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
|
||||
when (jsCode) {
|
||||
is JsExpression -> jsCode
|
||||
// TODO don't generate function for this case
|
||||
// TODO don't generate function for this case
|
||||
else -> JsInvocation(JsFunction(emptyScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), ""))
|
||||
}
|
||||
}
|
||||
|
||||
add(intrinsics.jsName) { call, context ->
|
||||
val args = translateCallArguments(call, context)
|
||||
val receiver = args[0]
|
||||
JsNameRef(Namer.KCALLABLE_NAME, receiver)
|
||||
}
|
||||
|
||||
add(intrinsics.jsPropertyGet) { call, context ->
|
||||
val args = translateCallArguments(call, context)
|
||||
val reference = args[0]
|
||||
val receiver = args[1]
|
||||
JsInvocation(JsNameRef(Namer.KPROPERTY_GET, reference), listOf(receiver))
|
||||
}
|
||||
|
||||
add(intrinsics.jsPropertySet) { call, context ->
|
||||
val args = translateCallArguments(call, context)
|
||||
val reference = args[0]
|
||||
val receiver = args[1]
|
||||
val value = args[2]
|
||||
JsInvocation(JsNameRef(Namer.KPROPERTY_SET, reference), listOf(receiver, value))
|
||||
}
|
||||
|
||||
add(intrinsics.jsGetContinuation) { _, context: JsGenerationContext ->
|
||||
context.continuation
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user