Implement inlining of Array constructor in JS BE
See KT-15456
This commit is contained in:
@@ -1,6 +1,3 @@
|
|||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
|
||||||
// IGNORE_BACKEND: JS
|
|
||||||
|
|
||||||
fun testArray() {
|
fun testArray() {
|
||||||
Array<String>(5) { i ->
|
Array<String>(5) { i ->
|
||||||
if (i == 3) return
|
if (i == 3) return
|
||||||
@@ -17,8 +14,44 @@ fun testIntArray() {
|
|||||||
throw AssertionError()
|
throw AssertionError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testLongArray() {
|
||||||
|
LongArray(5) { i ->
|
||||||
|
if (i == 3) return
|
||||||
|
i.toLong()
|
||||||
|
}
|
||||||
|
throw AssertionError()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testBooleanArray() {
|
||||||
|
BooleanArray(5) { i ->
|
||||||
|
if (i == 3) return
|
||||||
|
i % 2 == 0
|
||||||
|
}
|
||||||
|
throw AssertionError()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testCharArray() {
|
||||||
|
CharArray(5) { i ->
|
||||||
|
if (i == 3) return
|
||||||
|
i.toChar()
|
||||||
|
}
|
||||||
|
throw AssertionError()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFloatArray() {
|
||||||
|
FloatArray(5) { i ->
|
||||||
|
if (i == 3) return
|
||||||
|
i.toFloat()
|
||||||
|
}
|
||||||
|
throw AssertionError()
|
||||||
|
}
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
testArray()
|
testArray()
|
||||||
testIntArray()
|
testIntArray()
|
||||||
|
testLongArray()
|
||||||
|
testBooleanArray()
|
||||||
|
testCharArray()
|
||||||
|
testFloatArray()
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.js.inline.util.IdentitySet
|
|||||||
import org.jetbrains.kotlin.js.inline.util.isCallInvocation
|
import org.jetbrains.kotlin.js.inline.util.isCallInvocation
|
||||||
import org.jetbrains.kotlin.js.parser.parseFunction
|
import org.jetbrains.kotlin.js.parser.parseFunction
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator
|
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
||||||
@@ -143,7 +142,7 @@ class FunctionReader(private val config: JsConfig, private val currentModuleName
|
|||||||
|
|
||||||
private fun readFunctionFromSource(descriptor: CallableDescriptor, info: ModuleInfo): JsFunction? {
|
private fun readFunctionFromSource(descriptor: CallableDescriptor, info: ModuleInfo): JsFunction? {
|
||||||
val source = info.fileContent
|
val source = info.fileContent
|
||||||
val tag = Namer.getFunctionTag(descriptor)
|
val tag = Namer.getFunctionTag(descriptor, config)
|
||||||
val index = source.indexOf(tag)
|
val index = source.indexOf(tag)
|
||||||
if (index < 0) return null
|
if (index < 0) return null
|
||||||
|
|
||||||
@@ -174,8 +173,6 @@ private fun JsFunction.markInlineArguments(descriptor: CallableDescriptor) {
|
|||||||
val offset = if (descriptor.isExtension) 1 else 0
|
val offset = if (descriptor.isExtension) 1 else 0
|
||||||
|
|
||||||
for ((i, param) in params.withIndex()) {
|
for ((i, param) in params.withIndex()) {
|
||||||
if (!CallExpressionTranslator.shouldBeInlined(descriptor)) continue
|
|
||||||
|
|
||||||
val type = param.type
|
val type = param.type
|
||||||
if (!type.isFunctionTypeOrSubtype) continue
|
if (!type.isFunctionTypeOrSubtype) continue
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.flattenStatemen
|
|||||||
|
|
||||||
public class JsInliner extends JsVisitorWithContextImpl {
|
public class JsInliner extends JsVisitorWithContextImpl {
|
||||||
|
|
||||||
|
private final JsConfig config;
|
||||||
private final Map<JsName, JsFunction> functions;
|
private final Map<JsName, JsFunction> functions;
|
||||||
private final Map<String, JsFunction> accessors;
|
private final Map<String, JsFunction> accessors;
|
||||||
private final Stack<JsInliningContext> inliningContexts = new Stack<>();
|
private final Stack<JsInliningContext> inliningContexts = new Stack<>();
|
||||||
@@ -76,7 +77,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
accessorInvocationTransformer.accept(fragment.getInitializerBlock());
|
accessorInvocationTransformer.accept(fragment.getInitializerBlock());
|
||||||
}
|
}
|
||||||
FunctionReader functionReader = new FunctionReader(config, currentModuleName, fragments);
|
FunctionReader functionReader = new FunctionReader(config, currentModuleName, fragments);
|
||||||
JsInliner inliner = new JsInliner(functions, accessors, functionReader, trace);
|
JsInliner inliner = new JsInliner(config, functions, accessors, functionReader, trace);
|
||||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||||
inliner.inliningContexts.push(inliner.new JsInliningContext());
|
inliner.inliningContexts.push(inliner.new JsInliningContext());
|
||||||
inliner.accept(fragment.getDeclarationBlock());
|
inliner.accept(fragment.getDeclarationBlock());
|
||||||
@@ -92,11 +93,13 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JsInliner(
|
private JsInliner(
|
||||||
|
@NotNull JsConfig config,
|
||||||
@NotNull Map<JsName, JsFunction> functions,
|
@NotNull Map<JsName, JsFunction> functions,
|
||||||
@NotNull Map<String, JsFunction> accessors,
|
@NotNull Map<String, JsFunction> accessors,
|
||||||
@NotNull FunctionReader functionReader,
|
@NotNull FunctionReader functionReader,
|
||||||
@NotNull DiagnosticSink trace
|
@NotNull DiagnosticSink trace
|
||||||
) {
|
) {
|
||||||
|
this.config = config;
|
||||||
this.functions = functions;
|
this.functions = functions;
|
||||||
this.accessors = accessors;
|
this.accessors = accessors;
|
||||||
this.functionReader = functionReader;
|
this.functionReader = functionReader;
|
||||||
@@ -285,7 +288,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
private final FunctionContext functionContext;
|
private final FunctionContext functionContext;
|
||||||
|
|
||||||
JsInliningContext() {
|
JsInliningContext() {
|
||||||
functionContext = new FunctionContext(functionReader) {
|
functionContext = new FunctionContext(functionReader, config) {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected JsFunction lookUpStaticFunction(@Nullable JsName functionName) {
|
protected JsFunction lookUpStaticFunction(@Nullable JsName functionName) {
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ package org.jetbrains.kotlin.js.inline.context
|
|||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.isCallableReference
|
import org.jetbrains.kotlin.js.backend.ast.metadata.isCallableReference
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
|
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
|
||||||
|
import org.jetbrains.kotlin.js.config.JsConfig
|
||||||
import org.jetbrains.kotlin.js.inline.FunctionReader
|
import org.jetbrains.kotlin.js.inline.FunctionReader
|
||||||
import org.jetbrains.kotlin.js.inline.util.*
|
import org.jetbrains.kotlin.js.inline.util.*
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
|
|
||||||
abstract class FunctionContext(private val functionReader: FunctionReader) {
|
abstract class FunctionContext(private val functionReader: FunctionReader, private val config: JsConfig) {
|
||||||
protected abstract fun lookUpStaticFunction(functionName: JsName?): JsFunction?
|
protected abstract fun lookUpStaticFunction(functionName: JsName?): JsFunction?
|
||||||
|
|
||||||
protected abstract fun lookUpStaticFunctionByTag(functionTag: String): JsFunction?
|
protected abstract fun lookUpStaticFunctionByTag(functionTag: String): JsFunction?
|
||||||
@@ -70,7 +71,7 @@ abstract class FunctionContext(private val functionReader: FunctionReader) {
|
|||||||
val descriptor = call.descriptor
|
val descriptor = call.descriptor
|
||||||
if (descriptor != null) {
|
if (descriptor != null) {
|
||||||
if (descriptor in functionReader) return functionReader[descriptor]
|
if (descriptor in functionReader) return functionReader[descriptor]
|
||||||
lookUpStaticFunctionByTag(Namer.getFunctionTag(descriptor))?.let { return it }
|
lookUpStaticFunctionByTag(Namer.getFunctionTag(descriptor, config))?.let { return it }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** remove ending `()` */
|
/** remove ending `()` */
|
||||||
|
|||||||
@@ -16,16 +16,17 @@
|
|||||||
|
|
||||||
// a package is omitted to get declarations directly under the module
|
// a package is omitted to get declarations directly under the module
|
||||||
|
|
||||||
external private fun <T> Array(size: Int): Array<T>
|
@PublishedApi
|
||||||
|
external internal fun <T> Array(size: Int): Array<T>
|
||||||
|
|
||||||
@JsName("newArray")
|
@JsName("newArray")
|
||||||
fun <T> newArray(size: Int, initValue: T) = fillArrayVal(Array<T>(size), initValue)
|
fun <T> newArray(size: Int, initValue: T) = fillArrayVal(Array<T>(size), initValue)
|
||||||
|
|
||||||
@JsName("newArrayF")
|
@JsName("newArrayF")
|
||||||
fun <T> arrayWithFun(size: Int, init: (Int) -> T) = fillArrayFun(Array<T>(size), init)
|
inline fun <T> arrayWithFun(size: Int, init: (Int) -> T) = fillArrayFun(Array<T>(size), init)
|
||||||
|
|
||||||
@JsName("fillArray")
|
@JsName("fillArray")
|
||||||
fun <T> fillArrayFun(array: Array<T>, init: (Int) -> T): Array<T> {
|
inline fun <T> fillArrayFun(array: Array<T>, init: (Int) -> T): Array<T> {
|
||||||
for (i in 0..array.size - 1) {
|
for (i in 0..array.size - 1) {
|
||||||
array[i] = init(i)
|
array[i] = init(i)
|
||||||
}
|
}
|
||||||
@@ -43,6 +44,9 @@ fun booleanArray(size: Int, init: dynamic): Array<Boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsName("booleanArrayF")
|
||||||
|
inline fun booleanArrayWithFun(size: Int, init: (Int) -> Boolean): Array<Boolean> = fillArrayFun(booleanArray(size, false), init)
|
||||||
|
|
||||||
@JsName("charArray")
|
@JsName("charArray")
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun charArray(size: Int, init: dynamic): Array<Char> {
|
fun charArray(size: Int, init: dynamic): Array<Char> {
|
||||||
@@ -54,6 +58,9 @@ fun charArray(size: Int, init: dynamic): Array<Char> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsName("charArrayF")
|
||||||
|
inline fun charArrayWithFun(size: Int, init: (Int) -> Char): Array<Char> = fillArrayFun(charArray(size, null), init)
|
||||||
|
|
||||||
@JsName("longArray")
|
@JsName("longArray")
|
||||||
fun longArray(size: Int, init: dynamic): Array<Long> {
|
fun longArray(size: Int, init: dynamic): Array<Long> {
|
||||||
val result: dynamic = Array<Long>(size)
|
val result: dynamic = Array<Long>(size)
|
||||||
@@ -65,6 +72,9 @@ fun longArray(size: Int, init: dynamic): Array<Long> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsName("longArrayF")
|
||||||
|
inline fun longArrayWithFun(size: Int, init: (Int) -> Long): Array<Long> = fillArrayFun(longArray(size, false), init)
|
||||||
|
|
||||||
private fun <T> fillArrayVal(array: Array<T>, initValue: T): Array<T> {
|
private fun <T> fillArrayVal(array: Array<T>, initValue: T): Array<T> {
|
||||||
for (i in 0..array.size - 1) {
|
for (i in 0..array.size - 1) {
|
||||||
array[i] = initValue
|
array[i] = initValue
|
||||||
|
|||||||
+1
-7
@@ -788,13 +788,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
@TestMetadata("nonLocalReturnArrayConstructor.kt")
|
@TestMetadata("nonLocalReturnArrayConstructor.kt")
|
||||||
public void testNonLocalReturnArrayConstructor() throws Exception {
|
public void testNonLocalReturnArrayConstructor() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/nonLocalReturnArrayConstructor.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/nonLocalReturnArrayConstructor.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("nonNullArray.kt")
|
@TestMetadata("nonNullArray.kt")
|
||||||
|
|||||||
+1
-7
@@ -417,13 +417,7 @@ public class JsTypedArraysBoxTestGenerated extends AbstractJsTypedArraysBoxTest
|
|||||||
@TestMetadata("nonLocalReturnArrayConstructor.kt")
|
@TestMetadata("nonLocalReturnArrayConstructor.kt")
|
||||||
public void testNonLocalReturnArrayConstructor() throws Exception {
|
public void testNonLocalReturnArrayConstructor() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/nonLocalReturnArrayConstructor.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/arrays/nonLocalReturnArrayConstructor.kt");
|
||||||
try {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("nonNullArray.kt")
|
@TestMetadata("nonNullArray.kt")
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ import org.jetbrains.kotlin.js.backend.ast.*;
|
|||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
|
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.TypeCheck;
|
import org.jetbrains.kotlin.js.backend.ast.metadata.TypeCheck;
|
||||||
|
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||||
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||||
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
||||||
import org.jetbrains.kotlin.js.resolve.JsPlatform;
|
import org.jetbrains.kotlin.js.resolve.JsPlatform;
|
||||||
|
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.ArrayFIF;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils;
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
@@ -114,7 +116,10 @@ public final class Namer {
|
|||||||
public static final String ENUM_ORDINAL_FIELD = "ordinal$";
|
public static final String ENUM_ORDINAL_FIELD = "ordinal$";
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String getFunctionTag(@NotNull CallableDescriptor functionDescriptor) {
|
public static String getFunctionTag(@NotNull CallableDescriptor functionDescriptor, @NotNull JsConfig config) {
|
||||||
|
String intrinsicTag = ArrayFIF.INSTANCE.getTag(functionDescriptor, config);
|
||||||
|
if (intrinsicTag != null) return intrinsicTag;
|
||||||
|
|
||||||
functionDescriptor = (CallableDescriptor) JsDescriptorUtils.findRealInlineDeclaration(functionDescriptor);
|
functionDescriptor = (CallableDescriptor) JsDescriptorUtils.findRealInlineDeclaration(functionDescriptor);
|
||||||
String moduleName = getModuleName(functionDescriptor);
|
String moduleName = getModuleName(functionDescriptor);
|
||||||
FqNameUnsafe fqNameParent = DescriptorUtils.getFqName(functionDescriptor).parent();
|
FqNameUnsafe fqNameParent = DescriptorUtils.getFqName(functionDescriptor).parent();
|
||||||
|
|||||||
@@ -782,7 +782,7 @@ public final class StaticContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addInlineCall(@NotNull CallableDescriptor descriptor) {
|
public void addInlineCall(@NotNull CallableDescriptor descriptor) {
|
||||||
String tag = Namer.getFunctionTag(descriptor);
|
String tag = Namer.getFunctionTag(descriptor, config);
|
||||||
fragment.getInlineModuleMap().put(tag, getModuleExpressionFor(descriptor));
|
fragment.getInlineModuleMap().put(tag, getModuleExpressionFor(descriptor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -110,7 +110,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
|||||||
function.body.statements += FunctionBodyTranslator.setDefaultValueForArguments(descriptor, innerContext)
|
function.body.statements += FunctionBodyTranslator.setDefaultValueForArguments(descriptor, innerContext)
|
||||||
}
|
}
|
||||||
innerContext.translateFunction(expression, function)
|
innerContext.translateFunction(expression, function)
|
||||||
return innerContext.wrapWithInlineMetadata(function, descriptor)
|
return innerContext.wrapWithInlineMetadata(function, descriptor, context.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun addFunction(
|
protected abstract fun addFunction(
|
||||||
|
|||||||
+3
-2
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.js.backend.ast.JsScope
|
|||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
|
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.functionDescriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.hasDefaultValue
|
import org.jetbrains.kotlin.js.backend.ast.metadata.hasDefaultValue
|
||||||
|
import org.jetbrains.kotlin.js.config.JsConfig
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator.shouldBeInlined
|
import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator.shouldBeInlined
|
||||||
@@ -100,9 +101,9 @@ fun TranslationContext.translateFunction(declaration: KtDeclarationWithBody, fun
|
|||||||
function.functionDescriptor = descriptor
|
function.functionDescriptor = descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor: FunctionDescriptor): JsExpression {
|
fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor: FunctionDescriptor, config: JsConfig): JsExpression {
|
||||||
return if (shouldBeInlined(descriptor, this) && descriptor.isEffectivelyPublicApi) {
|
return if (shouldBeInlined(descriptor, this) && descriptor.isEffectivelyPublicApi) {
|
||||||
val metadata = InlineMetadata.compose(function, descriptor)
|
val metadata = InlineMetadata.compose(function, descriptor, config)
|
||||||
metadata.functionWithMetadata
|
metadata.functionWithMetadata
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.translate.expression
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.config.JsConfig
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
|
|
||||||
private val METADATA_PROPERTIES_COUNT = 2
|
private val METADATA_PROPERTIES_COUNT = 2
|
||||||
@@ -25,9 +26,9 @@ private val METADATA_PROPERTIES_COUNT = 2
|
|||||||
class InlineMetadata(val tag: JsStringLiteral, val function: JsFunction) {
|
class InlineMetadata(val tag: JsStringLiteral, val function: JsFunction) {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun compose(function: JsFunction, descriptor: CallableDescriptor): InlineMetadata {
|
fun compose(function: JsFunction, descriptor: CallableDescriptor, config: JsConfig): InlineMetadata {
|
||||||
val program = function.scope.program
|
val program = function.scope.program
|
||||||
val tag = program.getStringLiteral(Namer.getFunctionTag(descriptor))
|
val tag = program.getStringLiteral(Namer.getFunctionTag(descriptor, config))
|
||||||
return InlineMetadata(tag, function)
|
return InlineMetadata(tag, function)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -211,7 +211,7 @@ public final class PatternTranslator extends AbstractTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isArray(type)) {
|
if (isArray(type)) {
|
||||||
if (ArrayFIF.typedArraysEnabled(context())) {
|
if (ArrayFIF.typedArraysEnabled(context().getConfig())) {
|
||||||
return namer().isArray();
|
return namer().isArray();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -255,7 +255,7 @@ public final class PatternTranslator extends AbstractTranslator {
|
|||||||
return namer().isTypeOf(program().getStringLiteral("number"));
|
return namer().isTypeOf(program().getStringLiteral("number"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ArrayFIF.typedArraysEnabled(context())) {
|
if (ArrayFIF.typedArraysEnabled(context().getConfig())) {
|
||||||
if (KotlinBuiltIns.isPrimitiveArray(type)) {
|
if (KotlinBuiltIns.isPrimitiveArray(type)) {
|
||||||
PrimitiveType arrayType = KotlinBuiltIns.getPrimitiveArrayElementType(type);
|
PrimitiveType arrayType = KotlinBuiltIns.getPrimitiveArrayElementType(type);
|
||||||
assert arrayType != null;
|
assert arrayType != null;
|
||||||
|
|||||||
+73
-32
@@ -20,33 +20,40 @@ import com.intellij.openapi.util.text.StringUtil.decapitalize
|
|||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType.*
|
import org.jetbrains.kotlin.builtins.PrimitiveType.*
|
||||||
|
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
|
||||||
|
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
|
import org.jetbrains.kotlin.js.backend.ast.metadata.descriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
import org.jetbrains.kotlin.js.backend.ast.metadata.inlineStrategy
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.js.config.JsConfig
|
||||||
import org.jetbrains.kotlin.js.patterns.NamePredicate
|
import org.jetbrains.kotlin.js.patterns.NamePredicate
|
||||||
import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern
|
import org.jetbrains.kotlin.js.patterns.PatternBuilder.pattern
|
||||||
|
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.BuiltInPropertyIntrinsic
|
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.BuiltInPropertyIntrinsic
|
||||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed
|
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object ArrayFIF : CompositeFIF() {
|
object ArrayFIF : CompositeFIF() {
|
||||||
@JvmField
|
@JvmField
|
||||||
val GET_INTRINSIC = intrinsify { receiver, arguments, _ ->
|
val GET_INTRINSIC = intrinsify { callInfo, arguments, _ ->
|
||||||
assert(arguments.size == 1) { "Array get expression must have one argument." }
|
assert(arguments.size == 1) { "Array get expression must have one argument." }
|
||||||
val (indexExpression) = arguments
|
val (indexExpression) = arguments
|
||||||
JsArrayAccess(receiver!!, indexExpression)
|
JsArrayAccess(callInfo.dispatchReceiver, indexExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val SET_INTRINSIC = intrinsify { receiver, arguments, _ ->
|
val SET_INTRINSIC = intrinsify { callInfo, arguments, _ ->
|
||||||
assert(arguments.size == 2) { "Array set expression must have two arguments." }
|
assert(arguments.size == 2) { "Array set expression must have two arguments." }
|
||||||
val (indexExpression, value) = arguments
|
val (indexExpression, value) = arguments
|
||||||
val arrayAccess = JsArrayAccess(receiver!!, indexExpression)
|
val arrayAccess = JsArrayAccess(callInfo.dispatchReceiver, indexExpression)
|
||||||
JsAstUtils.assignment(arrayAccess, value)
|
JsAstUtils.assignment(arrayAccess, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,10 +61,10 @@ object ArrayFIF : CompositeFIF() {
|
|||||||
val LENGTH_PROPERTY_INTRINSIC = BuiltInPropertyIntrinsic("length")
|
val LENGTH_PROPERTY_INTRINSIC = BuiltInPropertyIntrinsic("length")
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun typedArraysEnabled(ctx: TranslationContext) = ctx.config.configuration.getBoolean(JSConfigurationKeys.TYPED_ARRAYS_ENABLED)
|
fun typedArraysEnabled(config: JsConfig) = config.configuration.getBoolean(JSConfigurationKeys.TYPED_ARRAYS_ENABLED)
|
||||||
|
|
||||||
fun castOrCreatePrimitiveArray(ctx: TranslationContext, type: PrimitiveType?, arg: JsArrayLiteral): JsExpression {
|
fun castOrCreatePrimitiveArray(ctx: TranslationContext, type: PrimitiveType?, arg: JsArrayLiteral): JsExpression {
|
||||||
if (type == null || !typedArraysEnabled(ctx)) return arg
|
if (type == null || !typedArraysEnabled(ctx.config)) return arg
|
||||||
|
|
||||||
if (type in TYPED_ARRAY_MAP) {
|
if (type in TYPED_ARRAY_MAP) {
|
||||||
return createTypedArray(type, arg)
|
return createTypedArray(type, arg)
|
||||||
@@ -81,6 +88,30 @@ object ArrayFIF : CompositeFIF() {
|
|||||||
private val PrimitiveType.lowerCaseName
|
private val PrimitiveType.lowerCaseName
|
||||||
get() = typeName.asString().toLowerCase()
|
get() = typeName.asString().toLowerCase()
|
||||||
|
|
||||||
|
fun getTag(descriptor: CallableDescriptor, config: JsConfig): String? {
|
||||||
|
if (descriptor !is ConstructorDescriptor) return null
|
||||||
|
val constructedClass = descriptor.constructedClass
|
||||||
|
if (!KotlinBuiltIns.isArrayOrPrimitiveArray(constructedClass)) return null
|
||||||
|
|
||||||
|
if (descriptor.valueParameters.size != 2) return null
|
||||||
|
val (sizeParam, functionParam) = descriptor.valueParameters
|
||||||
|
if (!KotlinBuiltIns.isInt(sizeParam.type) || !functionParam.type.isBuiltinFunctionalType) return null
|
||||||
|
if (functionParam.type.getValueParameterTypesFromFunctionType().size != 1) return null
|
||||||
|
|
||||||
|
val primitiveType = KotlinBuiltIns.getPrimitiveArrayElementType(constructedClass.defaultType)
|
||||||
|
return if (typedArraysEnabled(config) && primitiveType != null) {
|
||||||
|
if (primitiveType in TYPED_ARRAY_MAP) {
|
||||||
|
"kotlin.fillArray"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"kotlin.${primitiveType.lowerCaseName}ArrayF"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"kotlin.newArrayF"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val arrayName = KotlinBuiltIns.FQ_NAMES.array.shortName()
|
val arrayName = KotlinBuiltIns.FQ_NAMES.array.shortName()
|
||||||
|
|
||||||
@@ -97,7 +128,7 @@ object ArrayFIF : CompositeFIF() {
|
|||||||
assert(arguments.size == 1) { "Array <init>(Int) expression must have one argument." }
|
assert(arguments.size == 1) { "Array <init>(Int) expression must have one argument." }
|
||||||
val (size) = arguments
|
val (size) = arguments
|
||||||
|
|
||||||
if (typedArraysEnabled(context)) {
|
if (typedArraysEnabled(context.config)) {
|
||||||
if (type in TYPED_ARRAY_MAP) {
|
if (type in TYPED_ARRAY_MAP) {
|
||||||
createTypedArray(type, size)
|
createTypedArray(type, size)
|
||||||
}
|
}
|
||||||
@@ -116,24 +147,11 @@ object ArrayFIF : CompositeFIF() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
add(pattern(NamePredicate(type.arrayTypeName), "<init>(Int,Function1)"), intrinsify { _, arguments, context ->
|
add(pattern(NamePredicate(type.arrayTypeName), "<init>(Int,Function1)"), createConstructorIntrinsic(type))
|
||||||
assert(arguments.size == 2) { "Array <init>(Int,Function1) expression must have two arguments." }
|
|
||||||
val (size, fn) = arguments
|
|
||||||
if (typedArraysEnabled(context)) {
|
|
||||||
if (type in TYPED_ARRAY_MAP) {
|
|
||||||
JsAstUtils.invokeKotlinFunction("fillArray", createTypedArray(type, size), fn)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsAstUtils.invokeKotlinFunction("${type.lowerCaseName}Array", size, fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
JsAstUtils.invokeKotlinFunction("newArrayF", size, fn)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
add(pattern(NamePredicate(type.arrayTypeName), "iterator"), intrinsify { receiver, _, context ->
|
add(pattern(NamePredicate(type.arrayTypeName), "iterator"), intrinsify { callInfo, _, context ->
|
||||||
if (typedArraysEnabled(context)) {
|
val receiver = callInfo.dispatchReceiver
|
||||||
|
if (typedArraysEnabled(context.config)) {
|
||||||
JsAstUtils.invokeKotlinFunction("${type.lowerCaseName}ArrayIterator", receiver!!)
|
JsAstUtils.invokeKotlinFunction("${type.lowerCaseName}ArrayIterator", receiver!!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -143,7 +161,7 @@ object ArrayFIF : CompositeFIF() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
add(pattern(NamePredicate(arrayName), "<init>(Int,Function1)"), KotlinFunctionIntrinsic("newArrayF"))
|
add(pattern(NamePredicate(arrayName), "<init>(Int,Function1)"), createConstructorIntrinsic(null))
|
||||||
add(pattern(NamePredicate(arrayName), "iterator"), KotlinFunctionIntrinsic("arrayIterator"))
|
add(pattern(NamePredicate(arrayName), "iterator"), KotlinFunctionIntrinsic("arrayIterator"))
|
||||||
|
|
||||||
add(pattern(Namer.KOTLIN_LOWER_NAME, "arrayOfNulls"), KotlinFunctionIntrinsic("newArray", JsLiteral.NULL))
|
add(pattern(Namer.KOTLIN_LOWER_NAME, "arrayOfNulls"), KotlinFunctionIntrinsic("newArray", JsLiteral.NULL))
|
||||||
@@ -153,10 +171,33 @@ object ArrayFIF : CompositeFIF() {
|
|||||||
add(arrayFactoryMethods, intrinsify { _, arguments, _ -> arguments[0] })
|
add(arrayFactoryMethods, intrinsify { _, arguments, _ -> arguments[0] })
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun intrinsify(f: (receiver: JsExpression?, arguments: List<JsExpression>, context: TranslationContext) -> JsExpression)
|
private fun createConstructorIntrinsic(type: PrimitiveType?): FunctionIntrinsic {
|
||||||
= object : FunctionIntrinsicWithReceiverComputed() {
|
return intrinsify { callInfo, arguments, context ->
|
||||||
override fun apply(receiver: JsExpression?, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
|
assert(arguments.size == 2) { "Array <init>(Int,Function1) expression must have two arguments." }
|
||||||
return f(receiver, arguments, context)
|
val (size, fn) = arguments
|
||||||
|
val invocation = if (typedArraysEnabled(context.config) && type != null) {
|
||||||
|
if (type in TYPED_ARRAY_MAP) {
|
||||||
|
JsAstUtils.invokeKotlinFunction("fillArray", createTypedArray(type, size), fn)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JsAstUtils.invokeKotlinFunction("${type.lowerCaseName}ArrayF", size, fn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
JsAstUtils.invokeKotlinFunction("newArrayF", size, fn)
|
||||||
|
}
|
||||||
|
invocation.inlineStrategy = InlineStrategy.IN_PLACE
|
||||||
|
val descriptor = callInfo.resolvedCall.resultingDescriptor.original
|
||||||
|
invocation.descriptor = descriptor
|
||||||
|
context.addInlineCall(descriptor)
|
||||||
|
invocation
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun intrinsify(f: (callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext) -> JsExpression)
|
||||||
|
= object : FunctionIntrinsic() {
|
||||||
|
override fun apply(callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
|
||||||
|
return f(callInfo, arguments, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -21,8 +21,10 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
|
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
@@ -147,6 +149,9 @@ public final class JsDescriptorUtils {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static String getModuleName(@NotNull DeclarationDescriptor descriptor) {
|
public static String getModuleName(@NotNull DeclarationDescriptor descriptor) {
|
||||||
ModuleDescriptor moduleDescriptor = DescriptorUtils.getContainingModule(findRealInlineDeclaration(descriptor));
|
ModuleDescriptor moduleDescriptor = DescriptorUtils.getContainingModule(findRealInlineDeclaration(descriptor));
|
||||||
|
if (DescriptorUtils.getContainingModule(descriptor) == moduleDescriptor.getBuiltIns().getBuiltInsModule()) {
|
||||||
|
return Namer.KOTLIN_LOWER_NAME;
|
||||||
|
}
|
||||||
String moduleName = moduleDescriptor.getName().asString();
|
String moduleName = moduleDescriptor.getName().asString();
|
||||||
return moduleName.substring(1, moduleName.length() - 1);
|
return moduleName.substring(1, moduleName.length() - 1);
|
||||||
}
|
}
|
||||||
@@ -179,7 +184,7 @@ public final class JsDescriptorUtils {
|
|||||||
|
|
||||||
public static boolean isImmediateSubtypeOfError(@NotNull ClassDescriptor descriptor) {
|
public static boolean isImmediateSubtypeOfError(@NotNull ClassDescriptor descriptor) {
|
||||||
if (!isExceptionClass(descriptor)) return false;
|
if (!isExceptionClass(descriptor)) return false;
|
||||||
ClassDescriptor superClass = org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getSuperClassOrAny(descriptor);
|
ClassDescriptor superClass = DescriptorUtilsKt.getSuperClassOrAny(descriptor);
|
||||||
return TypeUtilsKt.isThrowable(superClass.getDefaultType()) || AnnotationsUtils.isNativeObject(superClass);
|
return TypeUtilsKt.isThrowable(superClass.getDefaultType()) || AnnotationsUtils.isNativeObject(superClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public final class TranslationUtils {
|
|||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
JsExpression functionExpression = function;
|
JsExpression functionExpression = function;
|
||||||
if (InlineUtil.isInline(descriptor)) {
|
if (InlineUtil.isInline(descriptor)) {
|
||||||
InlineMetadata metadata = InlineMetadata.compose(function, descriptor);
|
InlineMetadata metadata = InlineMetadata.compose(function, descriptor, context.getConfig());
|
||||||
functionExpression = metadata.getFunctionWithMetadata();
|
functionExpression = metadata.getFunctionWithMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user