[JS IR BE] support CharSequence and String methods

This commit is contained in:
Anton Bannykh
2018-09-19 17:09:26 +03:00
parent 3e90d367f2
commit beaf6df8c5
40 changed files with 67 additions and 42 deletions
@@ -9,9 +9,12 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.findSingleFunction
@@ -219,6 +222,20 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
val jsArraySlice = unOp("slice")
// TODO move to IntrinsifyCallsLowering
val doNotIntrinsifyAnnotationSymbol = context.symbolTable.referenceClass(context.getInternalClass("DoNotIntrinsify"))
// TODO move CharSequence-related stiff to IntrinsifyCallsLowering
val charSequenceClassSymbol = context.symbolTable.referenceClass(context.getClass(FqName("kotlin.CharSequence")))
val charSequenceLengthPropertyGetterSymbol = charSequenceClassSymbol.owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "length" }.getter!!.symbol
val charSequenceGetFunctionSymbol = charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "get"}.symbol
val charSequenceSubSequenceFunctionSymbol = charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "subSequence"}.symbol
val jsCharSequenceGet = getInternalFunction("charSequenceGet")
val jsCharSequenceLength = getInternalFunction("charSequenceLength")
val jsCharSequenceSubSequence = getInternalFunction("charSequenceSubSequence")
// Helpers:
private fun getInternalFunction(name: String) =
@@ -162,6 +162,13 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
}
add(context.irBuiltIns.stringClass.lengthProperty, context.intrinsics.jsArrayLength, true)
add(context.irBuiltIns.stringClass.getFunction, intrinsics.jsCharSequenceGet.owner, true)
add(context.irBuiltIns.stringClass.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "subSequence"}.symbol,
intrinsics.jsCharSequenceSubSequence.owner, true)
add(intrinsics.charSequenceLengthPropertyGetterSymbol, intrinsics.jsCharSequenceLength.owner, true)
add(intrinsics.charSequenceGetFunctionSymbol, intrinsics.jsCharSequenceGet.owner, true)
add(intrinsics.charSequenceSubSequenceFunctionSymbol, intrinsics.jsCharSequenceSubSequence.owner, true)
}
memberToTransformer.run {
@@ -352,6 +359,10 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
val symbol = call.symbol
val declaration = symbol.owner
if (declaration.annotations.any { it.superQualifierSymbol == intrinsics.doNotIntrinsifyAnnotationSymbol }) {
return call
}
if (declaration.isDynamic() || declaration.isEffectivelyExternal()) {
when (call.origin) {
IrStatementOrigin.GET_PROPERTY -> {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
val cs: CharSequence = "abcd"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
val xs = "abcd"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
val xs = "abcd"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
val xs = "abcd"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME
// COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// DONT_RUN_GENERATED_CODE: JS
fun escapeChar(c : Char) : String? = when (c) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun StringBuilder.first() = this.get(0)
fun foo() = StringBuilder("foo").first()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
val list = ArrayList<String>()
list.add("0")
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
val c: Char? = '0'
c!!.toInt()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
val s: String? = "abc"
val c = s?.get(0)!! - 'b'
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun foo(i : Int?, a : Any?) {
i?.plus(1)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME
@@ -1,9 +1,6 @@
// TODO: muted automatically, investigate should it be ran for JVM_IR or not
// IGNORE_BACKEND: JVM_IR
// TODO: muted automatically, investigate should it be ran for JS_IR or not
// IGNORE_BACKEND: JS_IR
// Auto-generated by org.jetbrains.kotlin.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
fun test(s: CharSequence): Int {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.assertEquals
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
import kotlin.test.*
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
fun box(): String {
@@ -1,9 +1,6 @@
// TODO: muted automatically, investigate should it be ran for JVM_IR or not
// IGNORE_BACKEND: JVM_IR
// TODO: muted automatically, investigate should it be ran for JS_IR or not
// IGNORE_BACKEND: JS_IR
// Auto-generated by org.jetbrains.kotlin.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
// WITH_RUNTIME
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// WITH_RUNTIME
fun foo(): Int {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
class Thing(delegate: CharSequence) : CharSequence by delegate
fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
val sb = StringBuilder("OK")
return "${sb.get(0)}${sb[1]}"
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// KT-5956 java.lang.AbstractMethodError: test.Thing.subSequence(II)Ljava/lang/CharSequence
class Thing(val delegate: CharSequence) : CharSequence {
@@ -122,8 +122,7 @@ public class GenerateRangesCodegenTestData {
private static final List<String> IGNORED_FOR_JS_BACKEND = Collections.emptyList();
private static final List<String> IGNORED_FOR_JS_IR_BACKEND = Arrays.asList("inexactDownToMinValue.kt",
"inexactToMaxValue.kt",
"simpleRangeWithNonConstantEnds.kt");
"inexactToMaxValue.kt");
private static final List<String> IGNORED_FOR_NATIVE_BACKEND = Collections.emptyList();
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1230
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1250
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1286
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// See KT-8005
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1300
/*
* Copy of JVM-backend test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1303
/*
* Copy of JVM-backend test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1524
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1288
var log = ""
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package kotlin.js
internal annotation class DoNotIntrinsify
@PublishedApi
@DoNotIntrinsify
internal fun charSequenceGet(a: CharSequence, index: Int): Char {
return if (a is String) {
Char(a.asDynamic().charCodeAt(index).unsafeCast<Int>())
} else {
a[index]
}
}
@PublishedApi
@DoNotIntrinsify
internal fun charSequenceLength(a: CharSequence): Int {
return if (a is String) {
a.asDynamic().length.unsafeCast<Int>()
} else {
a.length
}
}
@PublishedApi
@DoNotIntrinsify
internal fun charSequenceSubSequence(a: CharSequence, startIndex: Int, endIndex: Int): CharSequence {
return if (a is String) {
a.asDynamic().substring(startIndex, endIndex).unsafeCast<String>()
} else {
a.subSequence(startIndex, endIndex)
}
}