Add a common JVM/JS lowering for Array(size, function)
and remove the hack from JVM_IR codegen that replaces this call with hardcoded inline function bytecode.
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 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 org.jetbrains.kotlin.backend.common.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.getClass
|
||||||
|
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
|
class ArrayConstructorLowering(val context: CommonBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
irFile.transformChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array(size, init) -> Array(size)
|
||||||
|
private val arrayInlineToSizeCtor: Map<IrFunctionSymbol, IrFunctionSymbol> =
|
||||||
|
(context.irBuiltIns.primitiveArrays + context.irBuiltIns.arrayClass).associate { arrayClass ->
|
||||||
|
val fromInit = arrayClass.constructors.single { it.owner.valueParameters.size == 2 }
|
||||||
|
val fromSize = arrayClass.constructors.find { it.owner.valueParameters.size == 1 }
|
||||||
|
?: context.ir.symbols.arrayOfNulls // Array<T> has no unary constructor: it can only exist for Array<T?>
|
||||||
|
fromInit to fromSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate `array[index] = value`.
|
||||||
|
private fun IrBuilderWithScope.setItem(array: IrVariable, index: IrVariable, value: IrExpression) =
|
||||||
|
irCall(array.type.getClass()!!.functions.single { it.name.toString() == "set" }).apply {
|
||||||
|
dispatchReceiver = irGet(array)
|
||||||
|
putValueArgument(0, irGet(index))
|
||||||
|
putValueArgument(1, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate `for (index in 0 until end) { element }`.
|
||||||
|
private fun IrBlockBuilder.fromZeroTo(end: IrVariable, element: IrBlockBuilder.(IrLoop, IrVariable) -> Unit) {
|
||||||
|
val index = irTemporaryVar(irInt(0))
|
||||||
|
+irWhile().apply {
|
||||||
|
condition = irCall(context.irBuiltIns.lessFunByOperandType[index.type.toKotlinType()]!!).apply {
|
||||||
|
putValueArgument(0, irGet(index))
|
||||||
|
putValueArgument(1, irGet(end))
|
||||||
|
}
|
||||||
|
body = irBlock {
|
||||||
|
val currentIndex = irTemporary(irGet(index))
|
||||||
|
val inc = index.type.getClass()!!.functions.single { it.name.asString() == "inc" }
|
||||||
|
+irSetVar(index.symbol, irCall(inc).apply { dispatchReceiver = irGet(index) })
|
||||||
|
element(this@apply, currentIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrExpression.asSingleArgumentLambda(): IrSimpleFunction? {
|
||||||
|
// A lambda is represented as a block with a function declaration and a reference to it.
|
||||||
|
if (this !is IrBlock || statements.size != 2)
|
||||||
|
return null
|
||||||
|
val (function, reference) = statements
|
||||||
|
if (function !is IrSimpleFunction || reference !is IrFunctionReference || function.symbol != reference.symbol)
|
||||||
|
return null
|
||||||
|
// Only match the one that has exactly one non-vararg argument, as the code below
|
||||||
|
// does not handle defaults or varargs.
|
||||||
|
if (function.valueParameters.size != 1 || function.valueParameters[0].isVararg || reference.getValueArgument(0) != null)
|
||||||
|
return null
|
||||||
|
return function
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||||
|
val sizeConstructor = arrayInlineToSizeCtor[expression.symbol]
|
||||||
|
?: return super.visitConstructorCall(expression)
|
||||||
|
val arrayOfReferences = sizeConstructor == context.ir.symbols.arrayOfNulls
|
||||||
|
|
||||||
|
// inline fun <reified T> Array(size: Int, invokable: (Int) -> T): Array<T> {
|
||||||
|
// val result = arrayOfNulls<T>(size)
|
||||||
|
// for (i in 0 until size) {
|
||||||
|
// result[i] = invokable(i)
|
||||||
|
// }
|
||||||
|
// return result as Array<T>
|
||||||
|
// }
|
||||||
|
// (and similar for primitive arrays)
|
||||||
|
val loweringContext = context
|
||||||
|
val size = expression.getValueArgument(0)!!.transform(this, null)
|
||||||
|
val invokable = expression.getValueArgument(1)!!.transform(this, null)
|
||||||
|
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).irBlock(expression.startOffset, expression.endOffset) {
|
||||||
|
val sizeVar = irTemporary(size)
|
||||||
|
val result = irTemporary(irCall(sizeConstructor, expression.type).apply {
|
||||||
|
if (arrayOfReferences) {
|
||||||
|
putTypeArgument(0, expression.getTypeArgument(0))
|
||||||
|
}
|
||||||
|
putValueArgument(0, irGet(sizeVar))
|
||||||
|
})
|
||||||
|
|
||||||
|
val lambda = invokable.asSingleArgumentLambda()
|
||||||
|
if (lambda == null) {
|
||||||
|
val invokableVar = irTemporary(invokable)
|
||||||
|
val invoke = invokable.type.getClass()!!.functions.single { it.name == OperatorNameConventions.INVOKE }
|
||||||
|
fromZeroTo(sizeVar) { _, index ->
|
||||||
|
+setItem(result, index, irCall(invoke).apply {
|
||||||
|
dispatchReceiver = irGet(invokableVar)
|
||||||
|
putValueArgument(0, irGet(index))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Inline `invokable` by replacing the argument with `i` and `return x` with `result[i] = x; continue`.
|
||||||
|
fromZeroTo(sizeVar) { loop, index ->
|
||||||
|
val body = lambda.body!!.transform(object : IrElementTransformerVoidWithContext() {
|
||||||
|
override fun visitGetValue(expression: IrGetValue) =
|
||||||
|
if (expression.symbol == lambda.valueParameters[0].symbol)
|
||||||
|
IrGetValueImpl(expression.startOffset, expression.endOffset, index.symbol)
|
||||||
|
else
|
||||||
|
super.visitGetValue(expression)
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn) =
|
||||||
|
if (expression.returnTargetSymbol == lambda.symbol) {
|
||||||
|
val value = expression.value.transform(this, null)
|
||||||
|
val scope = currentScope?.scope?.scopeOwnerSymbol ?: lambda.symbol
|
||||||
|
loweringContext.createIrBuilder(scope).irBlock(expression.startOffset, expression.endOffset) {
|
||||||
|
+setItem(result, index, value)
|
||||||
|
+irContinue(loop)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.visitReturn(expression)
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
|
||||||
|
when (body) {
|
||||||
|
is IrExpressionBody -> +setItem(result, index, body.expression)
|
||||||
|
is IrBlockBody -> body.statements.forEach { +it }
|
||||||
|
else -> throw AssertionError("unexpected function body type: $body")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+irGet(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -84,6 +84,12 @@ private val lateinitLoweringPhase = makeJsModulePhase(
|
|||||||
description = "Insert checks for lateinit field references"
|
description = "Insert checks for lateinit field references"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val arrayConstructorPhase = makeJsModulePhase(
|
||||||
|
::ArrayConstructorLowering,
|
||||||
|
name = "ArrayConstructor",
|
||||||
|
description = "Transform `Array(size) { index -> value }` into a loop"
|
||||||
|
)
|
||||||
|
|
||||||
private val functionInliningPhase = makeCustomJsModulePhase(
|
private val functionInliningPhase = makeCustomJsModulePhase(
|
||||||
{ context, module ->
|
{ context, module ->
|
||||||
FunctionInlining(context).inline(module)
|
FunctionInlining(context).inline(module)
|
||||||
@@ -351,6 +357,7 @@ val jsPhases = namedIrModulePhase(
|
|||||||
description = "IR module lowering",
|
description = "IR module lowering",
|
||||||
lower = testGenerationPhase then
|
lower = testGenerationPhase then
|
||||||
expectDeclarationsRemovingPhase then
|
expectDeclarationsRemovingPhase then
|
||||||
|
arrayConstructorPhase then
|
||||||
functionInliningPhase then
|
functionInliningPhase then
|
||||||
lateinitLoweringPhase then
|
lateinitLoweringPhase then
|
||||||
tailrecLoweringPhase then
|
tailrecLoweringPhase then
|
||||||
|
|||||||
-65
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2018 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.builtins.PrimitiveType
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.util.irCall
|
|
||||||
|
|
||||||
// Replace array inline constructors with stdlib function invocations
|
|
||||||
class ArrayConstructorTransformer(
|
|
||||||
val context: JsIrBackendContext
|
|
||||||
) {
|
|
||||||
// Inline constructor for CharArray is implemented in runtime
|
|
||||||
private val primitiveArrayInlineToSizeConstructorMap =
|
|
||||||
context.intrinsics.primitiveArrays.filter { it.value != PrimitiveType.CHAR }.keys.associate {
|
|
||||||
it.inlineConstructor to it.sizeConstructor
|
|
||||||
}
|
|
||||||
|
|
||||||
fun transformConstructorCall(expression: IrConstructorCall): IrFunctionAccessExpression {
|
|
||||||
if (expression.symbol == context.intrinsics.array.inlineConstructor) {
|
|
||||||
return irCall(expression, context.intrinsics.jsArray).apply {
|
|
||||||
copyTypeArgumentsFrom(expression)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
primitiveArrayInlineToSizeConstructorMap[expression.symbol]?.let { sizeConstructor ->
|
|
||||||
return IrCallImpl(
|
|
||||||
expression.startOffset,
|
|
||||||
expression.endOffset,
|
|
||||||
expression.type,
|
|
||||||
context.intrinsics.jsFillArray
|
|
||||||
).apply {
|
|
||||||
putValueArgument(0, IrConstructorCallImpl.fromSymbolOwner(
|
|
||||||
expression.startOffset,
|
|
||||||
expression.endOffset,
|
|
||||||
expression.type,
|
|
||||||
sizeConstructor
|
|
||||||
).apply {
|
|
||||||
putValueArgument(0, expression.getValueArgument(0))
|
|
||||||
})
|
|
||||||
putValueArgument(1, expression.getValueArgument(1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return expression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO it.isInline doesn't work =(
|
|
||||||
private val IrClassSymbol.inlineConstructor
|
|
||||||
get() = owner.declarations.filterIsInstance<IrConstructor>().first { it.valueParameters.size == 2 }.symbol
|
|
||||||
|
|
||||||
private val IrClassSymbol.sizeConstructor
|
|
||||||
get() = owner.declarations.filterIsInstance<IrConstructor>().first { it.valueParameters.size == 1 }.symbol
|
|
||||||
+11
-19
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.config.languageVersionSettings
|
|||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.ArrayConstructorTransformer
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -43,38 +42,31 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
|
|||||||
return irModule.accept(this, data = null)
|
return irModule.accept(this, data = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val arrayConstructorTransformer = ArrayConstructorTransformer(context)
|
|
||||||
|
|
||||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
|
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
val callSite = when (expression) {
|
if (!(expression is IrCall || expression is IrConstructorCall) || !expression.symbol.owner.needsInlining)
|
||||||
is IrCall -> expression
|
return expression
|
||||||
is IrConstructorCall -> arrayConstructorTransformer.transformConstructorCall(expression)
|
|
||||||
else -> return expression
|
|
||||||
}
|
|
||||||
if (!callSite.symbol.owner.needsInlining)
|
|
||||||
return callSite
|
|
||||||
|
|
||||||
val languageVersionSettings = context.configuration.languageVersionSettings
|
val languageVersionSettings = context.configuration.languageVersionSettings
|
||||||
when {
|
when {
|
||||||
Symbols.isLateinitIsInitializedPropertyGetter(callSite.symbol) ->
|
Symbols.isLateinitIsInitializedPropertyGetter(expression.symbol) ->
|
||||||
return callSite
|
return expression
|
||||||
// Handle coroutine intrinsics
|
// Handle coroutine intrinsics
|
||||||
// TODO These should actually be inlined.
|
// TODO These should actually be inlined.
|
||||||
callSite.descriptor.isBuiltInIntercepted(languageVersionSettings) ->
|
expression.descriptor.isBuiltInIntercepted(languageVersionSettings) ->
|
||||||
error("Continuation.intercepted is not available with release coroutines")
|
error("Continuation.intercepted is not available with release coroutines")
|
||||||
callSite.symbol.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
|
expression.symbol.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
|
||||||
return irCall(callSite, context.coroutineSuspendOrReturn)
|
return irCall(expression, context.coroutineSuspendOrReturn)
|
||||||
callSite.symbol == context.intrinsics.jsCoroutineContext ->
|
expression.symbol == context.intrinsics.jsCoroutineContext ->
|
||||||
return irCall(callSite, context.coroutineGetContextJs)
|
return irCall(expression, context.coroutineGetContextJs)
|
||||||
}
|
}
|
||||||
|
|
||||||
val callee = getFunctionDeclaration(callSite.symbol) // Get declaration of the function to be inlined.
|
val callee = getFunctionDeclaration(expression.symbol) // Get declaration of the function to be inlined.
|
||||||
callee.transformChildrenVoid(this) // Process recursive inline.
|
callee.transformChildrenVoid(this) // Process recursive inline.
|
||||||
|
|
||||||
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
|
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
|
||||||
val inliner = Inliner(callSite, callee, currentScope!!, parent, context)
|
val inliner = Inliner(expression, callee, currentScope!!, parent, context)
|
||||||
return inliner.inline()
|
return inliner.inline()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ private fun makePatchParentsPhase(number: Int) = namedIrFilePhase(
|
|||||||
nlevels = 0
|
nlevels = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val arrayConstructorPhase = makeIrFilePhase(
|
||||||
|
::ArrayConstructorLowering,
|
||||||
|
name = "ArrayConstructor",
|
||||||
|
description = "Transform `Array(size) { index -> value }` into a loop"
|
||||||
|
)
|
||||||
|
|
||||||
private val expectDeclarationsRemovingPhase = makeIrFilePhase(
|
private val expectDeclarationsRemovingPhase = makeIrFilePhase(
|
||||||
::ExpectDeclarationsRemoving,
|
::ExpectDeclarationsRemoving,
|
||||||
name = "ExpectDeclarationsRemoving",
|
name = "ExpectDeclarationsRemoving",
|
||||||
@@ -61,6 +67,7 @@ val jvmPhases = namedIrFilePhase<JvmBackendContext>(
|
|||||||
lower = expectDeclarationsRemovingPhase then
|
lower = expectDeclarationsRemovingPhase then
|
||||||
fileClassPhase then
|
fileClassPhase then
|
||||||
kCallableNamePropertyPhase then
|
kCallableNamePropertyPhase then
|
||||||
|
arrayConstructorPhase then
|
||||||
|
|
||||||
jvmLateinitPhase then
|
jvmLateinitPhase then
|
||||||
|
|
||||||
|
|||||||
+40
-112
@@ -19,13 +19,11 @@ import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.SAFE
|
|||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
|
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
|
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
|
||||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
|
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
|
||||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
@@ -246,64 +244,30 @@ class ExpressionCodegen(
|
|||||||
override fun visitContainerExpression(expression: IrContainerExpression, data: BlockInfo) =
|
override fun visitContainerExpression(expression: IrContainerExpression, data: BlockInfo) =
|
||||||
visitStatementContainer(expression, data).coerce(expression.asmType)
|
visitStatementContainer(expression, data).coerce(expression.asmType)
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: BlockInfo): PromisedValue {
|
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: BlockInfo): PromisedValue {
|
||||||
expression.markLineNumber(startOffset = true)
|
expression.markLineNumber(startOffset = true)
|
||||||
mv.load(0, OBJECT_TYPE) // HACK
|
|
||||||
return generateCall(expression, null, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall, data: BlockInfo): PromisedValue {
|
|
||||||
expression.markLineNumber(startOffset = true)
|
|
||||||
if (expression.symbol.owner is IrConstructor) {
|
|
||||||
throw AssertionError("IrCall with ConstructorDescriptor: ${expression.javaClass.simpleName}")
|
|
||||||
}
|
|
||||||
return generateCall(expression, expression.superQualifierSymbol, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitConstructorCall(expression: IrConstructorCall, data: BlockInfo): PromisedValue {
|
|
||||||
val type = expression.asmType
|
|
||||||
if (type.sort == Type.ARRAY) {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return generateNewArray(expression, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
mv.anew(expression.asmType)
|
|
||||||
mv.dup()
|
|
||||||
generateCall(expression, null, data)
|
|
||||||
return expression.onStack
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun generateNewArray(expression: IrConstructorCall, data: BlockInfo): PromisedValue {
|
|
||||||
val args = expression.symbol.owner.valueParameters
|
|
||||||
assert(args.size == 1 || args.size == 2) { "Unknown constructor called: " + args.size + " arguments" }
|
|
||||||
|
|
||||||
if (args.size == 1) {
|
|
||||||
// TODO move to the intrinsic
|
|
||||||
expression.getValueArgument(0)!!.accept(this, data).coerce(Type.INT_TYPE).materialize()
|
|
||||||
newArrayInstruction(expression.type)
|
|
||||||
return expression.onStack
|
|
||||||
}
|
|
||||||
|
|
||||||
return generateCall(expression, null, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun generateCall(expression: IrFunctionAccessExpression, superQualifierSymbol: IrClassSymbol?, data: BlockInfo): PromisedValue {
|
|
||||||
classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol)
|
classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol)
|
||||||
?.invoke(expression, this, data)?.let { return it.coerce(expression.asmType) }
|
?.invoke(expression, this, data)?.let { return it.coerce(expression.asmType) }
|
||||||
val isSuperCall = superQualifierSymbol != null
|
|
||||||
val callable = resolveToCallable(expression, isSuperCall)
|
|
||||||
return generateCall(expression, callable, data, isSuperCall)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generateCall(
|
val isSuperCall = (expression as? IrCall)?.superQualifier != null
|
||||||
expression: IrFunctionAccessExpression,
|
val callable = resolveToCallable(expression, isSuperCall)
|
||||||
callable: Callable,
|
|
||||||
data: BlockInfo,
|
|
||||||
isSuperCall: Boolean = false
|
|
||||||
): PromisedValue {
|
|
||||||
val callee = expression.symbol.owner
|
val callee = expression.symbol.owner
|
||||||
val callGenerator = getOrCreateCallGenerator(expression, data)
|
val callGenerator = getOrCreateCallGenerator(expression, data)
|
||||||
|
|
||||||
|
when {
|
||||||
|
expression is IrConstructorCall -> {
|
||||||
|
// IR constructors have no receiver and return the new instance, but on JVM they are void-returning
|
||||||
|
// instance methods named <init>.
|
||||||
|
mv.anew(expression.asmType)
|
||||||
|
mv.dup()
|
||||||
|
}
|
||||||
|
expression is IrDelegatingConstructorCall ->
|
||||||
|
// In this case the receiver is `this` (not specified in IR) and the return value is discarded anyway.
|
||||||
|
mv.load(0, OBJECT_TYPE)
|
||||||
|
expression.descriptor is ConstructorDescriptor ->
|
||||||
|
throw AssertionError("IrCall with ConstructorDescriptor: ${expression.javaClass.simpleName}")
|
||||||
|
}
|
||||||
|
|
||||||
val receiver = expression.dispatchReceiver
|
val receiver = expression.dispatchReceiver
|
||||||
receiver?.apply {
|
receiver?.apply {
|
||||||
callGenerator.genValueAndPut(
|
callGenerator.genValueAndPut(
|
||||||
@@ -374,17 +338,19 @@ class ExpressionCodegen(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val returnType = callee.returnType.substitute(typeSubstitutionMap)
|
val returnType = callee.returnType.substitute(typeSubstitutionMap)
|
||||||
if (returnType.isNothing()) {
|
return when {
|
||||||
mv.aconst(null)
|
returnType.isNothing() -> {
|
||||||
mv.athrow()
|
mv.aconst(null)
|
||||||
return voidValue
|
mv.athrow()
|
||||||
} else if (callee is IrConstructor) {
|
voidValue
|
||||||
return voidValue
|
}
|
||||||
} else if (expression.type.isUnit()) {
|
expression is IrConstructorCall -> expression.onStack
|
||||||
// NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail.
|
expression is IrDelegatingConstructorCall -> voidValue
|
||||||
return MaterialValue(mv, callable.returnType).discard().coerce(expression.asmType)
|
expression.type.isUnit() ->
|
||||||
|
// NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail.
|
||||||
|
MaterialValue(mv, callable.returnType).discard().coerce(expression.asmType)
|
||||||
|
else -> MaterialValue(mv, callable.returnType).coerce(expression.asmType)
|
||||||
}
|
}
|
||||||
return MaterialValue(mv, callable.returnType).coerce(expression.asmType)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue {
|
override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue {
|
||||||
@@ -1040,50 +1006,23 @@ class ExpressionCodegen(
|
|||||||
return typeMapper.mapToCallableMethod(irCall.symbol.owner, isSuper)
|
return typeMapper.mapToCallableMethod(irCall.symbol.owner, isSuper)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getOrCreateCallGenerator(
|
private fun getOrCreateCallGenerator(element: IrFunctionAccessExpression, data: BlockInfo): IrCallGenerator {
|
||||||
irFunction: IrFunction,
|
if (!element.symbol.owner.isInlineFunctionCall(context)) {
|
||||||
element: IrMemberAccessExpression?,
|
return IrCallGenerator.DefaultCallGenerator
|
||||||
typeParameterMappings: IrTypeParameterMappings?,
|
|
||||||
isDefaultCompilation: Boolean,
|
|
||||||
data: BlockInfo
|
|
||||||
): IrCallGenerator {
|
|
||||||
if (element == null) return IrCallGenerator.DefaultCallGenerator
|
|
||||||
|
|
||||||
// We should inline callable containing reified type parameters even if inline is disabled
|
|
||||||
// because they may contain something to reify and straight call will probably fail at runtime
|
|
||||||
val isInline = irFunction.isInlineCall(state)
|
|
||||||
|
|
||||||
if (!isInline) return IrCallGenerator.DefaultCallGenerator
|
|
||||||
|
|
||||||
val original = (irFunction as? IrSimpleFunction)?.resolveFakeOverride() ?: irFunction
|
|
||||||
return if (isDefaultCompilation) {
|
|
||||||
TODO()
|
|
||||||
} else {
|
|
||||||
IrInlineCodegen(this, state, original.descriptor, typeParameterMappings!!, IrSourceCompilerForInline(state, element, this, data))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun getOrCreateCallGenerator(
|
val callee = element.symbol.owner
|
||||||
functionAccessExpression: IrFunctionAccessExpression,
|
|
||||||
data: BlockInfo
|
|
||||||
): IrCallGenerator {
|
|
||||||
val callee = functionAccessExpression.symbol.owner
|
|
||||||
val typeArgumentContainer = if (callee is IrConstructor) callee.parentAsClass else callee
|
val typeArgumentContainer = if (callee is IrConstructor) callee.parentAsClass else callee
|
||||||
val typeArguments =
|
val typeArguments =
|
||||||
if (functionAccessExpression.typeArgumentsCount == 0) {
|
if (element.typeArgumentsCount == 0) {
|
||||||
//avoid ambiguity with type constructor type parameters
|
//avoid ambiguity with type constructor type parameters
|
||||||
emptyMap()
|
emptyMap()
|
||||||
} else typeArgumentContainer.typeParameters.keysToMap {
|
} else typeArgumentContainer.typeParameters.keysToMap {
|
||||||
functionAccessExpression.getTypeArgumentOrDefault(it)
|
element.getTypeArgumentOrDefault(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
val mappings = IrTypeParameterMappings()
|
val mappings = IrTypeParameterMappings()
|
||||||
for (entry in typeArguments.entries) {
|
for ((key, type) in typeArguments.entries) {
|
||||||
val key = entry.key
|
|
||||||
val type = entry.value
|
|
||||||
|
|
||||||
val isReified = key.isReified || callee.isArrayConstructorWithLambda()
|
|
||||||
|
|
||||||
val reificationArgument = extractReificationArgument(type)
|
val reificationArgument = extractReificationArgument(type)
|
||||||
if (reificationArgument == null) {
|
if (reificationArgument == null) {
|
||||||
// type is not generic
|
// type is not generic
|
||||||
@@ -1091,16 +1030,17 @@ class ExpressionCodegen(
|
|||||||
val asmType = typeMapper.mapTypeParameter(type, signatureWriter)
|
val asmType = typeMapper.mapTypeParameter(type, signatureWriter)
|
||||||
|
|
||||||
mappings.addParameterMappingToType(
|
mappings.addParameterMappingToType(
|
||||||
key.name.identifier, type, asmType, signatureWriter.toString(), isReified
|
key.name.identifier, type, asmType, signatureWriter.toString(), key.isReified
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
mappings.addParameterMappingForFurtherReification(
|
mappings.addParameterMappingForFurtherReification(
|
||||||
key.name.identifier, type, reificationArgument, isReified
|
key.name.identifier, type, reificationArgument, key.isReified
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return getOrCreateCallGenerator(callee, functionAccessExpression, mappings, false, data)
|
val original = (callee as? IrSimpleFunction)?.resolveFakeOverride() ?: irFunction
|
||||||
|
return IrInlineCodegen(this, state, original.descriptor, mappings, IrSourceCompilerForInline(state, element, this, data))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) {
|
override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) {
|
||||||
@@ -1213,21 +1153,9 @@ fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isCo
|
|||||||
return toInts.isNotEmpty()
|
return toInts.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun IrFunction.isInlineCall(state: GenerationState) =
|
|
||||||
(!state.isInlineDisabled || containsReifiedTypeParameters()) &&
|
|
||||||
(isInline || isArrayConstructorWithLambda())
|
|
||||||
|
|
||||||
val IrType.isReifiedTypeParameter: Boolean
|
val IrType.isReifiedTypeParameter: Boolean
|
||||||
get() = this.classifierOrNull?.safeAs<IrTypeParameterSymbol>()?.owner?.isReified == true
|
get() = this.classifierOrNull?.safeAs<IrTypeParameterSymbol>()?.owner?.isReified == true
|
||||||
|
|
||||||
/* Copied and modified from InlineUtil.java */
|
|
||||||
fun isInline(declaration: IrDeclaration?): Boolean = declaration is IrSimpleFunction && declaration.isInline
|
|
||||||
|
|
||||||
fun IrFunction.containsReifiedTypeParameters(): Boolean =
|
|
||||||
typeParameters.any { it.isReified }
|
|
||||||
|
|
||||||
fun IrClass.isArrayOrPrimitiveArray() = this.defaultType.let { it.isArray() || it.isPrimitiveArray() }
|
|
||||||
|
|
||||||
/* From typeUtil.java */
|
/* From typeUtil.java */
|
||||||
fun IrType.getTypeParameterOrNull() = classifierOrNull?.owner?.safeAs<IrTypeParameter>()
|
fun IrType.getTypeParameterOrNull() = classifierOrNull?.owner?.safeAs<IrTypeParameter>()
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -165,8 +165,7 @@ fun isInlineIrExpression(argumentExpression: IrExpression) =
|
|||||||
(argumentExpression.origin == IrStatementOrigin.LAMBDA || argumentExpression.origin == IrStatementOrigin.ANONYMOUS_FUNCTION)
|
(argumentExpression.origin == IrStatementOrigin.LAMBDA || argumentExpression.origin == IrStatementOrigin.ANONYMOUS_FUNCTION)
|
||||||
|
|
||||||
fun IrFunction.isInlineFunctionCall(context: JvmBackendContext) =
|
fun IrFunction.isInlineFunctionCall(context: JvmBackendContext) =
|
||||||
(!context.state.isInlineDisabled || typeParameters.any { it.isReified }) &&
|
(!context.state.isInlineDisabled || typeParameters.any { it.isReified }) && isInline
|
||||||
(isInline || isArrayConstructorWithLambda())
|
|
||||||
|
|
||||||
fun IrValueParameter.isInlineParameter() =
|
fun IrValueParameter.isInlineParameter() =
|
||||||
!isNoinline && !type.isNullable() && type.isFunctionOrKFunction()
|
!isNoinline && !type.isNullable() && type.isFunctionOrKFunction()
|
||||||
@@ -89,15 +89,6 @@ fun JvmBackendContext.getSourceMapper(declaration: IrClass): DefaultSourceMapper
|
|||||||
val IrType.isExtensionFunctionType: Boolean
|
val IrType.isExtensionFunctionType: Boolean
|
||||||
get() = isFunctionTypeOrSubtype() && hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType)
|
get() = isFunctionTypeOrSubtype() && hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType)
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the function is a constructor of one of 9 array classes (Array<T>, IntArray, FloatArray, ...)
|
|
||||||
* which takes the size and an initializer lambda as parameters. Such constructors are marked as 'inline' but they are not loaded
|
|
||||||
* as such because the 'inline' flag is not stored for constructors in the binary metadata. Therefore we pretend that they are inline
|
|
||||||
*/
|
|
||||||
fun IrFunction.isArrayConstructorWithLambda(): Boolean = this is IrConstructor &&
|
|
||||||
valueParameters.size == 2 &&
|
|
||||||
parentAsClass.isArrayOrPrimitiveArray()
|
|
||||||
|
|
||||||
|
|
||||||
/* Borrowed from MemberCodegen.java */
|
/* Borrowed from MemberCodegen.java */
|
||||||
|
|
||||||
|
|||||||
-43
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2016 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.backend.jvm.intrinsics
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
|
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
|
||||||
|
|
||||||
object ArrayConstructor : IntrinsicMethod() {
|
|
||||||
override fun toCallable(
|
|
||||||
expression: IrFunctionAccessExpression,
|
|
||||||
signature: JvmMethodSignature,
|
|
||||||
context: JvmBackendContext
|
|
||||||
): IrIntrinsicFunction {
|
|
||||||
return object : IrIntrinsicFunction(expression, signature, context, expression.argTypes(context)) {
|
|
||||||
|
|
||||||
override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue {
|
|
||||||
codegen.generateCall(expression, this, data).materialize()
|
|
||||||
return StackValue.onStack(Type.getObjectType("[" + AsmTypes.OBJECT_TYPE.internalName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -213,9 +213,9 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun arrayMethods(arrayClass: IrClassSymbol) = listOf(
|
private fun arrayMethods(arrayClass: IrClassSymbol) = listOf(
|
||||||
arrayClass.constructors.single { it.owner.valueParameters.size == 2 }.toKey()!! to ArrayConstructor,
|
|
||||||
arrayClass.owner.properties.single { it.name.asString() == "size" }.getter!!.symbol.toKey()!! to ArraySize
|
arrayClass.owner.properties.single { it.name.asString() == "size" }.getter!!.symbol.toKey()!! to ArraySize
|
||||||
) +
|
) +
|
||||||
|
arrayClass.constructors.filter { it.owner.valueParameters.size == 1 }.map { it.toKey()!! to NewArray } +
|
||||||
methodWithArity(arrayClass, "set", 2, ArraySet) +
|
methodWithArity(arrayClass, "set", 2, ArraySet) +
|
||||||
methodWithArity(arrayClass, "get", 1, ArrayGet) +
|
methodWithArity(arrayClass, "get", 1, ArrayGet) +
|
||||||
methodWithArity(arrayClass, "clone", 0, Clone) +
|
methodWithArity(arrayClass, "clone", 0, Clone) +
|
||||||
|
|||||||
+6
-21
@@ -6,30 +6,15 @@
|
|||||||
package org.jetbrains.kotlin.backend.jvm.intrinsics
|
package org.jetbrains.kotlin.backend.jvm.intrinsics
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
|
import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
|
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
|
||||||
|
|
||||||
object NewArray : IntrinsicMethod() {
|
object NewArray : IntrinsicMethod() {
|
||||||
|
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
|
||||||
override fun toCallable(
|
codegen.gen(expression.getValueArgument(0)!!, Type.INT_TYPE, data)
|
||||||
expression: IrFunctionAccessExpression,
|
codegen.newArrayInstruction(expression.type)
|
||||||
signature: JvmMethodSignature,
|
return with(codegen) { expression.onStack }
|
||||||
context: JvmBackendContext
|
|
||||||
): IrIntrinsicFunction {
|
|
||||||
val irType = expression.type
|
|
||||||
return object : IrIntrinsicFunction(expression, signature, context) {
|
|
||||||
override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue {
|
|
||||||
super.invoke(v, codegen, data)
|
|
||||||
codegen.newArrayInstruction(irType)
|
|
||||||
return StackValue.onStack(returnType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun genInvokeInstruction(v: InstructionAdapter) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ fun IrBuilderWithScope.irCall(callee: IrSimpleFunctionSymbol, type: IrType): IrC
|
|||||||
fun IrBuilderWithScope.irCall(callee: IrConstructorSymbol, type: IrType): IrConstructorCall =
|
fun IrBuilderWithScope.irCall(callee: IrConstructorSymbol, type: IrType): IrConstructorCall =
|
||||||
IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, type, callee)
|
IrConstructorCallImpl.fromSymbolDescriptor(startOffset, endOffset, type, callee)
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol, type: IrType): IrMemberAccessExpression =
|
fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol, type: IrType): IrFunctionAccessExpression =
|
||||||
when (callee) {
|
when (callee) {
|
||||||
is IrConstructorSymbol -> irCall(callee, type)
|
is IrConstructorSymbol -> irCall(callee, type)
|
||||||
is IrSimpleFunctionSymbol -> irCall(callee, type)
|
is IrSimpleFunctionSymbol -> irCall(callee, type)
|
||||||
@@ -266,13 +266,13 @@ fun IrBuilderWithScope.irCall(callee: IrSimpleFunctionSymbol): IrCall =
|
|||||||
fun IrBuilderWithScope.irCall(callee: IrConstructorSymbol): IrConstructorCall =
|
fun IrBuilderWithScope.irCall(callee: IrConstructorSymbol): IrConstructorCall =
|
||||||
irCall(callee, callee.owner.returnType)
|
irCall(callee, callee.owner.returnType)
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol): IrMemberAccessExpression =
|
fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol): IrFunctionAccessExpression =
|
||||||
irCall(callee, callee.owner.returnType)
|
irCall(callee, callee.owner.returnType)
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol, descriptor: FunctionDescriptor, type: IrType): IrCall =
|
fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol, descriptor: FunctionDescriptor, type: IrType): IrCall =
|
||||||
IrCallImpl(startOffset, endOffset, type, callee as IrSimpleFunctionSymbol, descriptor)
|
IrCallImpl(startOffset, endOffset, type, callee as IrSimpleFunctionSymbol, descriptor)
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(callee: IrFunction): IrMemberAccessExpression =
|
fun IrBuilderWithScope.irCall(callee: IrFunction): IrFunctionAccessExpression =
|
||||||
irCall(callee.symbol)
|
irCall(callee.symbol)
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(callee: IrFunction, origin: IrStatementOrigin): IrCall =
|
fun IrBuilderWithScope.irCall(callee: IrFunction, origin: IrStatementOrigin): IrCall =
|
||||||
|
|||||||
@@ -183,6 +183,8 @@ class IrBuiltIns(
|
|||||||
val primitiveTypes = listOf(bool, char, byte, short, int, long, float, double)
|
val primitiveTypes = listOf(bool, char, byte, short, int, long, float, double)
|
||||||
val primitiveTypesWithComparisons = listOf(char, byte, short, int, long, float, double)
|
val primitiveTypesWithComparisons = listOf(char, byte, short, int, long, float, double)
|
||||||
val primitiveFloatingPointTypes = listOf(float, double)
|
val primitiveFloatingPointTypes = listOf(float, double)
|
||||||
|
val primitiveArrays = PrimitiveType.values().map { builtIns.getPrimitiveArrayClassDescriptor(it).toIrSymbol() }
|
||||||
|
val primitiveArrayElementTypes = primitiveArrays.zip(primitiveIrTypes).toMap()
|
||||||
|
|
||||||
val primitiveTypeToIrType = mapOf(
|
val primitiveTypeToIrType = mapOf(
|
||||||
PrimitiveType.BOOLEAN to booleanType,
|
PrimitiveType.BOOLEAN to booleanType,
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ public class ByteArray(size: Int) {
|
|||||||
* @constructor Creates a new array of the specified [size], with all elements initialized to null char (`\u0000').
|
* @constructor Creates a new array of the specified [size], with all elements initialized to null char (`\u0000').
|
||||||
*/
|
*/
|
||||||
public class CharArray(size: Int) {
|
public class CharArray(size: Int) {
|
||||||
|
/**
|
||||||
|
* Creates a new array of the specified [size], where each element is calculated by calling the specified
|
||||||
|
* [init] function. The [init] function returns an array element given its index.
|
||||||
|
*/
|
||||||
|
public inline constructor(size: Int, init: (Int) -> Char)
|
||||||
|
|
||||||
/** Returns the array element at the given [index]. This method can be called using the index operator. */
|
/** Returns the array element at the given [index]. This method can be called using the index operator. */
|
||||||
public operator fun get(index: Int): Char
|
public operator fun get(index: Int): Char
|
||||||
/** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */
|
/** Sets the element at the given [index] to the given [value]. This method can be called using the index operator. */
|
||||||
@@ -53,17 +59,6 @@ public class CharArray(size: Int) {
|
|||||||
public operator fun iterator(): CharIterator
|
public operator fun iterator(): CharIterator
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun CharArray(size: Int, init: (Int) -> Char): CharArray {
|
|
||||||
val result = CharArray(size)
|
|
||||||
var i = 0
|
|
||||||
while (i != result.size) {
|
|
||||||
result[i] = init(i)
|
|
||||||
++i
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of shorts. When targeting the JVM, instances of this class are represented as `short[]`.
|
* An array of shorts. When targeting the JVM, instances of this class are represented as `short[]`.
|
||||||
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
|
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
|
||||||
|
|||||||
Reference in New Issue
Block a user