[K/JS] feat: eliminate usage of kotlin.reflection if there is just raw js class usage.
This commit is contained in:
@@ -734,10 +734,18 @@ private val blockDecomposerLoweringPhase = makeBodyLoweringPhase(
|
||||
prerequisite = setOf(typeOperatorLoweringPhase, suspendFunctionsLoweringPhase)
|
||||
)
|
||||
|
||||
private val jsClassUsageInReflectionPhase = makeBodyLoweringPhase(
|
||||
::JsClassUsageInReflectionLowering,
|
||||
name = "JsClassUsageInReflectionLowering",
|
||||
description = "[Optimization] Eliminate ClassReference and GetClassExpression usages in a simple case of usage raw js constructor",
|
||||
prerequisite = setOf(functionInliningPhase)
|
||||
)
|
||||
|
||||
private val classReferenceLoweringPhase = makeBodyLoweringPhase(
|
||||
::ClassReferenceLowering,
|
||||
name = "ClassReferenceLowering",
|
||||
description = "Handle class references"
|
||||
description = "Handle class references",
|
||||
prerequisite = setOf(jsClassUsageInReflectionPhase)
|
||||
)
|
||||
|
||||
private val primitiveCompanionLoweringPhase = makeBodyLoweringPhase(
|
||||
@@ -845,6 +853,7 @@ val loweringList = listOf<Lowering>(
|
||||
innerClassesLoweringPhase,
|
||||
innerClassesMemberBodyLoweringPhase,
|
||||
innerClassConstructorCallsLoweringPhase,
|
||||
jsClassUsageInReflectionPhase,
|
||||
propertiesLoweringPhase,
|
||||
primaryConstructorLoweringPhase,
|
||||
delegateToPrimaryConstructorLoweringPhase,
|
||||
|
||||
@@ -29,8 +29,8 @@ fun eliminateDeadDeclarations(
|
||||
context.configuration.getBoolean(JSConfigurationKeys.PRINT_REACHABILITY_INFO) ||
|
||||
java.lang.Boolean.getBoolean("kotlin.js.ir.dce.print.reachability.info")
|
||||
|
||||
val usefulDeclarations = JsUsefulDeclarationProcessor(context, printReachabilityInfo, removeUnusedAssociatedObjects)
|
||||
.collectDeclarations(allRoots)
|
||||
val usefulDeclarationProcessor = JsUsefulDeclarationProcessor(context, printReachabilityInfo, removeUnusedAssociatedObjects)
|
||||
val usefulDeclarations = usefulDeclarationProcessor.collectDeclarations(allRoots)
|
||||
|
||||
val uselessDeclarationsProcessor =
|
||||
UselessDeclarationsRemover(removeUnusedAssociatedObjects, usefulDeclarations, context, context.dceRuntimeDiagnostic)
|
||||
@@ -38,7 +38,7 @@ fun eliminateDeadDeclarations(
|
||||
modules.forEach { module ->
|
||||
module.files.forEach {
|
||||
it.acceptVoid(uselessDeclarationsProcessor)
|
||||
context.polyfills.saveOnlyIntersectionOfNextDeclarationsFor(it, usefulDeclarations)
|
||||
context.polyfills.saveOnlyIntersectionOfNextDeclarationsFor(it, usefulDeclarationProcessor.usefulPolyfilledDeclarations)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.invokeFunForLambda
|
||||
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.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
@@ -109,6 +110,7 @@ internal class JsUsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun processClass(irClass: IrClass) {
|
||||
|
||||
+14
-2
@@ -52,8 +52,10 @@ abstract class UsefulDeclarationProcessor(
|
||||
|
||||
override fun visitBlock(expression: IrBlock, data: IrDeclaration) {
|
||||
super.visitBlock(expression, data)
|
||||
if (expression !is IrReturnableBlock) return
|
||||
expression.inlineFunctionSymbol?.owner?.enqueue(data, "inline function usage")
|
||||
|
||||
if (expression is IrReturnableBlock) {
|
||||
expression.inlineFunctionSymbol?.owner?.addToUsefulPolyfilledDeclarations()
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFieldAccess(expression: IrFieldAccessExpression, data: IrDeclaration) {
|
||||
@@ -111,6 +113,14 @@ abstract class UsefulDeclarationProcessor(
|
||||
if (this !in result) {
|
||||
result.add(this)
|
||||
queue.addLast(this)
|
||||
|
||||
addToUsefulPolyfilledDeclarations()
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrDeclaration.addToUsefulPolyfilledDeclarations() {
|
||||
if (hasJsPolyfill() && this !in usefulPolyfilledDeclarations) {
|
||||
usefulPolyfilledDeclarations.add(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +138,8 @@ abstract class UsefulDeclarationProcessor(
|
||||
protected val result = hashSetOf<IrDeclaration>()
|
||||
protected val classesWithObjectAssociations = hashSetOf<IrClass>()
|
||||
|
||||
public val usefulPolyfilledDeclarations = hashSetOf<IrDeclaration>()
|
||||
|
||||
protected open fun processField(irField: IrField): Unit = Unit
|
||||
|
||||
protected open fun processClass(irClass: IrClass) {
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicMemberExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
private val JS_CLASS_GETTER = FqName("kotlin.js.<get-js>")
|
||||
|
||||
class JsClassUsageInReflectionLowering(val backendContext: JsIrBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
if (expression.origin != IrStatementOrigin.GET_PROPERTY || !expression.isGetJsCall()) {
|
||||
return super.visitCall(expression)
|
||||
}
|
||||
|
||||
return when (val extensionReceiver = expression.extensionReceiver) {
|
||||
is IrClassReference -> extensionReceiver.generateDirectValueUsage() ?: super.visitCall(expression)
|
||||
is IrGetClass -> extensionReceiver.generateDirectConstructorUsage()
|
||||
else -> super.visitCall(expression)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private fun IrClassReference.generateDirectValueUsage(): IrExpression? {
|
||||
return with(backendContext) {
|
||||
when(val classSymbol = symbol as? IrClassSymbol ?: return null) {
|
||||
irBuiltIns.nothingClass -> null
|
||||
irBuiltIns.anyClass ->
|
||||
JsIrBuilder.buildCall(intrinsics.jsCode).apply {
|
||||
putValueArgument(
|
||||
0,
|
||||
IrConstImpl.string(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
irBuiltIns.stringType,
|
||||
"Object"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
else ->
|
||||
JsIrBuilder.buildCall(intrinsics.jsClass, origin = JsStatementOrigins.CLASS_REFERENCE).apply {
|
||||
putTypeArgument(0, classSymbol.owner.defaultType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrGetClass.generateDirectConstructorUsage(): IrDynamicMemberExpression {
|
||||
return IrDynamicMemberExpressionImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
backendContext.dynamicType,
|
||||
"constructor",
|
||||
argument
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrCall.isGetJsCall(): Boolean {
|
||||
return symbol.owner.fqNameWhenAvailable == JS_CLASS_GETTER
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -128,8 +128,9 @@ 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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user