[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:
Roman Artemev
2019-07-10 13:50:33 +03:00
committed by romanart
parent f9336555da
commit 946bc75cda
4 changed files with 51 additions and 176 deletions
@@ -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)) }
@@ -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()
}
}
}
@@ -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))
}
@@ -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
}