[K/JS] Make interface subtyping faster and lighter.
This commit is contained in:
@@ -8,12 +8,10 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
||||
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.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.isLong
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
@@ -109,6 +107,9 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
|
||||
// RTTI:
|
||||
val implementSymbol = getInternalFunction("implement")
|
||||
val setMetadataForSymbol = getInternalFunction("setMetadataFor")
|
||||
|
||||
val isInterfaceSymbol = getInternalFunction("isInterface")
|
||||
val isArraySymbol = getInternalFunction("isArray")
|
||||
// val isCharSymbol = getInternalFunction("isChar")
|
||||
|
||||
@@ -155,6 +155,7 @@ class JsIrBackendContext(
|
||||
|
||||
val dynamicType: IrDynamicType = IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT)
|
||||
val intrinsics: JsIntrinsics = JsIntrinsics(irBuiltIns, this)
|
||||
|
||||
override val reflectionSymbols: ReflectionSymbols get() = intrinsics.reflectionSymbols
|
||||
|
||||
override val propertyLazyInitialization: PropertyLazyInitialization = PropertyLazyInitialization(
|
||||
|
||||
@@ -526,7 +526,7 @@ private val privateMemberUsagesLoweringPhase = makeBodyLoweringPhase(
|
||||
private val propertyReferenceLoweringPhase = makeBodyLoweringPhase(
|
||||
::PropertyReferenceLowering,
|
||||
name = "PropertyReferenceLowering",
|
||||
description = "Transform property references"
|
||||
description = "Transform property references",
|
||||
)
|
||||
|
||||
private val interopCallableReferenceLoweringPhase = makeBodyLoweringPhase(
|
||||
@@ -669,7 +669,7 @@ private val typeOperatorLoweringPhase = makeBodyLoweringPhase(
|
||||
bridgesConstructionPhase,
|
||||
removeInlineDeclarationsWithReifiedTypeParametersLoweringPhase,
|
||||
singleAbstractMethodPhase, errorExpressionLoweringPhase,
|
||||
interopCallableReferenceLoweringPhase
|
||||
interopCallableReferenceLoweringPhase,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -705,7 +705,6 @@ private val constLoweringPhase = makeBodyLoweringPhase(
|
||||
name = "ConstLowering",
|
||||
description = "Wrap Long and Char constants into constructor invocation"
|
||||
)
|
||||
|
||||
private val inlineClassDeclarationLoweringPhase = makeDeclarationTransformerPhase(
|
||||
{ InlineClassLowering(it).inlineClassDeclarationLowering },
|
||||
name = "InlineClassDeclarationLowering",
|
||||
@@ -806,6 +805,7 @@ private val implicitlyExportedDeclarationsMarkingLowering = makeDeclarationTrans
|
||||
description = "Add @JsImplicitExport annotation to declarations which are not exported but are used inside other exported declarations as a type"
|
||||
)
|
||||
|
||||
|
||||
private val cleanupLoweringPhase = makeBodyLoweringPhase(
|
||||
{ CleanupLowering() },
|
||||
name = "CleanupLowering",
|
||||
|
||||
+34
-11
@@ -5,22 +5,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.dce
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.MethodsFromAnyGeneratorForLowerings.Companion.collectOverridenSymbols
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.associatedObject
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.invokeFunForLambda
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
|
||||
internal class JsUsefulDeclarationProcessor(
|
||||
@@ -33,6 +28,13 @@ internal class JsUsefulDeclarationProcessor(
|
||||
private val hashCodeMethod = getMethodOfAny("hashCode")
|
||||
|
||||
override val bodyVisitor: BodyVisitorBase = object : BodyVisitorBase() {
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: IrDeclaration) {
|
||||
if (expression.symbol != context.intrinsics.implementSymbol) {
|
||||
// Just ignore implement to not include large chunk of code inside small applications if it's not needed
|
||||
super.visitFunctionAccess(expression, data)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: IrDeclaration) {
|
||||
super.visitCall(expression, data)
|
||||
when (expression.symbol) {
|
||||
@@ -113,20 +115,41 @@ internal class JsUsefulDeclarationProcessor(
|
||||
|
||||
}
|
||||
|
||||
override fun processSuperTypes(irClass: IrClass) {
|
||||
irClass.superTypes.forEach {
|
||||
if (!it.isInterface()) {
|
||||
(it.classifierOrNull as? IrClassSymbol)?.owner?.enqueue(irClass, "superTypes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClass(irClass: IrClass) {
|
||||
super.processClass(irClass)
|
||||
|
||||
if (irClass.containsMetadata()) {
|
||||
when {
|
||||
irClass.isInterface -> context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
||||
irClass.isInterface -> {
|
||||
context.intrinsics.implementSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
}
|
||||
else -> context.intrinsics.metadataClassConstructorSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
|
||||
context.intrinsics.setMetadataForSymbol.owner.enqueue(irClass, "metadata")
|
||||
}
|
||||
}
|
||||
|
||||
override fun processSimpleFunction(irFunction: IrSimpleFunction) {
|
||||
super.processSimpleFunction(irFunction)
|
||||
|
||||
if (irFunction.isReal && irFunction.body != null) {
|
||||
irFunction.parentClassOrNull?.takeIf { it.isInterface }?.enqueue(irFunction, "interface default method is used")
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.containsMetadata(): Boolean =
|
||||
!isExternal && !isExpect && !isBuiltInClass(this)
|
||||
!isExternal && !isExpect && !isBuiltInClass(this)
|
||||
|
||||
override fun processConstructedClassDeclaration(declaration: IrDeclaration) {
|
||||
if (declaration in result) return
|
||||
|
||||
+9
-4
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isAssociatedObjectAnnotatedAnnot
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
@@ -138,14 +139,12 @@ abstract class UsefulDeclarationProcessor(
|
||||
protected val result = hashSetOf<IrDeclaration>()
|
||||
protected val classesWithObjectAssociations = hashSetOf<IrClass>()
|
||||
|
||||
public val usefulPolyfilledDeclarations = hashSetOf<IrDeclaration>()
|
||||
val usefulPolyfilledDeclarations = hashSetOf<IrDeclaration>()
|
||||
|
||||
protected open fun processField(irField: IrField): Unit = Unit
|
||||
|
||||
protected open fun processClass(irClass: IrClass) {
|
||||
irClass.superTypes.forEach {
|
||||
(it.classifierOrNull as? IrClassSymbol)?.owner?.enqueue(irClass, "superTypes")
|
||||
}
|
||||
processSuperTypes(irClass)
|
||||
|
||||
if (irClass.isObject && isExported(irClass)) {
|
||||
context.mapping.objectToGetInstanceFunction[irClass]
|
||||
@@ -161,6 +160,12 @@ abstract class UsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun processSuperTypes(irClass: IrClass) {
|
||||
irClass.superTypes.forEach {
|
||||
(it.classifierOrNull as? IrClassSymbol)?.owner?.enqueue(irClass, "superTypes")
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun processSimpleFunction(irFunction: IrSimpleFunction) {
|
||||
if (irFunction.isFakeOverride) {
|
||||
irFunction.resolveFakeOverride()?.enqueue(irFunction, "real overridden fun", isContagious = false)
|
||||
|
||||
+24
@@ -13,6 +13,11 @@ import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -24,6 +29,8 @@ class UselessDeclarationsRemover(
|
||||
private val context: JsIrBackendContext,
|
||||
private val dceRuntimeDiagnostic: RuntimeDiagnostic?,
|
||||
) : IrElementVisitorVoid {
|
||||
private val savedTypesCache = hashMapOf<IrClassSymbol, Set<IrClassSymbol>>()
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
@@ -47,6 +54,23 @@ class UselessDeclarationsRemover(
|
||||
if (removeUnusedAssociatedObjects && declaration.annotations.any { !it.shouldKeepAnnotation() }) {
|
||||
declaration.annotations = declaration.annotations.filter { it.shouldKeepAnnotation() }
|
||||
}
|
||||
|
||||
declaration.superTypes = declaration.superTypes
|
||||
.flatMap { it.classOrNull?.collectUsedSuperTypes() ?: emptyList() }
|
||||
.distinct()
|
||||
.map { it.defaultType }
|
||||
}
|
||||
|
||||
private fun IrClassSymbol.collectUsedSuperTypes(): Set<IrClassSymbol> {
|
||||
return savedTypesCache.getOrPut(this) {
|
||||
if (owner in usefulDeclarations) {
|
||||
setOf(this)
|
||||
} else {
|
||||
owner.superTypes
|
||||
.flatMap { it.takeIf { !it.isAny() }?.classOrNull?.collectUsedSuperTypes() ?: emptyList() }
|
||||
.toSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO bring back the primary constructor fix
|
||||
|
||||
+2
-2
@@ -128,8 +128,8 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue, context: JsGenerationContext): JsExpression {
|
||||
val obj = expression.symbol.owner
|
||||
|
||||
assert(obj.kind == ClassKind.OBJECT)
|
||||
assert(obj.isEffectivelyExternal()) { "Non external IrGetObjectValue must be lowered" }
|
||||
assert(obj.kind == ClassKind.OBJECT)
|
||||
assert(obj.isEffectivelyExternal()) { "Non external IrGetObjectValue must be lowered" }
|
||||
|
||||
return context.getRefForExternalClass(obj).withSource(expression, context)
|
||||
}
|
||||
|
||||
+1
-1
@@ -269,7 +269,7 @@ class IrModuleToJsTransformerTmp(
|
||||
|
||||
staticContext.classModels.entries.forEach { (symbol, model) ->
|
||||
result.classes[nameGenerator.getNameForClass(symbol.owner)] =
|
||||
JsIrIcClassModel(model.klass.superTypes.map { staticContext.getNameForClass((it.classifierOrFail as IrClassSymbol).owner) }).also {
|
||||
JsIrIcClassModel(model.superClasses.map { staticContext.getNameForClass(it.owner) }).also {
|
||||
it.preDeclarationBlock.statements += model.preDeclarationBlock.statements
|
||||
it.postDeclarationBlock.statements += model.postDeclarationBlock.statements
|
||||
}
|
||||
|
||||
+61
-66
@@ -6,27 +6,31 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isAllowedFakeOverriddenDeclaration
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||
|
||||
private val className = context.getNameForClass(irClass)
|
||||
private val classNameRef = className.makeRef()
|
||||
private val baseClass: IrType? = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
|
||||
@@ -44,6 +48,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
assert(!irClass.isExpect)
|
||||
|
||||
if (!es6mode) maybeGeneratePrimaryConstructor()
|
||||
|
||||
val transformer = IrDeclarationToJsTransformer()
|
||||
|
||||
// Properties might be lowered out of classes
|
||||
@@ -74,7 +79,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
} else {
|
||||
classBlock.statements += declaration.accept(transformer, context)
|
||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
}
|
||||
is IrSimpleFunction -> {
|
||||
@@ -104,8 +108,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
|
||||
classBlock.statements += generateClassMetadata()
|
||||
|
||||
if (!irClass.isInterface) {
|
||||
for (property in properties) {
|
||||
if (property.getter?.extensionReceiverParameter != null || property.setter?.extensionReceiverParameter != null)
|
||||
@@ -206,7 +208,11 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
classModel.preDeclarationBlock.statements += generateSetMetadataCall()
|
||||
|
||||
context.staticContext.classModels[irClass.symbol] = classModel
|
||||
|
||||
return classBlock
|
||||
}
|
||||
|
||||
@@ -307,24 +313,49 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
val func = JsFunction(emptyScope, JsBlock(), "Ctor for ${irClass.name}")
|
||||
func.name = className
|
||||
classBlock.statements += func.makeStmt()
|
||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateInheritanceCode(): List<JsStatement> {
|
||||
val baseClassPrototype = baseClassRef ?: return emptyList()
|
||||
private fun generateSetMetadataCall(): JsStatement {
|
||||
val setMetadataFor = context.staticContext.backendContext.intrinsics.setMetadataForSymbol.owner
|
||||
|
||||
val createCall = jsAssignment(
|
||||
classPrototypeRef, JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototypeOf(baseClassPrototype))
|
||||
val ctor = classNameRef
|
||||
val parent = baseClassRef
|
||||
val name = generateSimpleName()
|
||||
val interfaces = generateInterfacesList()
|
||||
val metadataConstructor = getMetadataConstructor()
|
||||
val associatedObjectKey = generateAssociatedObjectKey()
|
||||
val associatedObjects = generateAssociatedObjects()
|
||||
val suspendArity = generateSuspendArity()
|
||||
|
||||
return JsInvocation(
|
||||
JsNameRef(context.getNameForStaticFunction(setMetadataFor)),
|
||||
listOf(ctor, name, metadataConstructor, parent, interfaces, associatedObjectKey, associatedObjects, suspendArity)
|
||||
.dropLastWhile { it == null }
|
||||
.map { it ?: Namer.JS_UNDEFINED }
|
||||
).makeStmt()
|
||||
|
||||
val ctorAssign = jsAssignment(JsNameRef(Namer.CONSTRUCTOR_NAME, classPrototypeRef), classNameRef).makeStmt()
|
||||
|
||||
return listOf(createCall, ctorAssign)
|
||||
}
|
||||
|
||||
private fun generateClassMetadata(): JsStatement {
|
||||
val metadataConstructor = with(context.staticContext.backendContext.intrinsics) {
|
||||
|
||||
private fun IrType.asConstructorRef(): JsNameRef? {
|
||||
val ownerSymbol = classOrNull?.takeIf {
|
||||
!isAny() && !isFunctionType() && !it.owner.isEffectivelyExternal()
|
||||
} ?: return null
|
||||
|
||||
return JsNameRef(context.getNameForClass(ownerSymbol.owner))
|
||||
}
|
||||
|
||||
private fun IrType.isFunctionType() = isFunctionOrKFunction() || isSuspendFunctionOrKFunction()
|
||||
|
||||
private fun isCoroutineClass(): Boolean = irClass.superTypes.any { it.isSuspendFunctionTypeOrSubtype() }
|
||||
|
||||
private fun generateSimpleName(): JsStringLiteral? {
|
||||
return irClass.name.takeIf { !it.isSpecial }?.let { JsStringLiteral(it.identifier) }
|
||||
}
|
||||
|
||||
private fun getMetadataConstructor(): JsNameRef {
|
||||
val metadataConstructorSymbol = with(context.staticContext.backendContext.intrinsics) {
|
||||
when {
|
||||
irClass.isInterface -> metadataInterfaceConstructorSymbol
|
||||
irClass.isObject -> metadataObjectConstructorSymbol
|
||||
@@ -332,32 +363,21 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
|
||||
val simpleName = irClass.name
|
||||
.takeIf { !it.isSpecial }
|
||||
?.let { JsStringLiteral(it.identifier) }
|
||||
|
||||
val interfaces = generateSuperClasses()
|
||||
val associatedObjectKey = generateAssociatedObjectKey()
|
||||
val associatedObjects = generateAssociatedObjects()
|
||||
val fastPrototype = generateFastPrototype()
|
||||
val suspendArity = generateSuspendArity()
|
||||
|
||||
val constructorCall = JsInvocation(
|
||||
JsNameRef(context.getNameForStaticFunction(metadataConstructor.owner)),
|
||||
listOf(simpleName, interfaces, associatedObjectKey, associatedObjects, suspendArity, fastPrototype)
|
||||
.dropLastWhile { it == null }
|
||||
.map { it ?: Namer.JS_UNDEFINED }
|
||||
)
|
||||
|
||||
return jsAssignment(JsNameRef(Namer.METADATA, classNameRef), constructorCall).makeStmt()
|
||||
return JsNameRef(context.getNameForStaticFunction(metadataConstructorSymbol.owner))
|
||||
}
|
||||
|
||||
private fun isCoroutineClass(): Boolean = irClass.superTypes.any { it.isSuspendFunctionTypeOrSubtype() }
|
||||
private fun generateInterfacesList(): JsArrayLiteral? {
|
||||
val listRef = irClass.superTypes
|
||||
.filter { it.classOrNull?.owner?.isExternal != true }
|
||||
.takeIf { it.size > 1 || it.singleOrNull() != baseClass }
|
||||
?.mapNotNull { it.asConstructorRef() }
|
||||
?.takeIf { it.isNotEmpty() } ?: return null
|
||||
return JsArrayLiteral(listRef)
|
||||
}
|
||||
|
||||
private fun generateSuspendArity(): JsArrayLiteral? {
|
||||
if (!isCoroutineClass()) return null
|
||||
|
||||
val arity = context.staticContext.backendContext.mapping.suspendArityStore[irClass]!!
|
||||
val invokeFunctions = context.staticContext.backendContext.mapping.suspendArityStore[irClass] ?: return null
|
||||
val arity = invokeFunctions
|
||||
.map { it.valueParameters.size }
|
||||
.distinct()
|
||||
.map { JsIntLiteral(it) }
|
||||
@@ -365,30 +385,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
return JsArrayLiteral(arity)
|
||||
}
|
||||
|
||||
private fun generateSuperClasses(): JsArrayLiteral? {
|
||||
val parentSymbols = irClass.superTypes.mapNotNull {
|
||||
val symbol = it.classifierOrFail as IrClassSymbol
|
||||
val isFunctionType = it.isFunctionType()
|
||||
// TODO: make sure that there is a test which breaks when isExternal is used here instead of isEffectivelyExternal
|
||||
val requireInMetadata = if (context.staticContext.backendContext.baseClassIntoMetadata)
|
||||
!it.isAny()
|
||||
else
|
||||
symbol.isInterface
|
||||
|
||||
if (requireInMetadata && !isFunctionType && !symbol.isEffectivelyExternal) {
|
||||
symbol
|
||||
} else null
|
||||
}
|
||||
|
||||
return parentSymbols
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.run { JsArrayLiteral(map { JsNameRef(context.getNameForClass(it.owner)) }) }
|
||||
}
|
||||
|
||||
private fun generateFastPrototype() = baseClassRef?.let { prototypeOf(it) }
|
||||
|
||||
private fun IrType.isFunctionType() = isFunctionOrKFunction() || isSuspendFunctionOrKFunction()
|
||||
|
||||
private fun generateAssociatedObjectKey(): JsIntLiteral? {
|
||||
return context.getAssociatedObjectKey(irClass)?.let { JsIntLiteral(it) }
|
||||
}
|
||||
@@ -440,10 +436,9 @@ private fun IrOverridableDeclaration<*>.overridesExternal(): Boolean {
|
||||
}
|
||||
|
||||
private val IrClassifierSymbol.isInterface get() = (owner as? IrClass)?.isInterface == true
|
||||
private val IrClassifierSymbol.isEffectivelyExternal get() = (owner as? IrDeclaration)?.isEffectivelyExternal() == true
|
||||
|
||||
class JsIrClassModel(val klass: IrClass) {
|
||||
val superClasses = klass.superTypes.map { it.classifierOrFail as IrClassSymbol }
|
||||
val superClasses = klass.superTypes.map { it.classifierOrNull as IrClassSymbol }
|
||||
|
||||
val preDeclarationBlock = JsCompositeBlock()
|
||||
val postDeclarationBlock = JsCompositeBlock()
|
||||
|
||||
+1
-1
@@ -272,7 +272,7 @@ class Merger(
|
||||
|
||||
DFS.dfs(
|
||||
classModelMap.keys,
|
||||
{ klass -> classModelMap[klass]?.superClasses ?: emptyList() },
|
||||
{ classModelMap[it]?.superClasses ?: emptyList() },
|
||||
declarationHandler
|
||||
)
|
||||
}
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.declarations.IrOverridableDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -36,8 +37,8 @@ fun IrConstructorCall.getSingleConstStringArgument() =
|
||||
(getValueArgument(0) as IrConst<String>).value
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun IrConstructorCall.getSingleConstBooleanArgument() =
|
||||
(getValueArgument(0) as IrConst<Boolean>).value
|
||||
fun IrConstructorCall.getClassReferencVarargArguments() =
|
||||
(getValueArgument(0) as? IrVararg)?.elements as? List<IrClassReference>
|
||||
|
||||
fun IrAnnotationContainer.getJsModule(): String? =
|
||||
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
|
||||
|
||||
@@ -32,7 +32,7 @@ object Namer {
|
||||
val JS_OBJECT_CREATE_FUNCTION = JsNameRef("create", JS_OBJECT)
|
||||
|
||||
val METADATA = "\$metadata\$"
|
||||
val METADATA_INTERFACE_ID = "interfaceId"
|
||||
val INTERFACES_MASK = "\$imask\$"
|
||||
|
||||
val KCALLABLE_GET_NAME = "<get-name>"
|
||||
val KCALLABLE_NAME = "callableName"
|
||||
|
||||
Reference in New Issue
Block a user