[WASM] Implementation typeOf support

This commit is contained in:
Igor Yakovlev
2021-10-29 15:14:26 +02:00
committed by TeamCityServer
parent 39a389c49a
commit ee7f4c7278
31 changed files with 258 additions and 198 deletions
@@ -415,7 +415,7 @@ fun usefulDeclarations(
}
}
}
context.intrinsics.jsGetKClassFromExpression -> {
context.reflectionSymbols.getKClassFromExpression -> {
val ref = expression.getTypeArgument(0)?.classOrNull ?: context.irBuiltIns.anyClass
referencedJsClassesFromExpressions += ref.owner
}
@@ -30,16 +30,12 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
interface JsCommonBackendContext : CommonBackendContext {
override val mapping: JsMapping
val intrinsics: Intrinsics
val dynamicType: IrDynamicType
val reflectionSymbols: ReflectionSymbols
val inlineClassesUtils: InlineClassesUtils
val coroutineSymbols: JsCommonCoroutineSymbols
val primitiveClassesObject: IrClassSymbol
val catchAllThrowableType: IrType
get() = irBuiltIns.throwableType
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.IrBuiltIns
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.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.isLong
import org.jetbrains.kotlin.ir.util.constructors
@@ -21,21 +22,7 @@ import org.jetbrains.kotlin.psi2ir.findSingleFunction
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import java.util.*
interface Intrinsics {
val jsGetKClassFromExpression: IrSimpleFunctionSymbol
val jsGetKClass: IrSimpleFunctionSymbol
val jsClass: IrSimpleFunctionSymbol
val createKType: IrSimpleFunctionSymbol?
val createDynamicKType: IrSimpleFunctionSymbol?
val createKTypeParameter: IrSimpleFunctionSymbol?
val getStarKTypeProjection: IrSimpleFunctionSymbol?
val createCovariantKTypeProjection: IrSimpleFunctionSymbol?
val createInvariantKTypeProjection: IrSimpleFunctionSymbol?
val createContravariantKTypeProjection: IrSimpleFunctionSymbol?
val arrayLiteral: IrSimpleFunctionSymbol
}
class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendContext) : Intrinsics {
class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendContext) {
// TODO: Should we drop operator intrinsics in favor of IrDynamicOperatorExpression?
@@ -184,10 +171,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
val jsInvokeSuspendSuperTypeWithReceiverAndParam =
getInternalWithoutPackage("kotlin.coroutines.intrinsics.invokeSuspendSuperTypeWithReceiverAndParam")
override val jsGetKClass = getInternalWithoutPackage("getKClass")
override val jsGetKClassFromExpression = getInternalWithoutPackage("getKClassFromExpression")
override val jsClass = getInternalFunction("jsClassIntrinsic")
val jsNumberRangeToNumber = getInternalFunction("numberRangeToNumber")
val jsNumberRangeToLong = getInternalFunction("numberRangeToLong")
@@ -249,7 +232,25 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
val jsPrimitiveArrayIteratorFunctions =
PrimitiveType.values().associate { it to getInternalFunction("${it.typeName.asString().toLowerCaseAsciiOnly()}ArrayIterator") }
override val arrayLiteral = getInternalFunction("arrayLiteral")
val jsClass = getInternalFunction("jsClassIntrinsic")
val arrayLiteral: IrSimpleFunctionSymbol = getInternalFunction("arrayLiteral")
internal inner class JsReflectionSymbols : ReflectionSymbols {
override val createKType = getInternalWithoutPackageOrNull("createKType")
override val createDynamicKType = getInternalWithoutPackageOrNull("createDynamicKType")
override val createKTypeParameter = getInternalWithoutPackageOrNull("createKTypeParameter")
override val getStarKTypeProjection = getInternalWithoutPackageOrNull("getStarKTypeProjection")
override val createCovariantKTypeProjection = getInternalWithoutPackageOrNull("createCovariantKTypeProjection")
override val createInvariantKTypeProjection = getInternalWithoutPackageOrNull("createInvariantKTypeProjection")
override val createContravariantKTypeProjection = getInternalWithoutPackageOrNull("createContravariantKTypeProjection")
override val getKClass = getInternalWithoutPackage("getKClass")
override val getKClassFromExpression = getInternalWithoutPackage("getKClassFromExpression")
override val primitiveClassesObject = context.getIrClass(FqName("kotlin.reflect.js.internal.PrimitiveClasses"))
override val kTypeClass: IrClassSymbol = context.getIrClass(FqName("kotlin.reflect.KType"))
override val getClassData: IrSimpleFunctionSymbol get() = jsClass
}
internal val reflectionSymbols: JsReflectionSymbols = JsReflectionSymbols()
val primitiveToTypedArrayMap = EnumMap(
mapOf(
@@ -261,14 +262,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
)
)
override val createKType = getInternalWithoutPackageOrNull("createKType")
override val createDynamicKType = getInternalWithoutPackageOrNull("createDynamicKType")
override val createKTypeParameter = getInternalWithoutPackageOrNull("createKTypeParameter")
override val getStarKTypeProjection = getInternalWithoutPackageOrNull("getStarKTypeProjection")
override val createCovariantKTypeProjection = getInternalWithoutPackageOrNull("createCovariantKTypeProjection")
override val createInvariantKTypeProjection = getInternalWithoutPackageOrNull("createInvariantKTypeProjection")
override val createContravariantKTypeProjection = getInternalWithoutPackageOrNull("createContravariantKTypeProjection")
val primitiveToSizeConstructor =
PrimitiveType.values().associate { type ->
type to (primitiveToTypedArrayMap[type]?.let {
@@ -157,8 +157,9 @@ class JsIrBackendContext(
private val internalPackage = module.getPackage(JS_PACKAGE_FQNAME)
override val dynamicType: IrDynamicType = IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT)
override val intrinsics = JsIntrinsics(irBuiltIns, this)
val dynamicType: IrDynamicType = IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT)
val intrinsics: JsIntrinsics = JsIntrinsics(irBuiltIns, this)
override val reflectionSymbols: ReflectionSymbols get() = intrinsics.reflectionSymbols
override val catchAllThrowableType: IrType
get() = dynamicType
@@ -284,16 +285,12 @@ class JsIrBackendContext(
val errorCodeSymbol: IrSimpleFunctionSymbol? =
if (errorPolicy.allowErrors) symbolTable.referenceSimpleFunction(getJsInternalFunction("errorCode")) else null
override val primitiveClassesObject = getIrClass(FqName("kotlin.reflect.js.internal.PrimitiveClasses"))
val throwableClass = getIrClass(JsIrBackendContext.KOTLIN_PACKAGE_FQN.child(Name.identifier("Throwable")))
val primitiveCompanionObjects = primitivesWithImplicitCompanionObject().associateWith {
getIrClass(JS_INTERNAL_PACKAGE_FQNAME.child(Name.identifier("${it.identifier}CompanionObject")))
}
// Top-level functions forced to be loaded
@@ -355,7 +352,7 @@ class JsIrBackendContext(
internal fun getProperty(fqName: FqName): PropertyDescriptor =
findProperty(module.getPackage(fqName.parent()).memberScope, fqName.shortName()).single()
private fun getIrClass(fqName: FqName): IrClassSymbol = symbolTable.referenceClass(getClass(fqName))
internal fun getIrClass(fqName: FqName): IrClassSymbol = symbolTable.referenceClass(getClass(fqName))
internal fun getJsInternalFunction(name: String): SimpleFunctionDescriptor =
findFunctions(internalPackage.memberScope, Name.identifier(name)).singleOrNull() ?: error("Internal function '$name' not found")
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
interface ReflectionSymbols {
val getKClassFromExpression: IrSimpleFunctionSymbol
val getKClass: IrSimpleFunctionSymbol
val getClassData: IrSimpleFunctionSymbol
val createKType: IrSimpleFunctionSymbol?
val createDynamicKType: IrSimpleFunctionSymbol?
val createKTypeParameter: IrSimpleFunctionSymbol?
val getStarKTypeProjection: IrSimpleFunctionSymbol?
val createCovariantKTypeProjection: IrSimpleFunctionSymbol?
val createInvariantKTypeProjection: IrSimpleFunctionSymbol?
val createContravariantKTypeProjection: IrSimpleFunctionSymbol?
val primitiveClassesObject: IrClassSymbol
val kTypeClass: IrClassSymbol
}
@@ -8,9 +8,10 @@ package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.ir.createArrayOfExpression
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.toJsArrayLiteral
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
@@ -25,21 +26,22 @@ import org.jetbrains.kotlin.types.*
class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLoweringPass {
private val reflectionSymbols get() = context.reflectionSymbols
private val primitiveClassProperties by lazy {
primitiveClassesObject.owner.declarations.filterIsInstance<IrProperty>()
reflectionSymbols.primitiveClassesObject.owner.declarations.filterIsInstance<IrProperty>()
}
private val primitiveClassFunctionClass by lazy {
primitiveClassesObject.owner.declarations
reflectionSymbols.primitiveClassesObject.owner.declarations
.filterIsInstance<IrSimpleFunction>()
.find { it.name == Name.identifier("functionClass") }!!
}
private val primitiveClassesObject = context.primitiveClassesObject
private fun primitiveClassProperty(name: String) =
primitiveClassProperties.singleOrNull { it.name == Name.identifier(name) }?.getter
?: primitiveClassesObject.owner.declarations.filterIsInstance<IrSimpleFunction>().single { it.name == Name.special("<get-$name>") }
?: reflectionSymbols.primitiveClassesObject.owner.declarations
.filterIsInstance<IrSimpleFunction>().single { it.name == Name.special("<get-$name>") }
private val finalPrimitiveClasses by lazy {
mapOf(
@@ -80,14 +82,17 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
if (primitiveKClass != null)
return JsIrBuilder.buildBlock(returnType, listOf(argument, primitiveKClass))
return JsIrBuilder.buildCall(context.intrinsics.jsGetKClassFromExpression, returnType, listOf(typeArgument)).apply {
return JsIrBuilder.buildCall(reflectionSymbols.getKClassFromExpression, returnType, listOf(typeArgument)).apply {
putValueArgument(0, argument)
}
}
private fun getPrimitiveClass(target: IrSimpleFunction, returnType: IrType) =
JsIrBuilder.buildCall(target.symbol, returnType).apply {
dispatchReceiver = JsIrBuilder.buildGetObjectValue(primitiveClassesObject.defaultType, primitiveClassesObject)
dispatchReceiver = JsIrBuilder.buildGetObjectValue(
type = reflectionSymbols.primitiveClassesObject.defaultType,
classSymbol = reflectionSymbols.primitiveClassesObject
)
}
private fun getFinalPrimitiveKClass(returnType: IrType, typeArgument: IrType): IrCall? {
@@ -118,7 +123,7 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
}
private fun callGetKClass(
returnType: IrType = context.intrinsics.jsGetKClass.owner.returnType,
returnType: IrType = reflectionSymbols.getKClass.owner.returnType,
typeArgument: IrType
): IrCall {
val primitiveKClass =
@@ -127,15 +132,15 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
if (primitiveKClass != null)
return primitiveKClass
return JsIrBuilder.buildCall(context.intrinsics.jsGetKClass, returnType, listOf(typeArgument))
return JsIrBuilder.buildCall(reflectionSymbols.getKClass, returnType, listOf(typeArgument))
.apply {
putValueArgument(0, callJsClass(typeArgument))
putValueArgument(0, callGetClassByType(typeArgument))
}
}
private fun callJsClass(type: IrType) =
private fun callGetClassByType(type: IrType) =
JsIrBuilder.buildCall(
context.intrinsics.jsClass,
reflectionSymbols.getClassData,
typeArguments = listOf(type),
origin = JsLoweredDeclarationOrigin.CLASS_REFERENCE
)
@@ -157,7 +162,7 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
}
private fun createDynamicType(): IrExpression {
return buildCall(context.intrinsics.createDynamicKType!!)
return buildCall(reflectionSymbols.createDynamicKType!!)
}
private fun createSimpleKType(type: IrSimpleType, visitedTypeParams: MutableSet<IrTypeParameter>): IrExpression {
@@ -169,15 +174,16 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
// }
val kClassifier = createKClassifier(classifier, visitedTypeParams)
// TODO: Use static array types
val arguments = type.arguments.map { createKTypeProjection(it, visitedTypeParams) }.toJsArrayLiteral(
context,
context.dynamicType,
context.dynamicType
val arguments = context.createArrayOfExpression(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
arrayElementType = context.reflectionSymbols.kTypeClass.defaultType,
arrayElements = type.arguments.map { createKTypeProjection(it, visitedTypeParams) }
)
val isMarkedNullable = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, type.isMarkedNullable())
return buildCall(
context.intrinsics.createKType!!,
reflectionSymbols.createKType!!,
kClassifier,
arguments,
isMarkedNullable
@@ -186,13 +192,13 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
private fun createKTypeProjection(tp: IrTypeArgument, visitedTypeParams: MutableSet<IrTypeParameter>): IrExpression {
if (tp !is IrTypeProjection) {
return buildCall(context.intrinsics.getStarKTypeProjection!!)
return buildCall(reflectionSymbols.getStarKTypeProjection!!)
}
val factoryName = when (tp.variance) {
Variance.INVARIANT -> context.intrinsics.createInvariantKTypeProjection!!
Variance.IN_VARIANCE -> context.intrinsics.createContravariantKTypeProjection!!
Variance.OUT_VARIANCE -> context.intrinsics.createCovariantKTypeProjection!!
Variance.INVARIANT -> reflectionSymbols.createInvariantKTypeProjection!!
Variance.IN_VARIANCE -> reflectionSymbols.createContravariantKTypeProjection!!
Variance.OUT_VARIANCE -> reflectionSymbols.createCovariantKTypeProjection!!
}
val kType = createKType(tp.type, visitedTypeParams)
@@ -213,10 +219,12 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
visitedTypeParams.add(typeParameter)
val name = JsIrBuilder.buildString(context.irBuiltIns.stringType, typeParameter.name.asString())
val upperBounds = typeParameter.superTypes.map { createKType(it, visitedTypeParams) }.toJsArrayLiteral(
context,
context.dynamicType,
context.dynamicType
val upperBounds = context.createArrayOfExpression(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
arrayElementType = context.reflectionSymbols.kTypeClass.defaultType,
arrayElements = typeParameter.superTypes.map { createKType(it, visitedTypeParams) }
)
val variance = when (typeParameter.variance) {
@@ -231,7 +239,7 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
// }
return buildCall(
context.intrinsics.createKTypeParameter!!,
reflectionSymbols.createKTypeParameter!!,
name,
upperBounds,
variance
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.backend.js.utils.getClassRef
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -15,11 +14,9 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.getInlineClassBackingField
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.js.backend.ast.*
import java.lang.IllegalArgumentException
typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression
@@ -71,19 +71,6 @@ fun IrDeclaration.hasStaticDispatch() = when (this) {
else -> true
}
fun List<IrExpression>.toJsArrayLiteral(context: JsCommonBackendContext, arrayType: IrType, elementType: IrType): IrExpression {
val irVararg = IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, elementType, this)
return IrCallImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType,
context.intrinsics.arrayLiteral,
valueArgumentsCount = 1,
typeArgumentsCount = 0
).apply {
putValueArgument(0, irVararg)
}
}
val IrValueDeclaration.isDispatchReceiver: Boolean
get() {
val parent = this.parent