[K/JS] Add VOID optimization on object properties + align with the optimization the JS Plain Object plugin

This commit is contained in:
Artem Kobzar
2024-01-19 13:03:06 +00:00
committed by Space Team
parent b2c30921e4
commit 7568ee5a79
14 changed files with 153 additions and 46 deletions
@@ -77,6 +77,7 @@ var JsFunction.functionDescriptor: FunctionDescriptor? by MetadataProperty(defau
*/
var JsReturn.returnTarget: FunctionDescriptor? by MetadataProperty(default = null)
var HasMetadata.constant: Boolean by MetadataProperty(default = false)
var HasMetadata.synthetic: Boolean by MetadataProperty(default = false)
var HasMetadata.isInlineClassBoxing: Boolean by MetadataProperty(default = false)
@@ -17,8 +17,9 @@
package org.jetbrains.kotlin.js.inline.clean
import org.jetbrains.kotlin.js.backend.ast.JsFunction
import org.jetbrains.kotlin.js.backend.ast.JsName
class FunctionPostProcessor(val root: JsFunction) {
class FunctionPostProcessor(val root: JsFunction, private val voidName: JsName? = null) {
val optimizations = listOf(
{ RedundantLabelRemoval(root.body).apply() },
{ EmptyStatementElimination(root.body).apply() },
@@ -32,7 +33,8 @@ class FunctionPostProcessor(val root: JsFunction) {
{ RedundantStatementElimination(root).apply() },
{ CoroutineStateElimination(root.body).apply() },
{ BoxingUnboxingElimination(root.body).apply() },
{ MoveTemporaryVariableDeclarationToAssignment(root.body).apply() }
{ MoveTemporaryVariableDeclarationToAssignment(root.body).apply() },
{ voidName?.let { VoidPropertiesElimination(root.body, voidName).apply() } ?: false }
)
// TODO: reduce to A || B, A && B if possible
@@ -17,10 +17,7 @@
package org.jetbrains.kotlin.js.inline.clean
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
import org.jetbrains.kotlin.js.backend.ast.metadata.imported
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
import org.jetbrains.kotlin.js.backend.ast.metadata.*
import org.jetbrains.kotlin.js.inline.util.collectFreeVariables
import org.jetbrains.kotlin.js.inline.util.collectLocalVariables
import org.jetbrains.kotlin.js.translate.context.Namer
@@ -481,8 +478,8 @@ internal class TemporaryVariableElimination(private val function: JsFunction) {
override fun visitNameRef(nameRef: JsNameRef) {
val name = nameRef.name
if (name != null && name in localVariables) {
if (name !in namesToSubstitute && shouldConsiderTemporary(name)) {
if (name != null && (name in localVariables || name.constant)) {
if (name.constant || (name !in namesToSubstitute && shouldConsiderTemporary(name))) {
if (!sideEffectOccurred) {
substitutableVariableReferences += name
}
@@ -637,16 +634,18 @@ internal class TemporaryVariableElimination(private val function: JsFunction) {
private fun isTrivial(expr: JsExpression): Boolean = when (expr) {
is JsNameRef -> {
val qualifier = expr.qualifier
if (expr.sideEffects == SideEffectKind.PURE && (qualifier == null || isTrivial(qualifier))) {
expr.name !in temporary
}
else {
val name = expr.name
name in localVariables && when (definitions[name]) {
// Local variables with zero definitions are function parameters. We can relocate and copy them.
null, 0 -> true
1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false
else -> false
when {
expr.name?.constant == true -> true
expr.sideEffects == SideEffectKind.PURE && (qualifier == null || isTrivial(qualifier)) ->
expr.name !in temporary
else -> {
val name = expr.name
name in localVariables && when (definitions[name]) {
// Local variables with zero definitions are function parameters. We can relocate and copy them.
null, 0 -> true
1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false
else -> false
}
}
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.inline.clean
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.isInlineClassBoxing
import org.jetbrains.kotlin.js.backend.ast.metadata.isInlineClassUnboxing
// Replaces { a: 2, b: VOID, c: VOID } with { a: 2 }
class VoidPropertiesElimination(private val root: JsBlock, private val voidName: JsName) {
private var changed = false
fun apply(): Boolean {
val visitor = object : JsVisitorWithContextImpl() {
override fun endVisit(x: JsPropertyInitializer, ctx: JsContext<JsNode>) {
super.endVisit(x, ctx)
if ((x.valueExpr as? JsNameRef)?.name === voidName) {
ctx.removeMe()
changed = true
}
}
}
visitor.accept(root)
return changed
}
}