JS: inline private properties

This commit is contained in:
Anton Bannykh
2018-12-23 21:27:57 +03:00
committed by Anton Bannykh
parent 50aeeee462
commit 9716abcc12
5 changed files with 245 additions and 8 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.inline.context
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.isCallableReference
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
@@ -83,11 +84,12 @@ class FunctionContext(
private val functionReader = FunctionReader(inliner.reporter, inliner.config, inliner.translationResult.innerModuleName)
private data class FunctionsAndAccessors(
private data class FragmentInfo(
val functions: Map<JsName, FunctionWithWrapper>,
val accessors: Map<String, FunctionWithWrapper>)
val accessors: Map<String, FunctionWithWrapper>,
val localAccessors: Map<CallableDescriptor, FunctionWithWrapper>)
private val fragmentInfo = mutableMapOf<JsProgramFragment, FunctionsAndAccessors>()
private val fragmentInfo = mutableMapOf<JsProgramFragment, FragmentInfo>()
private fun lookUpStaticFunction(functionName: JsName?, fragment: JsProgramFragment): FunctionWithWrapper? =
fragmentInfo[fragment]?.run { functions[functionName] }
@@ -104,6 +106,16 @@ class FunctionContext(
call.qualifier
}
call.descriptor?.let { descriptor ->
fragmentInfo[scope.fragment]?.let { info ->
info.localAccessors[descriptor]?.let { fn ->
return InlineFunctionDefinition(fn, null).also { def ->
inliner.process(def, call, scope)
}
}
}
}
/** process cases 2, 3 */
val qualifier = callQualifier.transitiveStaticRef
return when (qualifier) {
@@ -134,9 +146,10 @@ class FunctionContext(
private fun loadFragment(fragment: JsProgramFragment) {
fragmentInfo.computeIfAbsent(fragment) {
FunctionsAndAccessors(
FragmentInfo(
collectNamedFunctionsAndWrappers(listOf(fragment)),
collectAccessors(listOf(fragment))
collectAccessors(listOf(fragment)),
collectLocalFunctions(listOf(fragment))
).also { (functions, accessors) ->
(functions.values.asSequence() + accessors.values.asSequence()).forEach { f ->
functionsByFunctionNodes[f.function] = f
@@ -16,13 +16,12 @@
package org.jetbrains.kotlin.js.inline.util
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
import org.jetbrains.kotlin.js.backend.ast.metadata.functionDescriptor
import org.jetbrains.kotlin.js.backend.ast.metadata.imported
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.inline.util.collectors.InstanceCollector
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
@@ -248,6 +247,31 @@ fun collectAccessors(fragments: Iterable<JsProgramFragment>): Map<String, Functi
return result
}
fun collectLocalFunctions(scope: JsNode): Map<CallableDescriptor, FunctionWithWrapper> {
val localFunctions = hashMapOf<CallableDescriptor, FunctionWithWrapper>()
scope.accept(object : RecursiveJsVisitor() {
override fun visitInvocation(invocation: JsInvocation) {
InlineMetadata.tryExtractFunction(invocation)?.let {
it.function.functionDescriptor?.let { fd ->
localFunctions[fd] = it
}
}
super.visitInvocation(invocation)
}
})
return localFunctions
}
fun collectLocalFunctions(fragments: List<JsProgramFragment>): Map<CallableDescriptor, FunctionWithWrapper> {
val result = mutableMapOf<CallableDescriptor, FunctionWithWrapper>()
for (fragment in fragments) {
result += collectLocalFunctions(fragment.declarationBlock)
}
return result
}
fun extractFunction(expression: JsExpression) = when (expression) {
is JsFunction -> FunctionWithWrapper(expression, null)
else -> InlineMetadata.decompose(expression)?.function ?: InlineMetadata.tryExtractFunction(expression)
@@ -4110,6 +4110,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
runTest("js/js.translator/testData/box/inline/params.kt");
}
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("js/js.translator/testData/box/inline/privateProperty.kt");
}
@TestMetadata("rootConstructor.kt")
public void testRootConstructor() throws Exception {
runTest("js/js.translator/testData/box/inline/rootConstructor.kt");
@@ -4110,6 +4110,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/inline/params.kt");
}
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("js/js.translator/testData/box/inline/privateProperty.kt");
}
@TestMetadata("rootConstructor.kt")
public void testRootConstructor() throws Exception {
runTest("js/js.translator/testData/box/inline/rootConstructor.kt");
+190
View File
@@ -0,0 +1,190 @@
// EXPECTED_REACHABLE_NODES: 1288
package test
var a = 0
// CHECK_NOT_CALLED_IN_SCOPE: function=get_p1 scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p1 scope=box
private inline var p1: Int
get() = a + 10000
set(v) {
a = v + 100
}
// CHECK_NOT_CALLED_IN_SCOPE: function=get_p2 scope=box
// CHECK_CALLED_IN_SCOPE: function=set_p2 scope=box
private var p2: Int
inline get() = a + 20000
set(v) {
a = v + 200
}
// CHECK_CALLED_IN_SCOPE: function=get_p3 scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p3 scope=box
var p3: Int
get() = a + 30000
private inline set(v) {
a = v + 300
}
// CHECK_CALLED_IN_SCOPE: function=get_p4 scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p4 scope=box
private var p4: Int
get() = a + 40000
inline set(v) {
a = v + 400
}
// CHECK_NOT_CALLED_IN_SCOPE: function=get_p5 scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p5 scope=box
private inline var Int.p5: Int
get() = this * 100 + a + 50000
set(v) {
a = this + v + 500
}
// CHECK_NOT_CALLED_IN_SCOPE: function=get_p6 scope=box
// CHECK_CALLED_IN_SCOPE: function=set_p6 scope=box
private var Int.p6: Int
inline get() = this * 100 + a + 60000
set(v) {
a = this + v + 600
}
// CHECK_CALLED_IN_SCOPE: function=get_p7 scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p7 scope=box
var Int.p7: Int
get() = this * 100 + a + 70000
private inline set(v) {
a = this + v + 700
}
// CHECK_CALLED_IN_SCOPE: function=get_p8 scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p8 scope=box
private var Int.p8: Int
get() = this * 100 + a + 80000
inline set(v) {
a = this + v + 800
}
private class A {
// PROPERTY_NOT_USED: p9
inline var p9: Int
get() = a + 90000
set(v) {
a = v + 900
}
// PROPERTY_NOT_READ_FROM: p10
var p10: Int
inline get() = a + 100000
set(v) {
a = v + 1000
}
// PROPERTY_NOT_WRITTEN_TO: p11
var p11: Int
get() = a + 110000
inline set(v) {
a = v + 1100
}
// CHECK_NOT_CALLED_IN_SCOPE: function=get_p12_s8ev3n$ scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p12_dqglrj$ scope=box
inline var Int.p12: Int
get() = this * 100 + a + 120000
set(v) {
a = this + v + 1200
}
// CHECK_NOT_CALLED_IN_SCOPE: function=get_p13_s8ev3n$ scope=box
// CHECK_CALLED_IN_SCOPE: function=set_p13_dqglrj$ scope=box
var Int.p13: Int
inline get() = this * 100 + a + 130000
set(v) {
a = this + v + 1300
}
// CHECK_CALLED_IN_SCOPE: function=get_p14_s8ev3n$ scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p14_dqglrj$ scope=box
var Int.p14: Int
get() = this * 100 + a + 140000
inline set(v) {
a = this + v + 1400
}
}
// CHECK_NOT_CALLED_IN_SCOPE: function=get_p15 scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p15 scope=box
private inline var A.p15: Int
get() = a + 150000
set(v) {
a = v + 1500
}
// CHECK_NOT_CALLED_IN_SCOPE: function=get_p16 scope=box
// CHECK_CALLED_IN_SCOPE: function=set_p16 scope=box
private var A.p16: Int
inline get() = a + 160000
set(v) {
a = v + 1600
}
// CHECK_CALLED_IN_SCOPE: function=get_p17 scope=box
// CHECK_NOT_CALLED_IN_SCOPE: function=set_p17 scope=box
private var A.p17: Int
get() = a + 170000
inline set(v) {
a = v + 1700
}
fun box(): String {
p1 = 1
if (p1 != 10101) return "test1: $p1"
p2 = 2
if (p2 != 20202) return "test2: $p2"
p3 = 3
if (p3 != 30303) return "test3: $p3"
p4 = 4
if (p4 != 40404) return "test4: $p4"
5000000.p5 = 5
if (5000000.p5 != 505050505) return "test5: ${5000000.p5}"
6000000.p6 = 6
if (6000000.p6 != 606060606) return "test6: ${6000000.p6}"
7000000.p7 = 7
if (7000000.p7 != 707070707) return "test7: ${7000000.p7}"
8000000.p8 = 8
if (8000000.p8 != 808080808) return "test8: ${8000000.p8}"
val a = A()
a.p9 = 9
if (a.p9 != 90909) return "test9: ${a.p9}"
a.p10 = 10
if (a.p10 != 101010) return "test10: ${a.p10}"
a.p11 = 11
if (a.p11 != 111111) return "test11: ${a.p11}"
with (a) {
12000000.p12 = 12
if (12000000.p12 != 1212121212) return "test12: ${12000000.p12}"
13000000.p13 = 13
if (13000000.p13 != 1313131313) return "test13: ${13000000.p13}"
14000000.p14 = 14
if (14000000.p14 != 1414141414) return "test14: ${14000000.p14}"
}
a.p15 = 15
if (a.p15 != 151515) return "test15: ${a.p15}"
a.p16 = 16
if (a.p16 != 161616) return "test16: ${a.p16}"
a.p17 = 17
if (a.p17 != 171717) return "test17: ${a.p17}"
return "OK"
}