[Wasm] Major compiler and stdlib update
This commit is contained in:
@@ -29,6 +29,7 @@ buildscript {
|
||||
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.20")
|
||||
classpath(kotlin("gradle-plugin", bootstrapKotlinVersion))
|
||||
classpath(kotlin("serialization", bootstrapKotlinVersion))
|
||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:0.9.17")
|
||||
classpath("org.jfrog.buildinfo:build-info-extractor-gradle:4.17.2")
|
||||
}
|
||||
|
||||
Generated
+5
@@ -12415,6 +12415,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterAsUpperBound.kt")
|
||||
public void testTypeParameterAsUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParameterAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersInLocalFunction.kt")
|
||||
public void testTypeParametersInLocalFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParametersInLocalFunction.kt");
|
||||
|
||||
@@ -295,6 +295,9 @@ abstract class Symbols<out T : CommonBackendContext>(val context: T, irBuiltIns:
|
||||
|
||||
abstract val throwKotlinNothingValueException: IrSimpleFunctionSymbol
|
||||
|
||||
open val throwISE: IrSimpleFunctionSymbol
|
||||
get() = error("throwISE is not implemented")
|
||||
|
||||
abstract val stringBuilder: IrClassSymbol
|
||||
|
||||
abstract val defaultConstructorMarker: IrClassSymbol
|
||||
|
||||
+8
-4
@@ -271,9 +271,13 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun Name.toInlineClassImplementationName() = when {
|
||||
isSpecial -> Name.special(asString() + INLINE_CLASS_IMPL_SUFFIX)
|
||||
else -> Name.identifier(asString() + INLINE_CLASS_IMPL_SUFFIX)
|
||||
private fun IrFunction.toInlineClassImplementationName(): Name {
|
||||
val klass = this.parentAsClass!!
|
||||
val newName = klass.name.asString() + "__" + name.asString() + INLINE_CLASS_IMPL_SUFFIX
|
||||
return when {
|
||||
name.isSpecial -> Name.special("<" + newName + ">")
|
||||
else -> Name.identifier(newName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectTypeParameters(declaration: IrTypeParametersContainer): List<IrTypeParameter> {
|
||||
@@ -292,7 +296,7 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
||||
private fun createStaticBodilessMethod(function: IrFunction): IrSimpleFunction =
|
||||
context.irFactory.createStaticFunctionWithReceivers(
|
||||
function.parent,
|
||||
function.name.toInlineClassImplementationName(),
|
||||
function.toInlineClassImplementationName(),
|
||||
function,
|
||||
typeParametersFromContext = collectTypeParameters(function.parentAsClass)
|
||||
)
|
||||
|
||||
@@ -284,7 +284,7 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
|
||||
|
||||
when (expression.symbol) {
|
||||
context.intrinsics.jsBoxIntrinsic -> {
|
||||
val inlineClass = expression.getTypeArgument(0)!!.getInlinedClass()!!
|
||||
val inlineClass = context.inlineClassesUtils.getInlinedClass(expression.getTypeArgument(0)!!)!!
|
||||
val constructor = inlineClass.declarations.filterIsInstance<IrConstructor>().single { it.isPrimary }
|
||||
constructor.enqueue("intrinsic: jsBoxIntrinsic")
|
||||
}
|
||||
|
||||
+25
@@ -6,10 +6,35 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isDispatchReceiver
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
|
||||
interface JsCommonBackendContext : CommonBackendContext {
|
||||
override val mapping: JsMapping
|
||||
|
||||
val inlineClassesUtils: InlineClassesUtils
|
||||
|
||||
val es6mode: Boolean
|
||||
get() = false
|
||||
}
|
||||
|
||||
interface InlineClassesUtils {
|
||||
fun isTypeInlined(type: IrType): Boolean
|
||||
|
||||
fun shouldValueParameterBeBoxed(parameter: IrValueParameter): Boolean {
|
||||
val function = parameter.parent as? IrSimpleFunction ?: return false
|
||||
val klass = function.parent as? IrClass ?: return false
|
||||
if (!isClassInlineLike(klass)) return false
|
||||
return parameter.isDispatchReceiver && function.isOverridableOrOverrides
|
||||
}
|
||||
|
||||
fun getInlinedClass(type: IrType): IrClass?
|
||||
|
||||
fun isClassInlineLike(klass: IrClass): Boolean
|
||||
|
||||
val boxIntrinsic: IrSimpleFunctionSymbol
|
||||
val unboxIntrinsic: IrSimpleFunctionSymbol
|
||||
}
|
||||
|
||||
@@ -16,9 +16,8 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.JsInnerClassesSupport
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getInlinedClass
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
@@ -123,6 +122,9 @@ class JsIrBackendContext(
|
||||
get() = testContainerFuns
|
||||
|
||||
override val mapping = JsMapping()
|
||||
|
||||
override val inlineClassesUtils = JsInlineClassesUtils(this)
|
||||
|
||||
val innerClassesSupport = JsInnerClassesSupport(mapping, irFactory)
|
||||
|
||||
companion object {
|
||||
@@ -196,6 +198,9 @@ class JsIrBackendContext(
|
||||
override val defaultConstructorMarker =
|
||||
symbolTable.referenceClass(context.getJsInternalClass("DefaultConstructorMarker"))
|
||||
|
||||
override val throwISE: IrSimpleFunctionSymbol =
|
||||
symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_ISE"))).single())
|
||||
|
||||
override val stringBuilder
|
||||
get() = TODO("not implemented")
|
||||
override val copyRangeTo: Map<ClassDescriptor, IrSimpleFunctionSymbol>
|
||||
@@ -226,7 +231,7 @@ class JsIrBackendContext(
|
||||
}
|
||||
|
||||
override fun unfoldInlineClassType(irType: IrType): IrType? {
|
||||
return irType.getInlinedClass()?.typeWith()
|
||||
return inlineClassesUtils.getInlinedClass(irType)?.typeWith()
|
||||
}
|
||||
|
||||
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
||||
|
||||
@@ -314,6 +314,12 @@ private val enumUsageLoweringPhase = makeBodyLoweringPhase(
|
||||
prerequisite = setOf(enumEntryCreateGetInstancesFunsLoweringPhase)
|
||||
)
|
||||
|
||||
private val externalEnumUsageLoweringPhase = makeBodyLoweringPhase(
|
||||
::ExternalEnumUsagesLowering,
|
||||
name = "ExternalEnumUsagesLowering",
|
||||
description = "Replace external enum entry accesses with field accesses"
|
||||
)
|
||||
|
||||
private val enumEntryRemovalLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::EnumClassRemoveEntriesLowering,
|
||||
name = "EnumEntryRemovalLowering",
|
||||
@@ -535,7 +541,7 @@ private val errorDeclarationLoweringPhase = makeDeclarationTransformerPhase(
|
||||
)
|
||||
|
||||
private val bridgesConstructionPhase = makeDeclarationTransformerPhase(
|
||||
::BridgesConstruction,
|
||||
::JsBridgesConstruction,
|
||||
name = "BridgesConstruction",
|
||||
description = "Generate bridges",
|
||||
prerequisite = setOf(suspendFunctionsLoweringPhase)
|
||||
@@ -712,6 +718,7 @@ val loweringList = listOf<Lowering>(
|
||||
enumEntryCreateGetInstancesFunsLoweringPhase,
|
||||
enumSyntheticFunsLoweringPhase,
|
||||
enumUsageLoweringPhase,
|
||||
externalEnumUsageLoweringPhase,
|
||||
enumEntryRemovalLoweringPhase,
|
||||
suspendFunctionsLoweringPhase,
|
||||
propertyReferenceLoweringPhase,
|
||||
|
||||
+93
-82
@@ -7,20 +7,26 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.AbstractValueUsageTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getInlinedClass
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isInlined
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
|
||||
|
||||
// Copied and adapted from Kotlin/Native
|
||||
|
||||
class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsageTransformer(context.irBuiltIns), BodyLoweringPass {
|
||||
abstract class AbstractValueUsageLowering(val context: JsCommonBackendContext) : AbstractValueUsageTransformer(context.irBuiltIns),
|
||||
BodyLoweringPass {
|
||||
|
||||
val icUtils = context.inlineClassesUtils
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
// TODO workaround for callable references
|
||||
@@ -35,36 +41,27 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
|
||||
irBody.patchDeclarationParents(container as? IrDeclarationParent ?: container.parent)
|
||||
}
|
||||
|
||||
private tailrec fun IrExpression.isGetUnit(): Boolean =
|
||||
when(this) {
|
||||
is IrContainerExpression ->
|
||||
when (val lastStmt = this.statements.lastOrNull()) {
|
||||
is IrExpression -> lastStmt.isGetUnit()
|
||||
else -> false
|
||||
}
|
||||
|
||||
is IrGetObjectValue ->
|
||||
this.symbol == irBuiltIns.unitClass
|
||||
|
||||
else -> false
|
||||
}
|
||||
abstract fun IrExpression.useExpressionAsType(actualType: IrType, expectedType: IrType): IrExpression
|
||||
|
||||
override fun IrExpression.useAs(type: IrType): IrExpression {
|
||||
|
||||
val actualType = when (this) {
|
||||
is IrConstructorCall -> symbol.owner.returnType
|
||||
is IrCall -> symbol.owner.realOverrideTarget.returnType
|
||||
is IrGetField -> this.symbol.owner.type
|
||||
|
||||
is IrTypeOperatorCall -> {
|
||||
assert(operator == IrTypeOperator.REINTERPRET_CAST) { "Only REINTERPRET_CAST expected at this point" }
|
||||
this.typeOperand
|
||||
if (operator == IrTypeOperator.REINTERPRET_CAST) {
|
||||
this.typeOperand
|
||||
} else {
|
||||
this.type
|
||||
}
|
||||
}
|
||||
|
||||
is IrGetValue -> {
|
||||
val value = this.symbol.owner
|
||||
if (value is IrValueParameter && value.isDispatchReceiver) {
|
||||
irBuiltIns.anyNType
|
||||
if (value is IrValueParameter && icUtils.shouldValueParameterBeBoxed(value)) {
|
||||
irBuiltIns.anyType
|
||||
} else {
|
||||
this.type
|
||||
}
|
||||
@@ -73,12 +70,60 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
|
||||
else -> this.type
|
||||
}
|
||||
|
||||
return useExpressionAsType(actualType, type)
|
||||
}
|
||||
|
||||
|
||||
private val IrFunctionAccessExpression.target: IrFunction
|
||||
get() = when (this) {
|
||||
is IrConstructorCall -> this.symbol.owner
|
||||
is IrDelegatingConstructorCall -> this.symbol.owner
|
||||
is IrCall -> this.callTarget
|
||||
else -> TODO(this.render())
|
||||
}
|
||||
|
||||
private val IrCall.callTarget: IrFunction
|
||||
get() = symbol.owner.realOverrideTarget
|
||||
|
||||
|
||||
override fun IrExpression.useAsDispatchReceiver(expression: IrFunctionAccessExpression): IrExpression {
|
||||
return if (expression.symbol.owner.dispatchReceiverParameter?.let { icUtils.shouldValueParameterBeBoxed(it) } == true)
|
||||
this.useAs(irBuiltIns.anyType)
|
||||
else
|
||||
this.useAsArgument(expression.target.dispatchReceiverParameter!!)
|
||||
}
|
||||
|
||||
override fun IrExpression.useAsExtensionReceiver(expression: IrFunctionAccessExpression): IrExpression {
|
||||
return this.useAsArgument(expression.target.extensionReceiverParameter!!)
|
||||
}
|
||||
|
||||
override fun IrExpression.useAsValueArgument(
|
||||
expression: IrFunctionAccessExpression,
|
||||
parameter: IrValueParameter
|
||||
): IrExpression {
|
||||
|
||||
return this.useAsArgument(expression.target.valueParameters[parameter.index])
|
||||
}
|
||||
|
||||
|
||||
override fun IrExpression.useAsVarargElement(expression: IrVararg): IrExpression {
|
||||
return this.useAs(
|
||||
// Do not box primitive inline classes
|
||||
if (icUtils.isTypeInlined(type) && !icUtils.isTypeInlined(expression.type) && !expression.type.isPrimitiveArray())
|
||||
irBuiltIns.anyNType
|
||||
else
|
||||
expression.varargElementType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AutoboxingTransformer(context: JsCommonBackendContext) : AbstractValueUsageLowering(context) {
|
||||
override fun IrExpression.useExpressionAsType(actualType: IrType, expectedType: IrType): IrExpression {
|
||||
// // TODO: Default parameters are passed as nulls and they need not to be unboxed. Fix this
|
||||
|
||||
if (actualType.makeNotNull().isNothing())
|
||||
return this
|
||||
|
||||
val expectedType = type
|
||||
|
||||
if (actualType.isUnit() && !expectedType.isUnit()) {
|
||||
// Don't materialize Unit if value is known to be proper Unit on runtime
|
||||
if (!this.isGetUnit()) {
|
||||
@@ -87,8 +132,8 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
|
||||
}
|
||||
}
|
||||
|
||||
val actualInlinedClass = actualType.getInlinedClass()
|
||||
val expectedInlinedClass = expectedType.getInlinedClass()
|
||||
val actualInlinedClass = icUtils.getInlinedClass(actualType)
|
||||
val expectedInlinedClass = icUtils.getInlinedClass(expectedType)
|
||||
|
||||
// Mimicking behaviour of current JS backend
|
||||
// TODO: Revisit
|
||||
@@ -99,8 +144,8 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
|
||||
|
||||
val function = when {
|
||||
actualInlinedClass == null && expectedInlinedClass == null -> return this
|
||||
actualInlinedClass != null && expectedInlinedClass == null -> context.intrinsics.jsBoxIntrinsic
|
||||
actualInlinedClass == null && expectedInlinedClass != null -> context.intrinsics.jsUnboxIntrinsic
|
||||
actualInlinedClass != null && expectedInlinedClass == null -> icUtils.boxIntrinsic
|
||||
actualInlinedClass == null && expectedInlinedClass != null -> icUtils.unboxIntrinsic
|
||||
else -> return this
|
||||
}
|
||||
|
||||
@@ -115,14 +160,31 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
|
||||
}
|
||||
}
|
||||
|
||||
private tailrec fun IrExpression.isGetUnit(): Boolean =
|
||||
when (this) {
|
||||
is IrContainerExpression ->
|
||||
when (val lastStmt = this.statements.lastOrNull()) {
|
||||
is IrExpression -> lastStmt.isGetUnit()
|
||||
else -> false
|
||||
}
|
||||
|
||||
is IrGetObjectValue ->
|
||||
this.symbol == irBuiltIns.unitClass
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun buildSafeCall(
|
||||
arg: IrExpression,
|
||||
actualType: IrType,
|
||||
resultType: IrType,
|
||||
call: (IrExpression) -> IrExpression
|
||||
): IrExpression {
|
||||
if (!actualType.isNullable())
|
||||
// Safe call is only needed if we cast from Nullable type to Nullable type.
|
||||
// Otherwise, null value cannot occur.
|
||||
if (!actualType.isNullable() || !resultType.isNullable())
|
||||
return call(arg)
|
||||
|
||||
return JsIrBuilder.run {
|
||||
// TODO: Set parent of local variables
|
||||
val tmp = buildVar(actualType, parent = null, initializer = arg)
|
||||
@@ -144,55 +206,4 @@ class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsag
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val IrFunctionAccessExpression.target: IrFunction
|
||||
get() = when (this) {
|
||||
is IrConstructorCall -> this.symbol.owner
|
||||
is IrDelegatingConstructorCall -> this.symbol.owner
|
||||
is IrCall -> this.callTarget
|
||||
else -> TODO(this.render())
|
||||
}
|
||||
|
||||
private val IrCall.callTarget: IrFunction
|
||||
get() = symbol.owner.realOverrideTarget
|
||||
|
||||
|
||||
override fun IrExpression.useAsDispatchReceiver(expression: IrFunctionAccessExpression): IrExpression {
|
||||
return this.useAsArgument(expression.target.dispatchReceiverParameter!!)
|
||||
}
|
||||
|
||||
override fun IrExpression.useAsExtensionReceiver(expression: IrFunctionAccessExpression): IrExpression {
|
||||
return this.useAsArgument(expression.target.extensionReceiverParameter!!)
|
||||
}
|
||||
|
||||
override fun IrExpression.useAsValueArgument(
|
||||
expression: IrFunctionAccessExpression,
|
||||
parameter: IrValueParameter
|
||||
): IrExpression {
|
||||
|
||||
return this.useAsArgument(expression.target.valueParameters[parameter.index])
|
||||
}
|
||||
|
||||
|
||||
override fun IrExpression.useAsVarargElement(expression: IrVararg): IrExpression {
|
||||
return this.useAs(
|
||||
// Do not box primitive inline classes
|
||||
if (this.type.isInlined() && !expression.type.isInlined() && !expression.type.isPrimitiveArray())
|
||||
irBuiltIns.anyNType
|
||||
else
|
||||
expression.varargElementType
|
||||
)
|
||||
}
|
||||
|
||||
private val IrValueParameter.isDispatchReceiver: Boolean
|
||||
get() {
|
||||
val parent = this.parent
|
||||
if (parent is IrClass)
|
||||
return true
|
||||
if (parent is IrFunction && parent.dispatchReceiverParameter == this)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+38
-25
@@ -15,8 +15,8 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.functionSignature
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -45,10 +45,15 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
// }
|
||||
//
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class BridgesConstruction(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
abstract class BridgesConstruction(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private val specialBridgeMethods = SpecialBridgeMethods(context)
|
||||
|
||||
abstract fun getFunctionSignature(function: IrSimpleFunction): Any
|
||||
|
||||
// Should dispatch receiver type be casted inside a bridge.
|
||||
open val shouldCastDispatchReceiver: Boolean = false
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration !is IrSimpleFunction || declaration.isStaticMethodOfClass || declaration.parent !is IrClass) return null
|
||||
|
||||
@@ -56,10 +61,6 @@ class BridgesConstruction(val context: JsCommonBackendContext) : DeclarationTran
|
||||
}
|
||||
|
||||
private fun generateBridges(function: IrSimpleFunction): List<IrDeclaration>? {
|
||||
// equals(Any?), hashCode(), toString() never need bridges
|
||||
if (function.isMethodOfAny())
|
||||
return null
|
||||
|
||||
val (specialOverride: IrSimpleFunction?, specialOverrideInfo) =
|
||||
specialBridgeMethods.findSpecialWithOverride(function) ?: Pair(null, null)
|
||||
|
||||
@@ -83,6 +84,11 @@ class BridgesConstruction(val context: JsCommonBackendContext) : DeclarationTran
|
||||
continue
|
||||
}
|
||||
|
||||
// Don't build bridges for functions with the same signature.
|
||||
// TODO: This should be caught earlier in bridgesToGenerate
|
||||
if (FunctionAndSignature(to.function.realOverrideTarget) == FunctionAndSignature(from.function.realOverrideTarget))
|
||||
continue
|
||||
|
||||
if (from.function.correspondingPropertySymbol != null && from.function.isEffectivelyExternal()) {
|
||||
// TODO: Revisit bridges from external properties
|
||||
continue
|
||||
@@ -150,7 +156,13 @@ class BridgesConstruction(val context: JsCommonBackendContext) : DeclarationTran
|
||||
}
|
||||
|
||||
val call = irCall(delegateTo.symbol)
|
||||
call.dispatchReceiver = irGet(irFunction.dispatchReceiverParameter!!)
|
||||
val dispatchReceiver = irGet(irFunction.dispatchReceiverParameter!!)
|
||||
|
||||
call.dispatchReceiver = if (shouldCastDispatchReceiver)
|
||||
irCastIfNeeded(dispatchReceiver, delegateTo.dispatchReceiverParameter!!.type)
|
||||
else
|
||||
dispatchReceiver
|
||||
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
call.extensionReceiver = irCastIfNeeded(irGet(it), delegateTo.extensionReceiverParameter!!.type)
|
||||
}
|
||||
@@ -171,6 +183,25 @@ class BridgesConstruction(val context: JsCommonBackendContext) : DeclarationTran
|
||||
// TODO: get rid of Unit check
|
||||
private fun IrBlockBodyBuilder.irCastIfNeeded(argument: IrExpression, type: IrType): IrExpression =
|
||||
if (argument.type.classifierOrNull == type.classifierOrNull) argument else irAs(argument, type)
|
||||
|
||||
// Wrapper around function that compares and hashCodes it based on signature
|
||||
// Designed to be used as a Signature type parameter in backend.common.bridges
|
||||
inner class FunctionAndSignature(val function: IrSimpleFunction) {
|
||||
|
||||
// TODO: Use type-upper-bound-based signature instead of Strings
|
||||
// Currently strings are used for compatibility with a hack-based name generator
|
||||
|
||||
private val signature = getFunctionSignature(function)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is BridgesConstruction.FunctionAndSignature) return false
|
||||
|
||||
return signature == other.signature
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = signature.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle for common.bridges
|
||||
@@ -187,23 +218,5 @@ data class IrBasedFunctionHandle(val function: IrSimpleFunction) : FunctionHandl
|
||||
function.overriddenSymbols.map { IrBasedFunctionHandle(it.owner) }
|
||||
}
|
||||
|
||||
// Wrapper around function that compares and hashCodes it based on signature
|
||||
// Designed to be used as a Signature type parameter in backend.common.bridges
|
||||
class FunctionAndSignature(val function: IrSimpleFunction) {
|
||||
|
||||
// TODO: Use type-upper-bound-based signature instead of Strings
|
||||
// Currently strings are used for compatibility with a hack-based name generator
|
||||
|
||||
private val signature = functionSignature(function)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is FunctionAndSignature) return false
|
||||
|
||||
return signature == other.signature
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = signature.hashCode()
|
||||
}
|
||||
|
||||
|
||||
|
||||
+14
-60
@@ -17,18 +17,14 @@ import org.jetbrains.kotlin.backend.common.lower.parents
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.toJsArrayLiteral
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
@@ -36,7 +32,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class EnumUsageLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
class EnumUsageLowering(val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||
private var IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
@@ -44,41 +40,13 @@ class EnumUsageLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
|
||||
val enumEntry = expression.symbol.owner
|
||||
val klass = enumEntry.parent as IrClass
|
||||
return if (klass.isExternal) lowerExternalEnumEntry(enumEntry, klass) else lowerEnumEntry(enumEntry)
|
||||
if (klass.isExternal) return expression
|
||||
return lowerEnumEntry(enumEntry, klass)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun lowerExternalEnumEntry(enumEntry: IrEnumEntry, klass: IrClass) =
|
||||
context.mapping.enumEntryToInstanceField.getOrPut(enumEntry) { createFieldForEntry(enumEntry, klass) }.let {
|
||||
JsIrBuilder.buildGetField(it.symbol, classAsReceiver(klass), null, klass.defaultType)
|
||||
}
|
||||
|
||||
private fun classAsReceiver(irClass: IrClass): IrExpression {
|
||||
val intrinsic = context.intrinsics.jsClass
|
||||
return JsIrBuilder.buildCall(intrinsic, context.irBuiltIns.anyType, listOf(irClass.defaultType))
|
||||
}
|
||||
|
||||
private fun createFieldForEntry(entry: IrEnumEntry, irClass: IrClass): IrField =
|
||||
context.irFactory.buildField {
|
||||
startOffset = entry.startOffset
|
||||
endOffset = entry.endOffset
|
||||
origin = entry.origin
|
||||
name = entry.name
|
||||
type = irClass.defaultType
|
||||
isFinal = false
|
||||
isExternal = true
|
||||
isStatic = true
|
||||
}.also {
|
||||
it.parent = irClass
|
||||
|
||||
// TODO need a way to emerge local declarations from BodyLoweringPass
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
irClass.declarations += it
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerEnumEntry(enumEntry: IrEnumEntry) =
|
||||
private fun lowerEnumEntry(enumEntry: IrEnumEntry, klass: IrClass) =
|
||||
enumEntry.getInstanceFun!!.run { JsIrBuilder.buildCall(symbol) }
|
||||
}
|
||||
|
||||
@@ -313,7 +281,7 @@ class EnumClassConstructorBodyTransformer(val context: JsCommonBackendContext) :
|
||||
private val IrClass.goodEnum: Boolean
|
||||
get() = isEnumClass && !isExpect && !isEffectivelyExternal()
|
||||
|
||||
class EnumEntryInstancesLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
class EnumEntryInstancesLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||
|
||||
@@ -346,7 +314,7 @@ class EnumEntryInstancesLowering(val context: JsIrBackendContext) : DeclarationT
|
||||
}
|
||||
}
|
||||
|
||||
class EnumEntryInstancesBodyLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
class EnumEntryInstancesBodyLowering(val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||
|
||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||
|
||||
@@ -370,7 +338,7 @@ class EnumEntryInstancesBodyLowering(val context: JsIrBackendContext) : BodyLowe
|
||||
}
|
||||
}
|
||||
|
||||
class EnumClassCreateInitializerLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
class EnumClassCreateInitializerLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
||||
@@ -431,7 +399,7 @@ class EnumClassCreateInitializerLowering(val context: JsIrBackendContext) : Decl
|
||||
}
|
||||
}
|
||||
|
||||
class EnumEntryCreateGetInstancesFunsLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
||||
@@ -477,7 +445,7 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsIrBackendContext) :
|
||||
}
|
||||
}
|
||||
|
||||
class EnumSyntheticFunctionsLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
class EnumSyntheticFunctionsLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private var IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun
|
||||
|
||||
@@ -500,7 +468,7 @@ class EnumSyntheticFunctionsLowering(val context: JsIrBackendContext) : Declarat
|
||||
return null
|
||||
}
|
||||
|
||||
private val throwISESymbol = context.throwISEsymbol
|
||||
private val throwISESymbol = context.ir.symbols.throwISE
|
||||
|
||||
private fun createEnumValueOfBody(valueOfFun: IrFunction, irClass: IrClass): IrBlockBody {
|
||||
val nameParameter = valueOfFun.valueParameters[0]
|
||||
@@ -521,26 +489,12 @@ class EnumSyntheticFunctionsLowering(val context: JsIrBackendContext) : Declarat
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<IrExpression>.toArrayLiteral(arrayType: IrType, elementType: IrType): IrExpression {
|
||||
val irVararg = IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, elementType, this)
|
||||
|
||||
return IrCallImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType,
|
||||
context.intrinsics.arrayLiteral,
|
||||
typeArgumentsCount = 0,
|
||||
valueArgumentsCount = 1
|
||||
).apply {
|
||||
putValueArgument(0, irVararg)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEnumValuesBody(valuesFun: IrFunction, irClass: IrClass): IrBlockBody {
|
||||
val backendContext = context
|
||||
return context.createIrBuilder(valuesFun.symbol).run {
|
||||
irBlockBody {
|
||||
val instances = irClass.enumEntries.map { irCall(it.getInstanceFun!!) }
|
||||
+irReturn(
|
||||
irClass.enumEntries.map { irCall(it.getInstanceFun!!) }
|
||||
.toJsArrayLiteral(backendContext, valuesFun.returnType, irClass.defaultType)
|
||||
IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, valuesFun.returnType, irClass.defaultType, instances)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -551,7 +505,7 @@ private val IrClass.enumEntries: List<IrEnumEntry>
|
||||
get() = declarations.filterIsInstance<IrEnumEntry>()
|
||||
|
||||
// Should be applied recursively
|
||||
class EnumClassRemoveEntriesLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
class EnumClassRemoveEntriesLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
// Remove IrEnumEntry nodes from class declarations. Replace them with corresponding class declarations (if they have them).
|
||||
if (declaration is IrEnumEntry && !declaration.isExpect && !declaration.isEffectivelyExternal()) {
|
||||
@@ -560,4 +514,4 @@ class EnumClassRemoveEntriesLowering(val context: JsIrBackendContext) : Declarat
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class ExternalEnumUsagesLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
|
||||
val enumEntry = expression.symbol.owner
|
||||
val klass = enumEntry.parent as IrClass
|
||||
return if (klass.isExternal) lowerExternalEnumEntry(enumEntry, klass) else expression
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun lowerExternalEnumEntry(enumEntry: IrEnumEntry, klass: IrClass) =
|
||||
context.mapping.enumEntryToInstanceField.getOrPut(enumEntry) { createFieldForEntry(enumEntry, klass) }.let {
|
||||
JsIrBuilder.buildGetField(it.symbol, classAsReceiver(klass), null, klass.defaultType)
|
||||
}
|
||||
|
||||
private fun classAsReceiver(irClass: IrClass): IrExpression {
|
||||
val intrinsic = context.intrinsics.jsClass
|
||||
return JsIrBuilder.buildCall(intrinsic, context.irBuiltIns.anyType, listOf(irClass.defaultType))
|
||||
}
|
||||
|
||||
private fun createFieldForEntry(entry: IrEnumEntry, irClass: IrClass): IrField =
|
||||
context.irFactory.buildField {
|
||||
startOffset = entry.startOffset
|
||||
endOffset = entry.endOffset
|
||||
origin = entry.origin
|
||||
name = entry.name
|
||||
type = irClass.defaultType
|
||||
isFinal = false
|
||||
isExternal = true
|
||||
isStatic = true
|
||||
}.also {
|
||||
it.parent = irClass
|
||||
|
||||
// TODO need a way to emerge local declarations from BodyLoweringPass
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
irClass.declarations += it
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Signature
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.jsFunctionSignature
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
|
||||
class JsBridgesConstruction(context: JsCommonBackendContext) : BridgesConstruction(context) {
|
||||
override fun getFunctionSignature(function: IrSimpleFunction): Signature =
|
||||
jsFunctionSignature(function)
|
||||
}
|
||||
+3
-2
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -13,7 +14,7 @@ import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
|
||||
// Move static member declarations from classes to top level
|
||||
class StaticMembersLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
class StaticMembersLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
(declaration.parent as? IrClass)?.let { irClass ->
|
||||
val isStatic = when (declaration) {
|
||||
@@ -26,7 +27,7 @@ class StaticMembersLowering(val context: JsIrBackendContext) : DeclarationTransf
|
||||
if (isStatic) {
|
||||
// JsExport might be inherited from parent declaration which would be broken if we move it out of its parent.
|
||||
// Marking declaration as exported explicitly.
|
||||
if (declaration.isExported(context)) {
|
||||
if (context is JsIrBackendContext && declaration.isExported(context)) {
|
||||
context.additionalExportedDeclarations.add(declaration)
|
||||
}
|
||||
var extractedUnder = declaration
|
||||
|
||||
+3
-2
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getInlinedClass
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isPure
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
@@ -64,6 +63,8 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val litFalse: IrExpression get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
private val litNull: IrExpression get() = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
|
||||
|
||||
private val icUtils = context.inlineClassesUtils
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
|
||||
override fun visitDeclaration(declaration: IrDeclarationBase, data: IrDeclarationParent) =
|
||||
@@ -102,7 +103,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
}
|
||||
|
||||
private fun needBoxingOrUnboxing(fromType: IrType, toType: IrType): Boolean {
|
||||
return ((fromType.getInlinedClass() != null) xor (toType.getInlinedClass() != null)) || (fromType.isUnit() && !toType.isUnit())
|
||||
return ((icUtils.getInlinedClass(fromType) != null) xor (icUtils.getInlinedClass(toType) != null)) || (fromType.isUnit() && !toType.isUnit())
|
||||
}
|
||||
|
||||
private fun IrTypeOperatorCall.wrapWithUnsafeCast(arg: IrExpression): IrExpression {
|
||||
|
||||
+2
-1
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getInlinedClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
@@ -32,6 +31,8 @@ private class VarargTransformer(
|
||||
val context: JsIrBackendContext
|
||||
) : IrElementTransformerVoid() {
|
||||
|
||||
fun IrType.getInlinedClass() = context.inlineClassesUtils.getInlinedClass(this)
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
private fun List<IrExpression>.toArrayLiteral(type: IrType, varargElementType: IrType): IrExpression {
|
||||
|
||||
|
||||
+8
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.util.explicitParameters
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
@@ -225,6 +226,13 @@ class JsSuspendFunctionsLowering(ctx: JsIrBackendContext) : AbstractSuspendFunct
|
||||
return result
|
||||
}
|
||||
|
||||
private fun needUnboxingOrUnit(fromType: IrType, toType: IrType): Boolean {
|
||||
val icUtils = context.inlineClassesUtils
|
||||
|
||||
return (icUtils.getInlinedClass(fromType) == null && icUtils.getInlinedClass(toType) != null) ||
|
||||
(fromType.isUnit() && !toType.isUnit())
|
||||
}
|
||||
|
||||
override fun IrBuilderWithScope.generateDelegatedCall(expectedType: IrType, delegatingCall: IrExpression): IrExpression {
|
||||
val fromType = (delegatingCall as? IrCall)?.symbol?.owner?.returnType ?: delegatingCall.type
|
||||
if (!needUnboxingOrUnit(fromType, expectedType)) return delegatingCall
|
||||
|
||||
+3
-4
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
|
||||
import org.jetbrains.kotlin.backend.common.ir.isSuspend
|
||||
import org.jetbrains.kotlin.backend.common.peek
|
||||
@@ -14,9 +13,9 @@ import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isPure
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getInlinedClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -69,7 +68,7 @@ class DispatchPointTransformer(val action: (SuspendState) -> IrExpression) : IrE
|
||||
|
||||
class StateMachineBuilder(
|
||||
private val suspendableNodes: MutableSet<IrElement>,
|
||||
val context: CommonBackendContext,
|
||||
val context: JsCommonBackendContext,
|
||||
val function: IrFunctionSymbol,
|
||||
private val rootLoop: IrLoop,
|
||||
private val exceptionSymbolGetter: IrSimpleFunction,
|
||||
@@ -279,7 +278,7 @@ class StateMachineBuilder(
|
||||
if (expression.isSuspend) {
|
||||
val result = lastExpression()
|
||||
val expectedType = expression.symbol.owner.returnType
|
||||
val isInlineClassExpected = expectedType.getInlinedClass() != null
|
||||
val isInlineClassExpected = context.inlineClassesUtils.getInlinedClass(expectedType) != null
|
||||
val continueState = SuspendState(unit)
|
||||
val unboxState = if (isInlineClassExpected) SuspendState(unit) else null
|
||||
|
||||
|
||||
-6
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.ir.isSuspend
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getInlinedClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
@@ -106,9 +105,4 @@ class LiveLocalsTransformer(
|
||||
JsIrBuilder.buildComposite(declaration.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun needUnboxingOrUnit(fromType: IrType, toType: IrType): Boolean {
|
||||
return (fromType.getInlinedClass() == null && toType.getInlinedClass() != null) ||
|
||||
(fromType.isUnit() && !toType.isUnit())
|
||||
}
|
||||
+3
-3
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getInlinedClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||
@@ -27,6 +26,7 @@ typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpres
|
||||
|
||||
class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
private val transformers: Map<IrSymbol, IrCallTransformer>
|
||||
val icUtils = backendContext.inlineClassesUtils
|
||||
|
||||
init {
|
||||
val intrinsics = backendContext.intrinsics
|
||||
@@ -188,14 +188,14 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
|
||||
add(intrinsics.jsBoxIntrinsic) { call, context ->
|
||||
val arg = translateCallArguments(call, context).single()
|
||||
val inlineClass = call.getTypeArgument(0)!!.getInlinedClass()!!
|
||||
val inlineClass = icUtils.getInlinedClass(call.getTypeArgument(0)!!)!!
|
||||
val constructor = inlineClass.declarations.filterIsInstance<IrConstructor>().single { it.isPrimary }
|
||||
JsNew(context.getNameForConstructor(constructor).makeRef(), listOf(arg))
|
||||
}
|
||||
|
||||
add(intrinsics.jsUnboxIntrinsic) { call, context ->
|
||||
val arg = translateCallArguments(call, context).single()
|
||||
val inlineClass = call.getTypeArgument(1)!!.getInlinedClass()!!
|
||||
val inlineClass = icUtils.getInlinedClass(call.getTypeArgument(1)!!)!!
|
||||
val field = getInlineClassBackingField(inlineClass)
|
||||
val fieldName = context.getNameForField(field)
|
||||
JsNameRef(fieldName, arg)
|
||||
|
||||
@@ -45,7 +45,7 @@ private fun IrClassifierSymbol.asString() = when (this) {
|
||||
/**
|
||||
* Returns inline class for given class or null of type is not inlined
|
||||
*/
|
||||
fun IrType.getInlinedClass(): IrClass? {
|
||||
fun IrType.getJsInlinedClass(): IrClass? {
|
||||
if (this is IrSimpleType) {
|
||||
val erased = erase(this) ?: return null
|
||||
if (erased.isInline) {
|
||||
@@ -58,7 +58,7 @@ fun IrType.getInlinedClass(): IrClass? {
|
||||
return null
|
||||
}
|
||||
|
||||
fieldInlinedClass = fieldType.getInlinedClass() ?: break
|
||||
fieldInlinedClass = fieldType.getJsInlinedClass() ?: break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,8 +68,6 @@ fun IrType.getInlinedClass(): IrClass? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun IrType.isInlined(): Boolean = this.getInlinedClass() != null
|
||||
|
||||
tailrec fun erase(type: IrType): IrClass? {
|
||||
val classifier = type.classifierOrFail
|
||||
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.utils
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.InlineClassesUtils
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isMarkedNullable
|
||||
import org.jetbrains.kotlin.ir.util.getInlineClassUnderlyingType
|
||||
|
||||
class JsInlineClassesUtils(val context: JsIrBackendContext) : InlineClassesUtils {
|
||||
override fun isTypeInlined(type: IrType): Boolean {
|
||||
return getInlinedClass(type) != null
|
||||
}
|
||||
|
||||
override fun getInlinedClass(type: IrType): IrClass? =
|
||||
type.getJsInlinedClass()
|
||||
|
||||
override fun isClassInlineLike(klass: IrClass): Boolean =
|
||||
klass.isInline
|
||||
|
||||
override val boxIntrinsic: IrSimpleFunctionSymbol
|
||||
get() = context.intrinsics.jsBoxIntrinsic
|
||||
|
||||
override val unboxIntrinsic: IrSimpleFunctionSymbol
|
||||
get() = context.intrinsics.jsUnboxIntrinsic
|
||||
}
|
||||
@@ -104,7 +104,7 @@ fun fieldSignature(field: IrField): Signature {
|
||||
return BackingFieldSignature(field)
|
||||
}
|
||||
|
||||
fun functionSignature(declaration: IrFunction): Signature {
|
||||
fun jsFunctionSignature(declaration: IrFunction): Signature {
|
||||
require(!declaration.isStaticMethodOfClass)
|
||||
require(declaration.dispatchReceiverParameter != null)
|
||||
|
||||
@@ -143,7 +143,7 @@ fun functionSignature(declaration: IrFunction): Signature {
|
||||
declaration.returnType.let {
|
||||
// Return type is only used in signature for inline class and Unit types because
|
||||
// they are binary incompatible with supertypes.
|
||||
if (it.isInlined() || it.isUnit()) {
|
||||
if (it.getJsInlinedClass() != null || it.isUnit()) {
|
||||
nameBuilder.append("_ret$${it.asString()}")
|
||||
}
|
||||
}
|
||||
@@ -286,7 +286,7 @@ class NameTables(
|
||||
}
|
||||
|
||||
private fun generateNameForMemberFunction(declaration: IrSimpleFunction) {
|
||||
when (val signature = functionSignature(declaration)) {
|
||||
when (val signature = jsFunctionSignature(declaration)) {
|
||||
is StableNameSignature -> memberNames.declareStableName(signature, signature.name)
|
||||
is ParameterTypeBasedSignature -> memberNames.declareFreshName(signature, signature.suggestedName)
|
||||
}
|
||||
@@ -335,7 +335,7 @@ class NameTables(
|
||||
}
|
||||
|
||||
fun getNameForMemberFunction(function: IrSimpleFunction): String {
|
||||
val signature = functionSignature(function)
|
||||
val signature = jsFunctionSignature(function)
|
||||
val name = memberNames.names[signature] ?: mappedNames[mapToKey(signature)]
|
||||
|
||||
// TODO Add a compiler flag, which enables this behaviour
|
||||
|
||||
@@ -79,4 +79,14 @@ fun IrExpression?.isPure(anyVariable: Boolean, checkFields: Boolean = true): Boo
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
val IrValueDeclaration.isDispatchReceiver: Boolean
|
||||
get() {
|
||||
val parent = this.parent
|
||||
if (parent is IrClass)
|
||||
return true
|
||||
if (parent is IrFunction && parent.dispatchReceiverParameter == this)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
@@ -12,6 +12,7 @@ dependencies {
|
||||
compile(project(":compiler:ir.backend.common"))
|
||||
compile(project(":compiler:ir.serialization.common"))
|
||||
compile(project(":compiler:ir.serialization.js"))
|
||||
compile(project(":compiler:ir.tree.persistent"))
|
||||
compile(project(":js:js.ast"))
|
||||
compile(project(":js:js.frontend"))
|
||||
compile(project(":compiler:backend.js"))
|
||||
|
||||
+54
-8
@@ -7,24 +7,36 @@ package org.jetbrains.kotlin.backend.wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.backend.common.ir.addChild
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmSharedVariablesManager
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.WasmInlineClassesUtils
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.SourceManager
|
||||
import org.jetbrains.kotlin.ir.SourceRangeInfo
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsMapping
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsSharedVariablesManager
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.JsInnerClassesSupport
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class WasmBackendContext(
|
||||
val module: ModuleDescriptor,
|
||||
@@ -43,10 +55,12 @@ class WasmBackendContext(
|
||||
override val irFactory: IrFactory = PersistentIrFactory
|
||||
|
||||
// Place to store declarations excluded from code generation
|
||||
val excludedDeclarations: IrPackageFragment by lazy {
|
||||
private val excludedDeclarations = mutableMapOf<FqName, IrPackageFragment>()
|
||||
|
||||
fun getExcludedPackageFragment(fqName: FqName): IrPackageFragment = excludedDeclarations.getOrPut(fqName) {
|
||||
IrExternalPackageFragmentImpl(
|
||||
DescriptorlessExternalPackageFragmentSymbol(),
|
||||
FqName("kotlin")
|
||||
fqName
|
||||
)
|
||||
}
|
||||
|
||||
@@ -54,14 +68,44 @@ class WasmBackendContext(
|
||||
|
||||
val innerClassesSupport = JsInnerClassesSupport(mapping, irFactory)
|
||||
|
||||
val objectToGetInstanceFunction = mutableMapOf<IrClassSymbol, IrSimpleFunction>()
|
||||
override val internalPackageFqn = FqName("kotlin.wasm")
|
||||
|
||||
private val internalPackageFragment = IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment(
|
||||
builtIns.builtInsModule, FqName("kotlin.wasm.internal")
|
||||
)
|
||||
private val internalPackageFragmentDescriptor = EmptyPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.wasm.internal"))
|
||||
// TODO: Merge with JS IR Backend context lazy file
|
||||
val internalPackageFragment by lazy {
|
||||
IrFileImpl(object : SourceManager.FileEntry {
|
||||
override val name = "<implicitDeclarations>"
|
||||
override val maxOffset = UNDEFINED_OFFSET
|
||||
|
||||
override val sharedVariablesManager = JsSharedVariablesManager(TODO("..."))
|
||||
override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int) =
|
||||
SourceRangeInfo(
|
||||
"",
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET
|
||||
)
|
||||
|
||||
override fun getLineNumber(offset: Int) = UNDEFINED_OFFSET
|
||||
override fun getColumnNumber(offset: Int) = UNDEFINED_OFFSET
|
||||
}, internalPackageFragmentDescriptor).also {
|
||||
irModuleFragment.files += it
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val startFunction = irFactory.buildFun {
|
||||
name = Name.identifier("startFunction")
|
||||
returnType = irBuiltIns.unitType
|
||||
}.apply {
|
||||
body = irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
||||
internalPackageFragment.addChild(this)
|
||||
}
|
||||
|
||||
override val sharedVariablesManager =
|
||||
WasmSharedVariablesManager(this, irBuiltIns, internalPackageFragment)
|
||||
|
||||
val wasmSymbols: WasmSymbols = WasmSymbols(this@WasmBackendContext, symbolTable)
|
||||
override val ir = object : Ir<WasmBackendContext>(this, irModuleFragment) {
|
||||
@@ -69,6 +113,8 @@ class WasmBackendContext(
|
||||
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
||||
}
|
||||
|
||||
override val inlineClassesUtils = WasmInlineClassesUtils(wasmSymbols)
|
||||
|
||||
override fun log(message: () -> String) {
|
||||
/*TODO*/
|
||||
if (inVerbosePhase) print(message())
|
||||
|
||||
+169
-124
@@ -5,23 +5,16 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.FunctionInlining
|
||||
import org.jetbrains.kotlin.backend.common.phaser.*
|
||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.BuiltInsLowering
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmBlockDecomposerLowering
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.excludeDeclarationsFromCodegen
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineFunctionsWithReifiedTypeParametersLowering
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
|
||||
private fun ClassLoweringPass.runOnFilesPostfix(moduleFragment: IrModuleFragment) = moduleFragment.files.forEach { runOnFilePostfix(it) }
|
||||
|
||||
private fun makeWasmModulePhase(
|
||||
lowering: (WasmBackendContext) -> FileLoweringPass,
|
||||
name: String,
|
||||
@@ -60,6 +53,12 @@ private val expectDeclarationsRemovingPhase = makeWasmModulePhase(
|
||||
description = "Remove expect declaration from module fragment"
|
||||
)
|
||||
|
||||
private val stringConstructorLowering = makeWasmModulePhase(
|
||||
::SimpleStringConcatenationLowering,
|
||||
name = "StringConcatenation",
|
||||
description = "String concatenation lowering"
|
||||
)
|
||||
|
||||
private val lateinitNullableFieldsPhase = makeWasmModulePhase(
|
||||
::NullableFieldsForLateinitCreationLowering,
|
||||
name = "LateinitNullableFields",
|
||||
@@ -86,12 +85,6 @@ private val provisionalFunctionExpressionPhase = makeWasmModulePhase(
|
||||
description = "Transform IrFunctionExpression to a local function reference"
|
||||
)
|
||||
|
||||
private val arrayConstructorPhase = makeWasmModulePhase(
|
||||
::ArrayConstructorLowering,
|
||||
name = "ArrayConstructor",
|
||||
description = "Transform `Array(size) { index -> value }` into a loop"
|
||||
)
|
||||
|
||||
private val functionInliningPhase = makeCustomWasmModulePhase(
|
||||
{ context, module ->
|
||||
FunctionInlining(context).inline(module)
|
||||
@@ -112,7 +105,7 @@ private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeWa
|
||||
private val tailrecLoweringPhase = makeWasmModulePhase(
|
||||
::TailrecLowering,
|
||||
name = "TailrecLowering",
|
||||
description = "Replace `tailrec` callsites with equivalent loop"
|
||||
description = "Replace `tailrec` call sites with equivalent loop"
|
||||
)
|
||||
|
||||
private val enumClassConstructorLoweringPhase = makeWasmModulePhase(
|
||||
@@ -121,6 +114,62 @@ private val enumClassConstructorLoweringPhase = makeWasmModulePhase(
|
||||
description = "Transform Enum Class into regular Class"
|
||||
)
|
||||
|
||||
private val enumClassConstructorBodyLoweringPhase = makeWasmModulePhase(
|
||||
::EnumClassConstructorBodyTransformer,
|
||||
name = "EnumClassConstructorBodyLowering",
|
||||
description = "Transform Enum Class into regular Class"
|
||||
)
|
||||
|
||||
|
||||
private val enumEntryInstancesLoweringPhase = makeWasmModulePhase(
|
||||
::EnumEntryInstancesLowering,
|
||||
name = "EnumEntryInstancesLowering",
|
||||
description = "Create instance variable for each enum entry initialized with `null`",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumEntryInstancesBodyLoweringPhase = makeWasmModulePhase(
|
||||
::EnumEntryInstancesBodyLowering,
|
||||
name = "EnumEntryInstancesBodyLowering",
|
||||
description = "Insert enum entry field initialization into corresponding class constructors",
|
||||
prerequisite = setOf(enumEntryInstancesLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumClassCreateInitializerLoweringPhase = makeWasmModulePhase(
|
||||
::EnumClassCreateInitializerLowering,
|
||||
name = "EnumClassCreateInitializerLowering",
|
||||
description = "Create initializer for enum entries",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumEntryCreateGetInstancesFunsLoweringPhase = makeWasmModulePhase(
|
||||
::EnumEntryCreateGetInstancesFunsLowering,
|
||||
name = "EnumEntryCreateGetInstancesFunsLowering",
|
||||
description = "Create enumEntry_getInstance functions",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumSyntheticFunsLoweringPhase = makeWasmModulePhase(
|
||||
::EnumSyntheticFunctionsLowering,
|
||||
name = "EnumSyntheticFunctionsLowering",
|
||||
description = "Implement `valueOf` and `values`",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumUsageLoweringPhase = makeWasmModulePhase(
|
||||
::EnumUsageLowering,
|
||||
name = "EnumUsageLowering",
|
||||
description = "Replace enum access with invocation of corresponding function",
|
||||
prerequisite = setOf(enumEntryCreateGetInstancesFunsLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumEntryRemovalLoweringPhase = makeWasmModulePhase(
|
||||
::EnumClassRemoveEntriesLowering,
|
||||
name = "EnumEntryRemovalLowering",
|
||||
description = "Replace enum entry with corresponding class",
|
||||
prerequisite = setOf(enumUsageLoweringPhase)
|
||||
)
|
||||
|
||||
|
||||
private val sharedVariablesLoweringPhase = makeWasmModulePhase(
|
||||
::SharedVariablesLowering,
|
||||
@@ -128,6 +177,12 @@ private val sharedVariablesLoweringPhase = makeWasmModulePhase(
|
||||
description = "Box captured mutable variables"
|
||||
)
|
||||
|
||||
private val callableReferencePhase = makeWasmModulePhase(
|
||||
::WasmCallableReferenceLowering,
|
||||
name = "WasmCallableReferenceLowering",
|
||||
description = "Handle callable references"
|
||||
)
|
||||
|
||||
private val localDelegatedPropertiesLoweringPhase = makeWasmModulePhase(
|
||||
{ LocalDelegatedPropertiesLowering() },
|
||||
name = "LocalDelegatedPropertiesLowering",
|
||||
@@ -183,7 +238,7 @@ private val defaultArgumentPatchOverridesPhase = makeWasmModulePhase(
|
||||
private val defaultParameterInjectorPhase = makeWasmModulePhase(
|
||||
{ context -> DefaultParameterInjector(context, skipExternalMethods = true) },
|
||||
name = "DefaultParameterInjector",
|
||||
description = "Replace callsite with default parameters with corresponding stub function",
|
||||
description = "Replace call site with default parameters with corresponding stub function",
|
||||
prerequisite = setOf(innerClassesLoweringPhase)
|
||||
)
|
||||
|
||||
@@ -193,18 +248,6 @@ private val defaultParameterCleanerPhase = makeWasmModulePhase(
|
||||
description = "Clean default parameters up"
|
||||
)
|
||||
|
||||
//private val jsDefaultCallbackGeneratorPhase = makeJsModulePhase(
|
||||
// ::JsDefaultCallbackGenerator,
|
||||
// name = "JsDefaultCallbackGenerator",
|
||||
// description = "Build binding for super calls with default parameters"
|
||||
//)
|
||||
|
||||
//private val varargLoweringPhase = makeJsModulePhase(
|
||||
// ::VarargLowering,
|
||||
// name = "VarargLowering",
|
||||
// description = "Lower vararg arguments"
|
||||
//)
|
||||
|
||||
private val propertiesLoweringPhase = makeWasmModulePhase(
|
||||
{ PropertiesLowering() },
|
||||
name = "PropertiesLowering",
|
||||
@@ -254,7 +297,7 @@ private val returnableBlockLoweringPhase = makeWasmModulePhase(
|
||||
)
|
||||
|
||||
private val bridgesConstructionPhase = makeWasmModulePhase(
|
||||
::BridgesConstruction,
|
||||
::WasmBridgesConstruction,
|
||||
name = "BridgesConstruction",
|
||||
description = "Generate bridges"
|
||||
)
|
||||
@@ -271,65 +314,57 @@ private val inlineClassUsageLoweringPhase = makeWasmModulePhase(
|
||||
description = "Handle inline class usages"
|
||||
)
|
||||
|
||||
//private val autoboxingTransformerPhase = makeJsModulePhase(
|
||||
// ::AutoboxingTransformer,
|
||||
// name = "AutoboxingTransformer",
|
||||
// description = "Insert box/unbox intrinsics"
|
||||
//)
|
||||
|
||||
private val blockDecomposerLoweringPhase = makeCustomWasmModulePhase(
|
||||
{ context, module ->
|
||||
WasmBlockDecomposerLowering(context).lower(module)
|
||||
module.patchDeclarationParents()
|
||||
},
|
||||
name = "BlockDecomposerLowering",
|
||||
description = "Transform statement-like-expression nodes into pure-statement to make it easily transform into JS"
|
||||
private val autoboxingTransformerPhase = makeWasmModulePhase(
|
||||
{ context -> AutoboxingTransformer(context) },
|
||||
name = "AutoboxingTransformer",
|
||||
description = "Insert box/unbox intrinsics"
|
||||
)
|
||||
|
||||
private val wasmNullSpecializationLowering = makeWasmModulePhase(
|
||||
{ context -> WasmNullCoercingLowering(context) },
|
||||
name = "WasmNullCoercingLowering",
|
||||
description = "Specialize assigning Nothing? values to other types."
|
||||
)
|
||||
|
||||
private val staticMembersLoweringPhase = makeWasmModulePhase(
|
||||
::StaticMembersLowering,
|
||||
name = "StaticMembersLowering",
|
||||
description = "Move static member declarations to top-level"
|
||||
)
|
||||
|
||||
private val wasmVarargExpressionLoweringPhase = makeWasmModulePhase(
|
||||
::WasmVarargExpressionLowering,
|
||||
name = "WasmVarargExpressionLowering",
|
||||
description = "Lower varargs"
|
||||
)
|
||||
|
||||
private val wasmThrowDebugLoweringPhase = makeWasmModulePhase(
|
||||
::WasmThrowDebugLowering,
|
||||
name = "WasmThrowDebugLowering",
|
||||
description = "Instrument throws with debug print information"
|
||||
)
|
||||
|
||||
private val fieldInitializersLoweringPhase = makeWasmModulePhase(
|
||||
::FieldInitializersLowering,
|
||||
name = "FieldInitializersLowering",
|
||||
description = "Move field initializers to start function"
|
||||
)
|
||||
|
||||
private val builtInsLoweringPhase0 = makeWasmModulePhase(
|
||||
::BuiltInsLowering,
|
||||
name = "BuiltInsLowering0",
|
||||
description = "Lower IR builtins 0"
|
||||
)
|
||||
|
||||
//private val classReferenceLoweringPhase = makeJsModulePhase(
|
||||
// ::ClassReferenceLowering,
|
||||
// name = "ClassReferenceLowering",
|
||||
// description = "Handle class references"
|
||||
//)
|
||||
//
|
||||
//private val primitiveCompanionLoweringPhase = makeJsModulePhase(
|
||||
// ::PrimitiveCompanionLowering,
|
||||
// name = "PrimitiveCompanionLowering",
|
||||
// description = "Replace common companion object access with platform one"
|
||||
//)
|
||||
//
|
||||
//private val constLoweringPhase = makeJsModulePhase(
|
||||
// ::ConstLowering,
|
||||
// name = "ConstLowering",
|
||||
// description = "Wrap Long and Char constants into constructor invocation"
|
||||
//)
|
||||
//
|
||||
//private val callsLoweringPhase = makeJsModulePhase(
|
||||
// ::CallsLowering,
|
||||
// name = "CallsLowering",
|
||||
// description = "Handle intrinsics"
|
||||
//)
|
||||
//
|
||||
//private val testGenerationPhase = makeJsModulePhase(
|
||||
// ::TestGenerator,
|
||||
// name = "TestGenerationLowering",
|
||||
// description = "Generate invocations to kotlin.test suite and test functions"
|
||||
//)
|
||||
//
|
||||
//private val staticMembersLoweringPhase = makeWasmModulePhase(
|
||||
// ::StaticMembersLowering,
|
||||
// name = "StaticMembersLowering",
|
||||
// description = "Move static member declarations to top-level"
|
||||
//)
|
||||
|
||||
private val builtInsLoweringPhase = makeWasmModulePhase(
|
||||
::BuiltInsLowering,
|
||||
name = "BuiltInsLowering",
|
||||
description = "Lower IR buildins"
|
||||
description = "Lower IR builtins"
|
||||
)
|
||||
|
||||
private val objectDeclarationLoweringPhase = makeWasmModulePhase(
|
||||
::ObjectUsageLowering,
|
||||
::ObjectDeclarationLowering,
|
||||
name = "ObjectDeclarationLowering",
|
||||
description = "Create lazy object instance generator functions"
|
||||
)
|
||||
@@ -340,26 +375,52 @@ private val objectUsageLoweringPhase = makeWasmModulePhase(
|
||||
description = "Transform IrGetObjectValue into instance generator call"
|
||||
)
|
||||
|
||||
private val typeOperatorLoweringPhase = makeWasmModulePhase(
|
||||
::WasmTypeOperatorLowering,
|
||||
name = "TypeOperatorLowering",
|
||||
description = "Lower IrTypeOperator with corresponding logic"
|
||||
)
|
||||
|
||||
private val genericReturnTypeLowering = makeWasmModulePhase(
|
||||
::GenericReturnTypeLowering,
|
||||
name = "GenericReturnTypeLowering",
|
||||
description = "Cast calls to functions with generic return types"
|
||||
)
|
||||
|
||||
private val eraseVirtualDispatchReceiverParametersTypes = makeWasmModulePhase(
|
||||
::EraseVirtualDispatchReceiverParametersTypes,
|
||||
name = "EraseVirtualDispatchReceiverParametersTypes",
|
||||
description = "Erase types of virtual dispatch receivers to Any"
|
||||
)
|
||||
|
||||
private val virtualDispatchReceiverExtractionPhase = makeWasmModulePhase(
|
||||
::VirtualDispatchReceiverExtraction,
|
||||
name = "VirtualDispatchReceiverExtraction",
|
||||
description = "Eliminate side-effects in dispatch receivers of virtual function calls"
|
||||
)
|
||||
|
||||
val wasmPhases = NamedCompilerPhase(
|
||||
name = "IrModuleLowering",
|
||||
description = "IR module lowering",
|
||||
lower = validateIrBeforeLowering then
|
||||
excludeDeclarationsFromCodegenPhase then
|
||||
expectDeclarationsRemovingPhase then
|
||||
provisionalFunctionExpressionPhase then
|
||||
|
||||
// TODO: Need some helpers from stdlib
|
||||
// arrayConstructorPhase then
|
||||
|
||||
functionInliningPhase then
|
||||
provisionalFunctionExpressionPhase then
|
||||
lateinitNullableFieldsPhase then
|
||||
lateinitDeclarationLoweringPhase then
|
||||
lateinitUsageLoweringPhase then
|
||||
tailrecLoweringPhase then
|
||||
|
||||
enumClassConstructorLoweringPhase then
|
||||
enumClassConstructorBodyLoweringPhase then
|
||||
|
||||
sharedVariablesLoweringPhase then
|
||||
callableReferencePhase then
|
||||
localDelegatedPropertiesLoweringPhase then
|
||||
localDeclarationsLoweringPhase then
|
||||
localClassExtractionPhase then
|
||||
@@ -373,68 +434,52 @@ val wasmPhases = NamedCompilerPhase(
|
||||
initializersCleanupLoweringPhase then
|
||||
// Common prefix ends
|
||||
|
||||
builtInsLoweringPhase then
|
||||
|
||||
// TODO: Commonize enumEntryToGetInstanceFunction
|
||||
// Commonize array literal creation
|
||||
// Extract external enum lowering to JS part
|
||||
//
|
||||
// enumClassLoweringPhase then
|
||||
// enumUsageLoweringPhase then
|
||||
|
||||
enumEntryInstancesLoweringPhase then
|
||||
enumEntryInstancesBodyLoweringPhase then
|
||||
enumClassCreateInitializerLoweringPhase then
|
||||
enumEntryCreateGetInstancesFunsLoweringPhase then
|
||||
enumSyntheticFunsLoweringPhase then
|
||||
enumUsageLoweringPhase then
|
||||
enumEntryRemovalLoweringPhase then
|
||||
|
||||
// TODO: Requires stdlib
|
||||
// suspendFunctionsLoweringPhase then
|
||||
|
||||
stringConstructorLowering then
|
||||
returnableBlockLoweringPhase then
|
||||
|
||||
// TODO: Callable reference lowering is too JS specific.
|
||||
// Should we reuse JVM or Native lowering?
|
||||
// callableReferenceLoweringPhase then
|
||||
|
||||
defaultArgumentStubGeneratorPhase then
|
||||
defaultArgumentPatchOverridesPhase then
|
||||
defaultParameterInjectorPhase then
|
||||
defaultParameterCleanerPhase then
|
||||
|
||||
// TODO: Investigate
|
||||
// jsDefaultCallbackGeneratorPhase then
|
||||
|
||||
removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then
|
||||
|
||||
|
||||
// TODO: Varargs are too platform-specific. Reimplement.
|
||||
// varargLoweringPhase then
|
||||
|
||||
// TODO: Investigate exception proposal
|
||||
// TODO:
|
||||
// multipleCatchesLoweringPhase then
|
||||
|
||||
bridgesConstructionPhase then
|
||||
|
||||
// TODO: Reimplement
|
||||
// typeOperatorLoweringPhase then
|
||||
|
||||
// TODO: Reimplement
|
||||
// secondaryConstructorLoweringPhase then
|
||||
// secondaryFactoryInjectorLoweringPhase then
|
||||
|
||||
// TODO: Reimplement
|
||||
// classReferenceLoweringPhase then
|
||||
|
||||
wasmVarargExpressionLoweringPhase then
|
||||
inlineClassDeclarationLoweringPhase then
|
||||
inlineClassUsageLoweringPhase then
|
||||
|
||||
// TODO: Commonize box/unbox intrinsics
|
||||
// autoboxingTransformerPhase then
|
||||
|
||||
blockDecomposerLoweringPhase then
|
||||
|
||||
// TODO: Reimplement
|
||||
// constLoweringPhase then
|
||||
|
||||
eraseVirtualDispatchReceiverParametersTypes then
|
||||
bridgesConstructionPhase then
|
||||
objectDeclarationLoweringPhase then
|
||||
objectUsageLoweringPhase then
|
||||
// staticMembersLoweringPhase then
|
||||
fieldInitializersLoweringPhase then
|
||||
genericReturnTypeLowering then
|
||||
|
||||
// Replace builtins before autoboxing
|
||||
builtInsLoweringPhase0 then
|
||||
|
||||
autoboxingTransformerPhase then
|
||||
objectUsageLoweringPhase then
|
||||
typeOperatorLoweringPhase then
|
||||
|
||||
// Clean up built-ins after type operator lowering
|
||||
builtInsLoweringPhase then
|
||||
|
||||
virtualDispatchReceiverExtractionPhase then
|
||||
wasmThrowDebugLoweringPhase then
|
||||
staticMembersLoweringPhase then
|
||||
wasmNullSpecializationLowering then
|
||||
validateIrAfterLowering
|
||||
)
|
||||
|
||||
@@ -7,10 +7,12 @@ package org.jetbrains.kotlin.backend.wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
@@ -18,24 +20,26 @@ import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class WasmSymbols(
|
||||
context: WasmBackendContext,
|
||||
private val symbolTable: SymbolTable
|
||||
) : Symbols<WasmBackendContext>(context, context.irBuiltIns, symbolTable) {
|
||||
|
||||
override val throwNullPointerException
|
||||
get() = TODO()
|
||||
override val throwNoWhenBranchMatchedException
|
||||
get() = TODO()
|
||||
override val throwTypeCastException
|
||||
get() = TODO()
|
||||
override val throwUninitializedPropertyAccessException
|
||||
get() = TODO()
|
||||
private val wasmInternalPackage: PackageViewDescriptor =
|
||||
context.module.getPackage(FqName("kotlin.wasm.internal"))
|
||||
|
||||
override val throwNullPointerException = getInternalFunction("THROW_NPE")
|
||||
override val throwISE = getInternalFunction("THROW_ISE")
|
||||
override val throwNoWhenBranchMatchedException = throwISE
|
||||
override val throwTypeCastException = getInternalFunction("THROW_CCE")
|
||||
override val throwUninitializedPropertyAccessException =
|
||||
getInternalFunction("throwUninitializedPropertyAccessException")
|
||||
override val defaultConstructorMarker =
|
||||
getIrClass(FqName("kotlin.wasm.internal.DefaultConstructorMarker"))
|
||||
override val throwKotlinNothingValueException: IrSimpleFunctionSymbol
|
||||
get() = TODO()
|
||||
override val defaultConstructorMarker
|
||||
get() = TODO()
|
||||
override val stringBuilder
|
||||
get() = TODO()
|
||||
override val copyRangeTo: Map<ClassDescriptor, IrSimpleFunctionSymbol>
|
||||
@@ -47,7 +51,7 @@ class WasmSymbols(
|
||||
override val getContinuation
|
||||
get() = TODO()
|
||||
override val coroutineContextGetter by lazy {
|
||||
context.irFactory.addFunction(context.excludedDeclarations) {
|
||||
context.irFactory.addFunction(context.getExcludedPackageFragment(FqName("kotlin.excluded"))) {
|
||||
name = Name.identifier("coroutineContextGetter\$Stub")
|
||||
}.symbol
|
||||
}
|
||||
@@ -62,7 +66,9 @@ class WasmSymbols(
|
||||
override val functionAdapter: IrClassSymbol
|
||||
get() = TODO()
|
||||
|
||||
private val wasmInternalPackage = context.module.getPackage(FqName("kotlin.wasm.internal"))
|
||||
val wasmUnreachable = getInternalFunction("wasm_unreachable")
|
||||
val wasmFloatNaN = getInternalFunction("wasm_float_nan")
|
||||
val wasmDoubleNaN = getInternalFunction("wasm_double_nan")
|
||||
|
||||
val equalityFunctions = mapOf(
|
||||
context.irBuiltIns.booleanType to getInternalFunction("wasm_i32_eq"),
|
||||
@@ -71,12 +77,16 @@ class WasmSymbols(
|
||||
context.irBuiltIns.charType to getInternalFunction("wasm_i32_eq"),
|
||||
context.irBuiltIns.intType to getInternalFunction("wasm_i32_eq"),
|
||||
context.irBuiltIns.longType to getInternalFunction("wasm_i64_eq"),
|
||||
context.irBuiltIns.stringType to getInternalFunction("wasm_string_eq")
|
||||
)
|
||||
|
||||
val floatEqualityFunctions = mapOf(
|
||||
context.irBuiltIns.floatType to getInternalFunction("wasm_f32_eq"),
|
||||
context.irBuiltIns.doubleType to getInternalFunction("wasm_f64_eq")
|
||||
)
|
||||
|
||||
private fun wasmString(classfier: IrClassifierSymbol): String = with(context.irBuiltIns) {
|
||||
when (classfier) {
|
||||
private fun wasmPrimitiveTypeName(classifier: IrClassifierSymbol): String = with(context.irBuiltIns) {
|
||||
when (classifier) {
|
||||
booleanClass, byteClass, shortClass, charClass, intClass -> "i32"
|
||||
floatClass -> "f32"
|
||||
doubleClass -> "f64"
|
||||
@@ -85,23 +95,66 @@ class WasmSymbols(
|
||||
}
|
||||
}
|
||||
|
||||
val irBuiltInsToWasmIntrinsics = context.irBuiltIns.run {
|
||||
mapOf(
|
||||
val comparisonBuiltInsToWasmIntrinsics = context.irBuiltIns.run {
|
||||
listOf(
|
||||
lessFunByOperandType to "lt",
|
||||
lessOrEqualFunByOperandType to "le",
|
||||
greaterOrEqualFunByOperandType to "ge",
|
||||
greaterFunByOperandType to "gt"
|
||||
).map { (typeToBuiltIn, wasmOp) ->
|
||||
typeToBuiltIn.map { (type, builtin) ->
|
||||
val wasmType = wasmString(type)
|
||||
val wasmType = wasmPrimitiveTypeName(type)
|
||||
val markSign = if (wasmType == "i32" || wasmType == "i64") "_s" else ""
|
||||
builtin to getInternalFunction("wasm_${wasmType}_$wasmOp$markSign")
|
||||
}
|
||||
}.flatten().toMap()
|
||||
}
|
||||
|
||||
val booleanAnd = getInternalFunction("wasm_i32_and")
|
||||
val refEq = getInternalFunction("wasm_ref_eq")
|
||||
val refIsNull = getInternalFunction("wasm_ref_is_null")
|
||||
val intToLong = getInternalFunction("wasm_i64_extend_i32_s")
|
||||
|
||||
val wasmRefCast = getInternalFunction("wasm_ref_cast")
|
||||
|
||||
val boxIntrinsic: IrSimpleFunctionSymbol = getInternalFunction("boxIntrinsic")
|
||||
val unboxIntrinsic: IrSimpleFunctionSymbol = getInternalFunction("unboxIntrinsic")
|
||||
|
||||
val stringGetLiteral = getInternalFunction("stringLiteral")
|
||||
|
||||
val wasmClassId = getInternalFunction("wasmClassId")
|
||||
val wasmInterfaceId = getInternalFunction("wasmInterfaceId")
|
||||
|
||||
val getVirtualMethodId = getInternalFunction("getVirtualMethodId")
|
||||
val getInterfaceMethodId = getInternalFunction("getInterfaceMethodId")
|
||||
|
||||
val isSubClass = getInternalFunction("isSubClass")
|
||||
val isInterface = getInternalFunction("isInterface")
|
||||
|
||||
val nullableEquals = getInternalFunction("nullableEquals")
|
||||
val ensureNotNull = getInternalFunction("ensureNotNull")
|
||||
val anyNtoString = getInternalFunction("anyNtoString")
|
||||
|
||||
val nullableFloatIeee754Equals = getInternalFunction("nullableFloatIeee754Equals")
|
||||
val nullableDoubleIeee754Equals = getInternalFunction("nullableDoubleIeee754Equals")
|
||||
|
||||
val wasmThrow = getInternalFunction("wasmThrow")
|
||||
|
||||
private val functionNInterfaces = (0..22).map { arity ->
|
||||
getIrClass(FqName("kotlin.wasm.internal.Function$arity"))
|
||||
}
|
||||
|
||||
val functionNInvokeMethods by lazy {
|
||||
functionNInterfaces.map { interfaceSymbol ->
|
||||
interfaceSymbol.owner.declarations.filterIsInstance<IrSimpleFunction>().single { method ->
|
||||
method.name == OperatorNameConventions.INVOKE
|
||||
}.symbol
|
||||
}
|
||||
}
|
||||
|
||||
override fun functionN(n: Int): IrClassSymbol =
|
||||
functionNInterfaces[n]
|
||||
|
||||
private fun findClass(memberScope: MemberScope, name: Name): ClassDescriptor =
|
||||
memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
|
||||
@@ -117,7 +170,7 @@ class WasmSymbols(
|
||||
internal fun getProperty(fqName: FqName): PropertyDescriptor =
|
||||
findProperty(context.module.getPackage(fqName.parent()).memberScope, fqName.shortName()).single()
|
||||
|
||||
internal fun getInternalFunction(name: String): IrSimpleFunctionSymbol {
|
||||
private fun getInternalFunction(name: String): IrSimpleFunctionSymbol {
|
||||
val tmp = findFunctions(wasmInternalPackage.memberScope, Name.identifier(name)).single()
|
||||
return symbolTable.referenceSimpleFunction(tmp)
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.ast
|
||||
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
|
||||
// TODO: Abstract out S-expression part of dumping?
|
||||
|
||||
fun WasmInstruction.toWat(ident: String = ""): String =
|
||||
"$ident($mnemonic${immediate.toWat()}${operands.joinToString("") { " " + it.toWat("") }})"
|
||||
|
||||
fun WasmImmediate.toWat(): String = when (this) {
|
||||
WasmImmediate.None -> ""
|
||||
is WasmImmediate.DeclarationReference -> " $$name"
|
||||
// SpiderMonkey jsshell won't parse Uppercase letters in literals
|
||||
is WasmImmediate.LiteralValue<*> -> " $value".toLowerCaseAsciiOnly()
|
||||
}
|
||||
|
||||
fun wasmModuleToWat(module: WasmModule): String =
|
||||
"(module\n${module.fields.joinToString("") { wasmModuleFieldToWat(it) + "\n" }})"
|
||||
|
||||
fun wasmFunctionToWat(function: WasmFunction): String {
|
||||
val watId = "$${function.name}"
|
||||
val watImport = function.importPair?.let { importPair ->
|
||||
" (import ${toWasString(importPair.module)} ${toWasString(importPair.name)})"
|
||||
} ?: ""
|
||||
val watLocals = function.locals.joinToString("") { " " + wasmLocalToWat(it) + "\n" }
|
||||
val watParameters = function.parameters.joinToString("") { " " + wasmParameterToWat(it, function.importPair == null) }
|
||||
val watResult = function.returnType?.let { type -> " (result ${type.mnemonic})" } ?: ""
|
||||
val watBody = function.instructions.joinToString("") { it.toWat(" ") + "\n" }
|
||||
return " (func $watId$watImport$watParameters$watResult\n$watLocals$watBody )"
|
||||
}
|
||||
|
||||
fun wasmParameterToWat(parameter: WasmParameter, includeName: Boolean): String {
|
||||
val name = if (includeName) " $${parameter.name}" else ""
|
||||
return "(param$name ${parameter.type.mnemonic})"
|
||||
}
|
||||
|
||||
fun wasmLocalToWat(local: WasmLocal): String =
|
||||
local.run { "(local $$name ${type.mnemonic})" }
|
||||
|
||||
fun wasmGlobalToWat(global: WasmGlobal): String {
|
||||
val watMut = if (global.isMutable) "mut " else ""
|
||||
val watInit = global.init?.toWat("") ?: ""
|
||||
return global.run { " (global $$name ($watMut${type.mnemonic}) $watInit)" }
|
||||
}
|
||||
|
||||
fun wasmExportToWat(export: WasmExport): String =
|
||||
export.run { " (export \"$exportedName\" (${kind.keyword} $$wasmName))" }
|
||||
|
||||
fun wasmModuleFieldToWat(moduleField: WasmModuleField): String =
|
||||
when (moduleField) {
|
||||
is WasmFunction -> wasmFunctionToWat(moduleField)
|
||||
is WasmGlobal -> wasmGlobalToWat(moduleField)
|
||||
is WasmExport -> wasmExportToWat(moduleField)
|
||||
is WasmModuleFieldList -> moduleField.fields.joinToString("") { wasmModuleFieldToWat(it) + "\n" }
|
||||
}
|
||||
|
||||
fun toWasString(s: String): String {
|
||||
// TODO: escape characters according to
|
||||
// https://webassembly.github.io/spec/core/text/values.html#strings
|
||||
return "\"" + s + "\""
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.ast
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.WasmImportPair
|
||||
|
||||
class WasmModule(
|
||||
val fields: List<WasmModuleField>
|
||||
)
|
||||
|
||||
sealed class WasmModuleField
|
||||
|
||||
class WasmModuleFieldList(
|
||||
val fields: List<WasmModuleField>
|
||||
) : WasmModuleField()
|
||||
|
||||
class WasmFunction(
|
||||
val name: String,
|
||||
val parameters: List<WasmParameter>,
|
||||
val returnType: WasmValueType?,
|
||||
val locals: List<WasmLocal>,
|
||||
val instructions: List<WasmInstruction>,
|
||||
val importPair: WasmImportPair?
|
||||
) : WasmModuleField()
|
||||
|
||||
class WasmParameter(
|
||||
val name: String,
|
||||
val type: WasmValueType
|
||||
)
|
||||
|
||||
class WasmLocal(
|
||||
val name: String,
|
||||
val type: WasmValueType
|
||||
)
|
||||
|
||||
class WasmGlobal(
|
||||
val name: String,
|
||||
val type: WasmValueType,
|
||||
val isMutable: Boolean,
|
||||
val init: WasmInstruction?
|
||||
) : WasmModuleField()
|
||||
|
||||
class WasmExport(
|
||||
val wasmName: String,
|
||||
val exportedName: String,
|
||||
val kind: Kind
|
||||
) : WasmModuleField() {
|
||||
enum class Kind(val keyword: String) {
|
||||
FUNCTION("func"),
|
||||
GLOBAL("global")
|
||||
}
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.ast
|
||||
|
||||
|
||||
sealed class WasmImmediate {
|
||||
object None : WasmImmediate()
|
||||
class DeclarationReference(val name: String) : WasmImmediate()
|
||||
class LiteralValue<T : Number>(val value: T) : WasmImmediate()
|
||||
}
|
||||
|
||||
sealed class WasmInstruction(
|
||||
val mnemonic: String,
|
||||
val immediate: WasmImmediate = WasmImmediate.None,
|
||||
val operands: List<WasmInstruction> = emptyList()
|
||||
)
|
||||
|
||||
class WasmSimpleInstruction(mnemonic: String, operands: List<WasmInstruction>) :
|
||||
WasmInstruction(mnemonic, operands = operands)
|
||||
|
||||
class WasmNop : WasmInstruction("nop")
|
||||
|
||||
class WasmReturn(values: List<WasmInstruction>) :
|
||||
WasmInstruction("return", operands = values)
|
||||
|
||||
class WasmDrop(instructions: List<WasmInstruction>) :
|
||||
WasmInstruction("drop", operands = instructions)
|
||||
|
||||
class WasmCall(name: String, operands: List<WasmInstruction>) :
|
||||
WasmInstruction("call", WasmImmediate.DeclarationReference(name), operands)
|
||||
|
||||
class WasmGetLocal(name: String) :
|
||||
WasmInstruction("get_local", WasmImmediate.DeclarationReference(name))
|
||||
|
||||
class WasmGetGlobal(name: String) :
|
||||
WasmInstruction("get_global", WasmImmediate.DeclarationReference(name))
|
||||
|
||||
class WasmSetGlobal(name: String, value: WasmInstruction) :
|
||||
WasmInstruction("set_global", WasmImmediate.DeclarationReference(name), listOf(value))
|
||||
|
||||
class WasmSetLocal(name: String, value: WasmInstruction) :
|
||||
WasmInstruction("set_local", WasmImmediate.DeclarationReference(name), listOf(value))
|
||||
|
||||
class WasmIf(condition: WasmInstruction, thenInstructions: WasmThen?, elseInstruction: WasmElse?) :
|
||||
WasmInstruction("if", operands = listOfNotNull(condition, thenInstructions, elseInstruction))
|
||||
|
||||
class WasmThen(inst: WasmInstruction) :
|
||||
WasmInstruction("then", operands = listOf(inst))
|
||||
|
||||
class WasmElse(inst: WasmInstruction) :
|
||||
WasmInstruction("else", operands = listOf(inst))
|
||||
|
||||
class WasmBlock(instructions: List<WasmInstruction>) :
|
||||
WasmInstruction("block", operands = instructions)
|
||||
|
||||
sealed class WasmConst<KotlinType : Number, WasmType : WasmValueType>(value: KotlinType, type: WasmType) :
|
||||
WasmInstruction(type.mnemonic + ".const", WasmImmediate.LiteralValue<KotlinType>(value))
|
||||
|
||||
class WasmI32Const(value: Int) : WasmConst<Int, WasmI32>(value, WasmI32)
|
||||
class WasmI64Const(value: Long) : WasmConst<Long, WasmI64>(value, WasmI64)
|
||||
class WasmF32Const(value: Float) : WasmConst<Float, WasmF32>(value, WasmF32)
|
||||
class WasmF64Const(value: Double) : WasmConst<Double, WasmF64>(value, WasmF64)
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.ast
|
||||
|
||||
sealed class WasmValueType(val mnemonic: String)
|
||||
|
||||
object WasmI32 : WasmValueType("i32")
|
||||
object WasmI64 : WasmValueType("i64")
|
||||
object WasmF32 : WasmValueType("f32")
|
||||
object WasmF64 : WasmValueType("f64")
|
||||
|
||||
object WasmAnyRef : WasmValueType("anyref")
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.TODO
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
interface BaseTransformer<out R, in D> : IrElementVisitor<R, D> {
|
||||
override fun visitElement(element: IrElement, data: D): R {
|
||||
TODO(element)
|
||||
}
|
||||
}
|
||||
-123
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.*
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.getWasmImportAnnotation
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.getWasmInstructionAnnotation
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.hasExcludedFromCodegenAnnotation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||
import org.jetbrains.kotlin.ir.util.isFakeOverride
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
class DeclarationTransformer : BaseTransformer<WasmModuleField?, WasmCodegenContext> {
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: WasmCodegenContext): WasmModuleField? {
|
||||
if (declaration.hasExcludedFromCodegenAnnotation())
|
||||
return null
|
||||
if (declaration.getWasmInstructionAnnotation() != null)
|
||||
return null
|
||||
if (declaration.isFakeOverride)
|
||||
return null
|
||||
// Virtual functions are not supported yet
|
||||
if (declaration.origin == IrDeclarationOrigin.BRIDGE)
|
||||
return null
|
||||
|
||||
// Collect local variables
|
||||
val localNames = wasmNameTable<IrValueDeclaration>()
|
||||
|
||||
val wasmName = data.getGlobalName(declaration)
|
||||
|
||||
val irParameters = declaration.run {
|
||||
listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters
|
||||
}
|
||||
|
||||
val wasmParameters = irParameters.map { parameter ->
|
||||
val name = localNames.declareFreshName(parameter, parameter.name.asString())
|
||||
WasmParameter(name, data.transformType(parameter.type))
|
||||
}
|
||||
|
||||
val wasmReturnType = when {
|
||||
declaration.returnType.isUnit() -> null
|
||||
else -> data.transformType(declaration.returnType)
|
||||
}
|
||||
|
||||
val importedName = declaration.getWasmImportAnnotation()
|
||||
if (importedName != null) {
|
||||
data.imports.add(
|
||||
WasmFunction(
|
||||
name = wasmName,
|
||||
parameters = wasmParameters,
|
||||
returnType = wasmReturnType,
|
||||
locals = emptyList(),
|
||||
instructions = emptyList(),
|
||||
importPair = importedName
|
||||
)
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
val body = declaration.body
|
||||
?: error("Function ${declaration.fqNameWhenAvailable} without a body")
|
||||
|
||||
data.localNames = localNames.names
|
||||
val locals = mutableListOf<WasmLocal>()
|
||||
body.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
val name = localNames.declareFreshName(declaration, declaration.name.asString())
|
||||
locals += WasmLocal(name, data.transformType(declaration.type))
|
||||
super.visitVariable(declaration)
|
||||
}
|
||||
})
|
||||
|
||||
return WasmFunction(
|
||||
name = wasmName,
|
||||
parameters = wasmParameters,
|
||||
returnType = wasmReturnType,
|
||||
locals = locals,
|
||||
instructions = bodyToWasmInstructionList(body, data),
|
||||
importPair = null
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor, data: WasmCodegenContext): WasmModuleField? {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass, data: WasmCodegenContext): WasmModuleField? {
|
||||
if (declaration.isAnnotationClass) return null
|
||||
if (declaration.hasExcludedFromCodegenAnnotation()) return null
|
||||
|
||||
val wasmMembers = declaration.declarations.mapNotNull { member ->
|
||||
when (member) {
|
||||
is IrSimpleFunction -> this.visitSimpleFunction(member, data)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
return WasmModuleFieldList(wasmMembers)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField, data: WasmCodegenContext): WasmModuleField {
|
||||
return WasmGlobal(
|
||||
name = data.getGlobalName(declaration),
|
||||
type = data.transformType(declaration.type),
|
||||
isMutable = true,
|
||||
// TODO: move non-constexpr initializers out
|
||||
init = declaration.initializer?.let {
|
||||
expressionToWasmInstruction(it.expression, data)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
-204
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.*
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.getWasmInstructionAnnotation
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
|
||||
class ExpressionTransformer : BaseTransformer<WasmInstruction, WasmCodegenContext> {
|
||||
override fun visitVararg(expression: IrVararg, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("Support arrays")
|
||||
}
|
||||
|
||||
override fun visitExpressionBody(body: IrExpressionBody, data: WasmCodegenContext): WasmInstruction =
|
||||
body.expression.accept(this, data)
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("?")
|
||||
}
|
||||
|
||||
override fun <T> visitConst(expression: IrConst<T>, data: WasmCodegenContext): WasmInstruction {
|
||||
return when (val kind = expression.kind) {
|
||||
is IrConstKind.Null -> TODO()
|
||||
is IrConstKind.String -> {
|
||||
val value = kind.valueOf(expression)
|
||||
val index = data.stringLiterals.size
|
||||
data.stringLiterals.add(value)
|
||||
val funName = data.getGlobalName(data.backendContext.wasmSymbols.stringGetLiteral.owner)
|
||||
val operand = WasmI32Const(index)
|
||||
WasmCall(funName, listOf(operand))
|
||||
}
|
||||
is IrConstKind.Boolean -> WasmI32Const(if (kind.valueOf(expression)) 1 else 0)
|
||||
is IrConstKind.Byte -> WasmI32Const(kind.valueOf(expression).toInt())
|
||||
is IrConstKind.Short -> WasmI32Const(kind.valueOf(expression).toInt())
|
||||
is IrConstKind.Int -> WasmI32Const(kind.valueOf(expression))
|
||||
is IrConstKind.Long -> WasmI64Const(kind.valueOf(expression))
|
||||
is IrConstKind.Char -> WasmI32Const(kind.valueOf(expression).toInt())
|
||||
is IrConstKind.Float -> WasmF32Const(kind.valueOf(expression))
|
||||
is IrConstKind.Double -> WasmF64Const(kind.valueOf(expression))
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("Implement kotlin.String")
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField, data: WasmCodegenContext): WasmInstruction {
|
||||
val fieldName = data.getGlobalName(expression.symbol.owner)
|
||||
if (expression.receiver != null)
|
||||
TODO("Support member fields")
|
||||
|
||||
return WasmGetGlobal(fieldName)
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue, data: WasmCodegenContext): WasmInstruction =
|
||||
WasmGetLocal(data.getLocalName(expression.symbol.owner))
|
||||
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrGetObjectValue")
|
||||
}
|
||||
|
||||
override fun visitSetField(expression: IrSetField, data: WasmCodegenContext): WasmInstruction {
|
||||
val fieldName = data.getGlobalName(expression.symbol.owner)
|
||||
if (expression.receiver != null)
|
||||
TODO("Support member fields")
|
||||
|
||||
val value = expression.value.accept(this, data)
|
||||
return WasmSetGlobal(fieldName, value)
|
||||
}
|
||||
|
||||
override fun visitSetValue(expression: IrSetValue, data: WasmCodegenContext): WasmInstruction {
|
||||
val fieldName = data.getLocalName(expression.symbol.owner)
|
||||
val value = expression.value.accept(this, data)
|
||||
return WasmSetLocal(fieldName, value)
|
||||
}
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrConstructorCall")
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: WasmCodegenContext): WasmInstruction {
|
||||
val function = expression.symbol.owner.realOverrideTarget
|
||||
val valueArgs = (0 until expression.valueArgumentsCount).mapNotNull { expression.getValueArgument(it) }
|
||||
val irArguments = listOfNotNull(expression.dispatchReceiver, expression.extensionReceiver) + valueArgs
|
||||
val wasmArguments = irArguments.map { expressionToWasmInstruction(it, data) }
|
||||
|
||||
val wasmInstruction = function.getWasmInstructionAnnotation()
|
||||
if (wasmInstruction != null) {
|
||||
if (wasmInstruction == "nop") {
|
||||
return wasmArguments.single()
|
||||
}
|
||||
return WasmSimpleInstruction(wasmInstruction, wasmArguments)
|
||||
}
|
||||
|
||||
val name = data.getGlobalName(function)
|
||||
return WasmCall(name, wasmArguments)
|
||||
}
|
||||
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: WasmCodegenContext): WasmInstruction {
|
||||
val wasmArgument = expressionToWasmInstruction(expression.argument, data)
|
||||
if (expression.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) {
|
||||
return wasmArgument
|
||||
}
|
||||
TODO("IrTypeOperatorCall:\n ${expression.dump()}")
|
||||
}
|
||||
|
||||
override fun visitGetEnumValue(expression: IrGetEnumValue, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrGetEnumValue")
|
||||
}
|
||||
|
||||
override fun visitBlockBody(body: IrBlockBody, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression, data: WasmCodegenContext): WasmInstruction {
|
||||
val expressions = expression.statements.map { it.accept(this, data) }
|
||||
|
||||
if (!expression.type.isUnit())
|
||||
return WasmBlock(expressions + listOf(WasmDrop(emptyList())))
|
||||
|
||||
return WasmBlock(expressions)
|
||||
}
|
||||
|
||||
override fun visitExpression(expression: IrExpression, data: WasmCodegenContext): WasmInstruction {
|
||||
return expressionToWasmInstruction(expression, data)
|
||||
}
|
||||
|
||||
override fun visitBreak(jump: IrBreak, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun visitContinue(jump: IrContinue, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO()
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn, data: WasmCodegenContext): WasmInstruction {
|
||||
if (expression.value.type.isUnit()) return WasmReturn(emptyList())
|
||||
|
||||
return WasmReturn(listOf(expressionToWasmInstruction(expression.value, data)))
|
||||
}
|
||||
|
||||
override fun visitThrow(expression: IrThrow, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrThrow")
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, data: WasmCodegenContext): WasmInstruction {
|
||||
val init = declaration.initializer ?: return WasmNop()
|
||||
val varName = data.getLocalName(declaration)
|
||||
return WasmSetLocal(varName, expressionToWasmInstruction(init, data))
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrDelegatingConstructorCall")
|
||||
}
|
||||
|
||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrInstanceInitializerCall")
|
||||
}
|
||||
|
||||
override fun visitTry(aTry: IrTry, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrTry")
|
||||
}
|
||||
|
||||
override fun visitWhen(expression: IrWhen, data: WasmCodegenContext): WasmInstruction {
|
||||
return expression.branches.foldRight(null) { br: IrBranch, inst: WasmInstruction? ->
|
||||
val body = expressionToWasmInstruction(br.result, data)
|
||||
if (isElseBranch(br)) body
|
||||
else {
|
||||
val condition = expressionToWasmInstruction(br.condition, data)
|
||||
WasmIf(condition, WasmThen(body), inst?.let { WasmElse(inst) })
|
||||
}
|
||||
}!!
|
||||
}
|
||||
|
||||
override fun visitWhileLoop(loop: IrWhileLoop, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrWhileLoop")
|
||||
}
|
||||
|
||||
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrDoWhileLoop")
|
||||
}
|
||||
|
||||
override fun visitSyntheticBody(body: IrSyntheticBody, data: WasmCodegenContext): WasmInstruction {
|
||||
TODO("IrSyntheticBody")
|
||||
}
|
||||
|
||||
override fun visitDynamicMemberExpression(expression: IrDynamicMemberExpression, data: WasmCodegenContext): WasmInstruction =
|
||||
error("Dynamic operators are not supported for WASM target")
|
||||
|
||||
override fun visitDynamicOperatorExpression(expression: IrDynamicOperatorExpression, data: WasmCodegenContext): WasmInstruction =
|
||||
error("Dynamic operators are not supported for WASM target")
|
||||
}
|
||||
|
||||
fun expressionToWasmInstruction(expression: IrExpression, context: WasmCodegenContext): WasmInstruction {
|
||||
return expression.accept(ExpressionTransformer(), context)
|
||||
}
|
||||
-82
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmCompilerResult
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.WasmExport
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.WasmModule
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.wasmModuleToWat
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsAssignment
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsArrayLiteral
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsBlock
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsStringLiteral
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class IrModuleToWasm(private val backendContext: WasmBackendContext) {
|
||||
fun generateModule(module: IrModuleFragment): WasmCompilerResult {
|
||||
val nameTable = generateWatTopLevelNames(module.files)
|
||||
val context = WasmCodegenContext(nameTable, backendContext)
|
||||
val irDeclarations = module.files.flatMap { it.declarations }
|
||||
val wasmDeclarations = irDeclarations.mapNotNull { it.accept(DeclarationTransformer(), context) }
|
||||
val exports = generateExports(module, context)
|
||||
|
||||
|
||||
val wasmModule = WasmModule(context.imports + wasmDeclarations + exports)
|
||||
val wat = wasmModuleToWat(wasmModule)
|
||||
return WasmCompilerResult(wat, generateStringLiteralsSupport(context.stringLiterals))
|
||||
}
|
||||
|
||||
private fun generateStringLiteralsSupport(literals: List<String>): String {
|
||||
return JsBlock(
|
||||
jsAssignment(
|
||||
JsNameRef("stringLiterals", "runtime"),
|
||||
JsArrayLiteral(literals.map { JsStringLiteral(it) })
|
||||
).makeStmt()
|
||||
).toString()
|
||||
}
|
||||
|
||||
private fun generateExports(module: IrModuleFragment, context: WasmCodegenContext): List<WasmExport> {
|
||||
val exports = mutableListOf<WasmExport>()
|
||||
for (file in module.files) {
|
||||
for (declaration in file.declarations) {
|
||||
exports.addIfNotNull(generateExport(declaration, context))
|
||||
}
|
||||
}
|
||||
return exports
|
||||
}
|
||||
|
||||
private fun generateExport(declaration: IrDeclaration, context: WasmCodegenContext): WasmExport? {
|
||||
if (declaration !is IrDeclarationWithVisibility ||
|
||||
declaration !is IrDeclarationWithName ||
|
||||
declaration !is IrSimpleFunction ||
|
||||
declaration.visibility != DescriptorVisibilities.PUBLIC
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!declaration.isExported(context))
|
||||
return null
|
||||
|
||||
val internalName = context.getGlobalName(declaration)
|
||||
val exportedName = sanitizeName(declaration.name.identifier)
|
||||
|
||||
return WasmExport(
|
||||
wasmName = internalName,
|
||||
exportedName = exportedName,
|
||||
kind = WasmExport.Kind.FUNCTION
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun IrFunction.isExported(context: WasmCodegenContext): Boolean =
|
||||
fqNameWhenAvailable in context.backendContext.additionalExportedDeclarations
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
fun <T> wasmNameTable() = NameTable<T>(sanitizer = ::sanitizeWatIdentifier)
|
||||
|
||||
fun generateWatTopLevelNames(packages: List<IrPackageFragment>): Map<IrDeclarationWithName, String> {
|
||||
val names = wasmNameTable<IrDeclarationWithName>()
|
||||
|
||||
fun nameTopLevelDecl(declaration: IrDeclarationWithName) {
|
||||
val suggestedName = declaration.fqNameWhenAvailable?.toString()
|
||||
?: "fqname???" + declaration.name.asString()
|
||||
names.declareFreshName(declaration, suggestedName)
|
||||
}
|
||||
|
||||
for (p in packages) {
|
||||
p.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||
nameTopLevelDecl(declaration)
|
||||
super.visitSimpleFunction(declaration)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) {
|
||||
if (declaration.isTopLevel)
|
||||
nameTopLevelDecl(declaration)
|
||||
super.visitField(declaration)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return names.names
|
||||
}
|
||||
|
||||
fun sanitizeWatIdentifier(ident: String): String {
|
||||
if (ident.isEmpty())
|
||||
return "_"
|
||||
if (ident.all(::isValidWatIdentifier))
|
||||
return ident
|
||||
return ident.map { if (isValidWatIdentifier(it)) it else "_" }.joinToString("")
|
||||
}
|
||||
|
||||
// https://webassembly.github.io/spec/core/text/values.html#text-id
|
||||
fun isValidWatIdentifier(c: Char): Boolean =
|
||||
c in '0'..'9' || c in 'A'..'Z' || c in 'a'..'z'
|
||||
// TODO: SpiderMonkey js shell can't parse some of the
|
||||
// permitted identifiers: '?', '<'
|
||||
// || c in "!#$%&′*+-./:<=>?@\\^_`|~"
|
||||
|| c in "$.@_"
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.WasmInstruction
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.WasmNop
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.WasmSetLocal
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
|
||||
class StatementTransformer : BaseTransformer<WasmInstruction, WasmCodegenContext> {
|
||||
override fun visitVariable(declaration: IrVariable, data: WasmCodegenContext): WasmInstruction {
|
||||
val init = declaration.initializer ?: return WasmNop()
|
||||
val varName = data.getLocalName(declaration)
|
||||
return WasmSetLocal(varName, expressionToWasmInstruction(init, data))
|
||||
}
|
||||
|
||||
override fun visitExpression(expression: IrExpression, data: WasmCodegenContext): WasmInstruction {
|
||||
return expressionToWasmInstruction(expression, data)
|
||||
}
|
||||
}
|
||||
|
||||
fun statementToWasmInstruction(statement: IrStatement, context: WasmCodegenContext): WasmInstruction {
|
||||
return statement.accept(StatementTransformer(), context)
|
||||
}
|
||||
|
||||
fun bodyToWasmInstructionList(body: IrBody, context: WasmCodegenContext): List<WasmInstruction> {
|
||||
if (body is IrBlockBody) {
|
||||
return body.statements.map { statementToWasmInstruction(it, context) }
|
||||
} else TODO()
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
|
||||
|
||||
fun WasmCodegenContext.transformType(irType: IrType): WasmValueType =
|
||||
when {
|
||||
irType.isBoolean() -> WasmI32
|
||||
irType.isByte() -> WasmI32
|
||||
irType.isShort() -> WasmI32
|
||||
irType.isInt() -> WasmI32
|
||||
irType.isLong() -> WasmI64
|
||||
irType.isChar() -> WasmI32
|
||||
irType.isFloat() -> WasmF32
|
||||
irType.isDouble() -> WasmF64
|
||||
irType.isString() -> WasmAnyRef
|
||||
irType.isAny() || irType.isNullableAny() -> WasmAnyRef
|
||||
else ->
|
||||
TODO("Unsupported type: ${irType.render()}")
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.ast.WasmModuleField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
|
||||
class WasmCodegenContext(
|
||||
private val topLevelNames: Map<IrDeclarationWithName, String>,
|
||||
val backendContext: WasmBackendContext
|
||||
) {
|
||||
val imports = mutableListOf<WasmModuleField>()
|
||||
var localNames: Map<IrValueDeclaration, String> = emptyMap()
|
||||
val stringLiterals = mutableListOf<String>()
|
||||
|
||||
fun getGlobalName(declaration: IrDeclarationWithName): String =
|
||||
topLevelNames[declaration]
|
||||
?: error("Can't find name for ${declaration.fqNameWhenAvailable}")
|
||||
|
||||
fun getLocalName(declaration: IrValueDeclaration): String =
|
||||
localNames[declaration]
|
||||
?: error("Can't find local name for ${declaration.fqNameWhenAvailable}")
|
||||
}
|
||||
@@ -9,7 +9,9 @@ import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.backend.wasm.codegen.IrModuleToWasm
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmModuleFragmentGenerator
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmCompiledModuleFragment
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.generateStringLiteralsSupport
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.ir.backend.js.MainModule
|
||||
@@ -22,8 +24,11 @@ import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToBinary
|
||||
import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToText
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
data class WasmCompilerResult(val wat: String, val js: String)
|
||||
class WasmCompilerResult(val wat: String, val js: String, val wasm: ByteArray)
|
||||
|
||||
fun compileWasm(
|
||||
project: Project,
|
||||
@@ -60,9 +65,25 @@ fun compileWasm(
|
||||
val irProviders = generateTypicalIrProviderList(moduleDescriptor, irBuiltIns, symbolTable, deserializer)
|
||||
ExternalDependenciesGenerator(symbolTable, irProviders, configuration.languageVersionSettings).generateUnboundSymbolsAsDependencies()
|
||||
moduleFragment.patchDeclarationParents()
|
||||
deserializer.postProcess()
|
||||
|
||||
wasmPhases.invokeToplevel(phaseConfig, context, moduleFragment)
|
||||
|
||||
return IrModuleToWasm(context).generateModule(moduleFragment)
|
||||
val compiledWasmModule = WasmCompiledModuleFragment()
|
||||
val codeGenerator = WasmModuleFragmentGenerator(context, compiledWasmModule)
|
||||
codeGenerator.generateModule(moduleFragment)
|
||||
|
||||
val linkedModule = compiledWasmModule.linkWasmCompiledFragments()
|
||||
val watGenerator = WasmIrToText()
|
||||
watGenerator.appendWasmModule(linkedModule)
|
||||
val wat = watGenerator.toString()
|
||||
|
||||
val os = ByteArrayOutputStream()
|
||||
WasmIrToBinary(os, linkedModule).appendWasmModule()
|
||||
val byteArray = os.toByteArray()
|
||||
|
||||
return WasmCompilerResult(
|
||||
wat,
|
||||
generateStringLiteralsSupport(compiledWasmModule.stringLiterals),
|
||||
wasm = byteArray
|
||||
)
|
||||
}
|
||||
|
||||
+492
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalUnsignedTypes::class)
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
|
||||
import org.jetbrains.kotlin.backend.common.ir.isOverridable
|
||||
import org.jetbrains.kotlin.backend.common.ir.returnType
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmSymbols
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.wasmSignature
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.getInlineClassBackingField
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
|
||||
class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorVoid {
|
||||
val body: WasmExpressionBuilder = context.bodyGen
|
||||
|
||||
// Shortcuts
|
||||
private val backendContext: WasmBackendContext = context.backendContext
|
||||
private val wasmSymbols: WasmSymbols = backendContext.wasmSymbols
|
||||
private val irBuiltIns: IrBuiltIns = backendContext.irBuiltIns
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
error("Unexpected element of type ${element::class}")
|
||||
}
|
||||
|
||||
override fun <T> visitConst(expression: IrConst<T>) {
|
||||
when (val kind = expression.kind) {
|
||||
is IrConstKind.Null -> generateDefaultInitializerForType(context.transformType(expression.type), body)
|
||||
is IrConstKind.Boolean -> body.buildConstI32(if (kind.valueOf(expression)) 1 else 0)
|
||||
is IrConstKind.Byte -> body.buildConstI32(kind.valueOf(expression).toInt())
|
||||
is IrConstKind.Short -> body.buildConstI32(kind.valueOf(expression).toInt())
|
||||
is IrConstKind.Int -> body.buildConstI32(kind.valueOf(expression))
|
||||
is IrConstKind.Long -> body.buildConstI64(kind.valueOf(expression))
|
||||
is IrConstKind.Char -> body.buildConstI32(kind.valueOf(expression).toInt())
|
||||
is IrConstKind.Float -> body.buildConstF32(kind.valueOf(expression))
|
||||
is IrConstKind.Double -> body.buildConstF64(kind.valueOf(expression))
|
||||
is IrConstKind.String -> {
|
||||
body.buildConstI32Symbol(context.referenceStringLiteral(kind.valueOf(expression)))
|
||||
body.buildCall(context.referenceFunction(wasmSymbols.stringGetLiteral))
|
||||
}
|
||||
else -> error("Unknown constant kind")
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField) {
|
||||
val field: IrField = expression.symbol.owner
|
||||
val receiver: IrExpression? = expression.receiver
|
||||
if (receiver != null) {
|
||||
generateExpression(receiver)
|
||||
if (backendContext.inlineClassesUtils.isClassInlineLike(field.parentAsClass)) {
|
||||
// Unboxed inline class instance is already represented as backing field.
|
||||
// Doing nothing.
|
||||
} else {
|
||||
generateInstanceFieldAccess(field)
|
||||
}
|
||||
} else {
|
||||
body.buildGetGlobal(context.referenceGlobal(field.symbol))
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateInstanceFieldAccess(field: IrField) {
|
||||
body.buildStructGet(
|
||||
context.referenceStructType(field.parentAsClass.symbol),
|
||||
context.getStructFieldRef(field)
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitSetField(expression: IrSetField) {
|
||||
val field = expression.symbol.owner
|
||||
val receiver = expression.receiver
|
||||
|
||||
if (receiver != null) {
|
||||
generateExpression(receiver)
|
||||
generateExpression(expression.value)
|
||||
body.buildStructSet(
|
||||
struct = context.referenceStructType(field.parentAsClass.symbol),
|
||||
fieldId = context.getStructFieldRef(field),
|
||||
)
|
||||
} else {
|
||||
generateExpression(expression.value)
|
||||
body.buildSetGlobal(context.referenceGlobal(expression.symbol))
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue) {
|
||||
body.buildGetLocal(context.referenceLocal(expression.symbol))
|
||||
}
|
||||
|
||||
override fun visitSetValue(expression: IrSetValue) {
|
||||
generateExpression(expression.value)
|
||||
body.buildSetLocal(context.referenceLocal(expression.symbol))
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall) {
|
||||
generateCall(expression)
|
||||
}
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall) {
|
||||
val klass: IrClass = expression.symbol.owner.parentAsClass
|
||||
|
||||
if (backendContext.inlineClassesUtils.isClassInlineLike(klass)) {
|
||||
// Unboxed instance is just a constructor argument.
|
||||
generateExpression(expression.getValueArgument(0)!!)
|
||||
return
|
||||
}
|
||||
|
||||
val wasmStruct: WasmSymbol<WasmStructDeclaration> = context.referenceStructType(klass.symbol)
|
||||
val wasmClassId = context.referenceClassId(klass.symbol)
|
||||
|
||||
val irFields: List<IrField> = klass.allFields(backendContext.irBuiltIns)
|
||||
|
||||
irFields.forEachIndexed { index, field ->
|
||||
if (index == 0)
|
||||
body.buildConstI32Symbol(wasmClassId)
|
||||
else
|
||||
generateDefaultInitializerForType(context.transformType(field.type), body)
|
||||
}
|
||||
|
||||
body.buildGetGlobal(context.referenceClassRTT(klass.symbol))
|
||||
body.buildStructNew(wasmStruct)
|
||||
generateCall(expression)
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
||||
val klass = context.irFunction.parentAsClass
|
||||
|
||||
// Don't delegate constructors of Any to Any.
|
||||
if (klass.defaultType.isAny()) {
|
||||
return
|
||||
}
|
||||
|
||||
body.buildGetLocal(context.referenceLocal(0)) // this parameter
|
||||
generateCall(expression)
|
||||
}
|
||||
|
||||
private fun generateCall(call: IrFunctionAccessExpression) {
|
||||
// Box intrinsic has an additional klass ID argument.
|
||||
// Processing it separately
|
||||
if (call.symbol == wasmSymbols.boxIntrinsic) {
|
||||
val toType = call.getTypeArgument(0)!!
|
||||
val klass = toType.erasedUpperBound!!
|
||||
val structTypeName = context.referenceStructType(klass.symbol)
|
||||
val klassId = context.referenceClassId(klass.symbol)
|
||||
|
||||
body.buildConstI32Symbol(klassId)
|
||||
generateExpression(call.getValueArgument(0)!!)
|
||||
body.buildGetGlobal(context.referenceClassRTT(klass.symbol))
|
||||
body.buildStructNew(structTypeName)
|
||||
return
|
||||
}
|
||||
|
||||
call.dispatchReceiver?.let { generateExpression(it) }
|
||||
call.extensionReceiver?.let { generateExpression(it) }
|
||||
for (i in 0 until call.valueArgumentsCount) {
|
||||
generateExpression(call.getValueArgument(i)!!)
|
||||
}
|
||||
|
||||
val function: IrFunction = call.symbol.owner.realOverrideTarget
|
||||
|
||||
if (tryToGenerateIntrinsicCall(call, function)) {
|
||||
return
|
||||
}
|
||||
|
||||
val isSuperCall = call is IrCall && call.superQualifierSymbol != null
|
||||
if (function is IrSimpleFunction && function.isOverridable && !isSuperCall) {
|
||||
// Generating index for indirect call
|
||||
val klass = function.parentAsClass
|
||||
if (!klass.isInterface) {
|
||||
val classMetadata = context.getClassMetadata(klass.symbol)
|
||||
val vfSlot = classMetadata.virtualMethods.map { it.function }.indexOf(function)
|
||||
// Dispatch receiver should be simple and without side effects at this point
|
||||
// TODO: Verify
|
||||
generateExpression(call.dispatchReceiver!!)
|
||||
body.buildConstI32(vfSlot)
|
||||
body.buildCall(context.referenceFunction(wasmSymbols.getVirtualMethodId))
|
||||
} else {
|
||||
val signatureId = context.referenceSignatureId(function.wasmSignature(backendContext.irBuiltIns))
|
||||
generateExpression(call.dispatchReceiver!!)
|
||||
body.buildConstI32Symbol(signatureId)
|
||||
body.buildCall(context.referenceFunction(wasmSymbols.getInterfaceMethodId))
|
||||
}
|
||||
|
||||
body.buildCallIndirect(
|
||||
symbol = context.referenceFunctionType(function.symbol)
|
||||
)
|
||||
} else {
|
||||
// Static function call
|
||||
body.buildCall(context.referenceFunction(function.symbol))
|
||||
}
|
||||
|
||||
// Return types of imported functions cannot have concrete struct/array references.
|
||||
// Non-primitive return types are represented as eqref which need to be casted back to expected type on call site.
|
||||
if (function.getWasmImportAnnotation() != null) {
|
||||
val resT = context.transformResultType(function.returnType)
|
||||
if (resT is WasmRefNullType) {
|
||||
generateTypeRTT(function.returnType)
|
||||
body.buildRefCast(fromType = WasmEqRef, toType = resT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateTypeRTT(type: IrType) {
|
||||
val rtClass = type.erasedUpperBound?.symbol ?: context.backendContext.irBuiltIns.anyClass
|
||||
body.buildGetGlobal(context.referenceClassRTT(rtClass))
|
||||
}
|
||||
|
||||
// Return true if generated.
|
||||
// Assumes call arguments are already on the stack
|
||||
private fun tryToGenerateIntrinsicCall(
|
||||
call: IrFunctionAccessExpression,
|
||||
function: IrFunction
|
||||
): Boolean {
|
||||
if (tryToGenerateWasmOpIntrinsicCall(function)) {
|
||||
return true
|
||||
}
|
||||
|
||||
when (function.symbol) {
|
||||
wasmSymbols.wasmClassId -> {
|
||||
val klass = call.getTypeArgument(0)!!.getClass()
|
||||
?: error("No class given for wasmClassId intrinsic")
|
||||
assert(!klass.isInterface)
|
||||
body.buildConstI32Symbol(context.referenceClassId(klass.symbol))
|
||||
}
|
||||
|
||||
wasmSymbols.wasmInterfaceId -> {
|
||||
val irInterface = call.getTypeArgument(0)!!.getClass()
|
||||
?: error("No interface given for wasmInterfaceId intrinsic")
|
||||
assert(irInterface.isInterface)
|
||||
body.buildConstI32Symbol(context.referenceInterfaceId(irInterface.symbol))
|
||||
}
|
||||
|
||||
wasmSymbols.wasmRefCast -> {
|
||||
val fromType = call.getTypeArgument(0)!!
|
||||
val toType = call.getTypeArgument(1)!!
|
||||
generateTypeRTT(toType)
|
||||
body.buildRefCast(context.transformType(fromType), context.transformType(toType))
|
||||
}
|
||||
|
||||
wasmSymbols.wasmFloatNaN -> {
|
||||
body.buildConstF32(Float.NaN)
|
||||
}
|
||||
wasmSymbols.wasmDoubleNaN -> {
|
||||
body.buildConstF64(Double.NaN)
|
||||
}
|
||||
|
||||
wasmSymbols.unboxIntrinsic -> {
|
||||
val fromType = call.getTypeArgument(0)!!
|
||||
|
||||
if (fromType.isNothing()) {
|
||||
body.buildUnreachable()
|
||||
// TODO: Investigate why?
|
||||
return true
|
||||
}
|
||||
|
||||
// Workaround test codegen/box/elvis/nullNullOk.kt
|
||||
if (fromType.makeNotNull().isNothing()) {
|
||||
body.buildUnreachable()
|
||||
return true
|
||||
}
|
||||
|
||||
val toType = call.getTypeArgument(1)!!
|
||||
val klass: IrClass = backendContext.inlineClassesUtils.getInlinedClass(toType)!!
|
||||
val field = getInlineClassBackingField(klass)
|
||||
|
||||
generateTypeRTT(toType)
|
||||
body.buildRefCast(context.transformType(fromType), context.transformBoxedType(toType))
|
||||
generateInstanceFieldAccess(field)
|
||||
}
|
||||
else -> {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression) {
|
||||
val statements = expression.statements
|
||||
if (statements.isEmpty()) return
|
||||
|
||||
statements.dropLast(1).forEach {
|
||||
statementToWasmInstruction(it)
|
||||
}
|
||||
|
||||
if (expression.type != irBuiltIns.unitType) {
|
||||
generateExpression(statements.last() as IrExpression)
|
||||
} else {
|
||||
statementToWasmInstruction(statements.last())
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitBreak(jump: IrBreak) {
|
||||
body.buildBr(context.referenceLoopLevel(jump.loop, LoopLabelType.BREAK))
|
||||
}
|
||||
|
||||
override fun visitContinue(jump: IrContinue) {
|
||||
body.buildBr(context.referenceLoopLevel(jump.loop, LoopLabelType.CONTINUE))
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn) {
|
||||
generateExpression(expression.value)
|
||||
|
||||
// FIXME: Hack for "returning" Unit from functions with generic return type.
|
||||
// Common case -- lambdas returning unit.
|
||||
if (expression.value.type == irBuiltIns.unitType &&
|
||||
expression.returnTargetSymbol.owner.returnType(backendContext) != irBuiltIns.unitType
|
||||
) {
|
||||
val irReturnType = expression.returnTargetSymbol.owner.returnType(backendContext)
|
||||
|
||||
if (irReturnType != irBuiltIns.unitType) {
|
||||
generateDefaultInitializerForType(context.transformType(irReturnType), body)
|
||||
}
|
||||
}
|
||||
|
||||
body.buildInstr(WasmOp.RETURN)
|
||||
}
|
||||
|
||||
override fun visitWhen(expression: IrWhen) {
|
||||
if (expression.type == irBuiltIns.unitType) {
|
||||
var ifCount = 0
|
||||
for (branch in expression.branches) {
|
||||
if (!isElseBranch(branch)) {
|
||||
generateExpression(branch.condition)
|
||||
body.buildIf(label = null, resultType = null)
|
||||
statementToWasmInstruction(branch.result)
|
||||
body.buildElse()
|
||||
ifCount++
|
||||
} else {
|
||||
statementToWasmInstruction(branch.result)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
repeat(ifCount) { body.buildEnd() }
|
||||
return
|
||||
}
|
||||
|
||||
val resultType = context.transformBlockResultType(expression.type)
|
||||
var ifCount = 0
|
||||
for (branch in expression.branches) {
|
||||
if (!isElseBranch(branch)) {
|
||||
generateExpression(branch.condition)
|
||||
body.buildIf(null, resultType)
|
||||
generateExpression(branch.result)
|
||||
if (expression.type == irBuiltIns.nothingType) {
|
||||
body.buildUnreachable()
|
||||
}
|
||||
body.buildElse()
|
||||
ifCount++
|
||||
} else {
|
||||
generateExpression(branch.result)
|
||||
if (expression.type == irBuiltIns.nothingType) {
|
||||
body.buildUnreachable()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
repeat(ifCount) { body.buildEnd() }
|
||||
}
|
||||
|
||||
override fun visitDoWhileLoop(loop: IrDoWhileLoop) {
|
||||
// (loop $LABEL
|
||||
// (block $BREAK_LABEL
|
||||
// (block $CONTINUE_LABEL <LOOP BODY>)
|
||||
// (br_if $LABEL <CONDITION>)))
|
||||
|
||||
val label = loop.label
|
||||
|
||||
body.buildLoop(label)
|
||||
val wasmLoop = body.numberOfNestedBlocks
|
||||
|
||||
body.buildBlock("BREAK_$label")
|
||||
val wasmBreakBlock = body.numberOfNestedBlocks
|
||||
|
||||
body.buildBlock("CONTINUE_$label")
|
||||
val wasmContinueBlock = body.numberOfNestedBlocks
|
||||
|
||||
context.defineLoopLevel(loop, LoopLabelType.BREAK, wasmBreakBlock)
|
||||
context.defineLoopLevel(loop, LoopLabelType.CONTINUE, wasmContinueBlock)
|
||||
|
||||
loop.body?.let { statementToWasmInstruction(it) }
|
||||
body.buildEnd()
|
||||
generateExpression(loop.condition)
|
||||
body.buildBrIf(wasmLoop)
|
||||
body.buildEnd()
|
||||
body.buildEnd()
|
||||
}
|
||||
|
||||
override fun visitWhileLoop(loop: IrWhileLoop) {
|
||||
// (loop $CONTINUE_LABEL
|
||||
// (block $BREAK_LABEL
|
||||
// (br_if $BREAK_LABEL (i32.eqz <CONDITION>))
|
||||
// <LOOP_BODY>
|
||||
// (br $CONTINUE_LABEL)))
|
||||
|
||||
val label = loop.label
|
||||
|
||||
body.buildLoop(label)
|
||||
val wasmLoop = body.numberOfNestedBlocks
|
||||
|
||||
body.buildBlock("BREAK_$label")
|
||||
val wasmBreakBlock = body.numberOfNestedBlocks
|
||||
|
||||
context.defineLoopLevel(loop, LoopLabelType.BREAK, wasmBreakBlock)
|
||||
context.defineLoopLevel(loop, LoopLabelType.CONTINUE, wasmLoop)
|
||||
|
||||
generateExpression(loop.condition)
|
||||
body.buildInstr(WasmOp.I32_EQZ)
|
||||
body.buildBrIf(wasmBreakBlock)
|
||||
loop.body?.let {
|
||||
statementToWasmInstruction(it)
|
||||
}
|
||||
body.buildBr(wasmLoop)
|
||||
body.buildEnd()
|
||||
body.buildEnd()
|
||||
}
|
||||
|
||||
fun generateExpression(expression: IrExpression) {
|
||||
expression.acceptVoid(this)
|
||||
|
||||
if (expression.type == irBuiltIns.nothingType) {
|
||||
body.buildUnreachable()
|
||||
}
|
||||
}
|
||||
|
||||
fun statementToWasmInstruction(statement: IrStatement) {
|
||||
if (statement is IrVariable) {
|
||||
context.defineLocal(statement.symbol)
|
||||
val init = statement.initializer ?: return
|
||||
generateExpression(init)
|
||||
val varName = context.referenceLocal(statement.symbol)
|
||||
body.buildSetLocal(varName)
|
||||
return
|
||||
}
|
||||
|
||||
generateExpression(statement as IrExpression)
|
||||
|
||||
if (statement.type != irBuiltIns.unitType && statement.type != irBuiltIns.nothingType) {
|
||||
body.buildInstr(WasmOp.DROP)
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if function is recognized as intrinsic.
|
||||
fun tryToGenerateWasmOpIntrinsicCall(function: IrFunction): Boolean {
|
||||
if (function.hasWasmReinterpretAnnotation()) {
|
||||
return true
|
||||
}
|
||||
|
||||
val opString = function.getWasmOpAnnotation()
|
||||
if (opString != null) {
|
||||
val op = WasmOp.valueOf(opString)
|
||||
var immediates = emptyArray<WasmImmediate>()
|
||||
when (op.immediates.size) {
|
||||
0 -> {
|
||||
}
|
||||
1 -> {
|
||||
when (val imm = op.immediates[0]) {
|
||||
WasmImmediateKind.MEM_ARG ->
|
||||
immediates = arrayOf(WasmImmediate.MemArg(0u, 0u))
|
||||
else ->
|
||||
error("Immediate $imm is unsupported")
|
||||
}
|
||||
}
|
||||
else ->
|
||||
error("Op $opString is unsupported")
|
||||
}
|
||||
body.buildInstr(op, *immediates)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.wasmSignature
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
|
||||
class ClassMetadata(
|
||||
val klass: IrClass,
|
||||
val superClass: ClassMetadata?,
|
||||
irBuiltIns: IrBuiltIns
|
||||
) {
|
||||
// List of all fields including fields of super classes
|
||||
// In Wasm order
|
||||
val fields: List<IrField> =
|
||||
superClass?.fields.orEmpty() + klass.declarations.filterIsInstance<IrField>()
|
||||
|
||||
// Implemented interfaces in no particular order
|
||||
val interfaces: List<IrClass> = klass.allSuperInterfaces()
|
||||
|
||||
// Virtual methods in Wasm order
|
||||
// TODO: Collect interface methods separately
|
||||
val virtualMethods: List<VirtualMethodMetadata> = run {
|
||||
val virtualFunctions =
|
||||
klass.declarations
|
||||
.filterVirtualFunctions()
|
||||
.map {
|
||||
VirtualMethodMetadata(
|
||||
it,
|
||||
it.wasmSignature(irBuiltIns)
|
||||
)
|
||||
}
|
||||
|
||||
val signatureToVirtualFunction = virtualFunctions.associateBy { it.signature }
|
||||
|
||||
val superSignatures = superClass?.virtualMethodsSignatures.orEmpty()
|
||||
|
||||
val newVirtualMethods = virtualFunctions.filter { it.signature !in superSignatures }
|
||||
val superVirtualMethods = superClass?.virtualMethods.orEmpty().map {
|
||||
signatureToVirtualFunction[it.signature] ?: it
|
||||
}
|
||||
val orderedVirtualFunctions = superVirtualMethods + newVirtualMethods
|
||||
|
||||
orderedVirtualFunctions
|
||||
}
|
||||
|
||||
init {
|
||||
val signatureToFunctions = mutableMapOf<WasmSignature, MutableList<IrSimpleFunction>>()
|
||||
for (vm in virtualMethods) {
|
||||
signatureToFunctions.getOrPut(vm.signature) { mutableListOf() }.add(vm.function)
|
||||
}
|
||||
|
||||
for ((sig, functions) in signatureToFunctions) {
|
||||
if (functions.size > 1) {
|
||||
val funcList = functions.joinToString { " ---- ${it.fqNameWhenAvailable} \n" }
|
||||
// TODO: Check in FE
|
||||
error(
|
||||
"Class ${klass.fqNameWhenAvailable} has ${functions.size} methods with the same signature $sig\n $funcList"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val virtualMethodsSignatures: Set<WasmSignature> =
|
||||
virtualMethods.map { it.signature }.toSet()
|
||||
}
|
||||
|
||||
class VirtualMethodMetadata(
|
||||
val function: IrSimpleFunction,
|
||||
val signature: WasmSignature
|
||||
)
|
||||
|
||||
fun IrClass.allSuperInterfaces(): List<IrClass> =
|
||||
superTypes.map {
|
||||
it.classifierOrFail.owner as IrClass
|
||||
}.flatMap {
|
||||
(if (it.isInterface) listOf(it) else emptyList()) + it.allSuperInterfaces()
|
||||
}
|
||||
|
||||
fun List<IrDeclaration>.filterVirtualFunctions(): List<IrSimpleFunction> =
|
||||
asSequence()
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.filter { it.dispatchReceiverParameter != null }
|
||||
.map { it.realOverrideTarget }
|
||||
.filter { it.isOverridableOrOverrides }
|
||||
.distinct()
|
||||
.toList()
|
||||
|
||||
fun IrClass.getSuperClass(builtIns: IrBuiltIns): IrClass? =
|
||||
when (this) {
|
||||
builtIns.anyClass.owner -> null
|
||||
else -> {
|
||||
superTypes
|
||||
.map { it.classifierOrFail.owner as IrClass }
|
||||
.singleOrNull { !it.isInterface } ?: builtIns.anyClass.owner
|
||||
}
|
||||
}
|
||||
|
||||
fun IrClass.allFields(builtIns: IrBuiltIns): List<IrField> =
|
||||
getSuperClass(builtIns)?.allFields(builtIns).orEmpty() + declarations.filterIsInstance<IrField>()
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.wasm.ir.WasmSymbol
|
||||
|
||||
// Representation of constant data in Wasm memory
|
||||
|
||||
sealed class ConstantDataElement {
|
||||
abstract val sizeInBytes: Int
|
||||
abstract fun dump(indent: String = "", startAddress: Int = 0): String
|
||||
abstract fun toBytes(): ByteArray
|
||||
}
|
||||
|
||||
private fun addressToString(address: Int): String =
|
||||
address.toString().padEnd(6, ' ')
|
||||
|
||||
class ConstantDataIntField(val name: String, val value: WasmSymbol<Int>) : ConstantDataElement() {
|
||||
constructor(name: String, value: Int) : this(name, WasmSymbol(value))
|
||||
|
||||
override fun toBytes(): ByteArray = value.owner.toLittleEndianBytes()
|
||||
|
||||
override fun dump(indent: String, startAddress: Int): String {
|
||||
return "${addressToString(startAddress)}: $indent i32 : ${value.owner} ;; $name\n"
|
||||
}
|
||||
|
||||
override val sizeInBytes: Int = 4
|
||||
}
|
||||
|
||||
class ConstantDataIntArray(val name: String, val value: List<WasmSymbol<Int>>) : ConstantDataElement() {
|
||||
override fun toBytes(): ByteArray {
|
||||
return value.fold(byteArrayOf()) { acc, el -> acc + el.owner.toLittleEndianBytes() }
|
||||
}
|
||||
|
||||
override fun dump(indent: String, startAddress: Int): String {
|
||||
if (value.isEmpty()) return ""
|
||||
return "${addressToString(startAddress)}: $indent i32[] : ${value.map { it.owner }.toIntArray().contentToString()} ;; $name\n"
|
||||
}
|
||||
|
||||
override val sizeInBytes: Int = value.size * 4
|
||||
}
|
||||
|
||||
class ConstantDataStruct(val name: String, val elements: List<ConstantDataElement>) : ConstantDataElement() {
|
||||
override fun toBytes(): ByteArray {
|
||||
return elements.fold(byteArrayOf()) { acc, el -> acc + el.toBytes() }
|
||||
}
|
||||
|
||||
override fun dump(indent: String, startAddress: Int): String {
|
||||
var res = "$indent;; $name\n"
|
||||
var elemStartAddr = startAddress
|
||||
|
||||
for (el in elements) {
|
||||
res += el.dump("$indent ", elemStartAddr)
|
||||
elemStartAddr += el.sizeInBytes
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
override val sizeInBytes: Int = elements.map { it.sizeInBytes }.sum()
|
||||
}
|
||||
|
||||
fun Int.toLittleEndianBytes(): ByteArray {
|
||||
return ByteArray(4) {
|
||||
(this ushr (it * 8)).toByte()
|
||||
}
|
||||
}
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.*
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
|
||||
class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVisitorVoid {
|
||||
|
||||
// Shortcuts
|
||||
private val backendContext: WasmBackendContext = context.backendContext
|
||||
private val irBuiltIns: IrBuiltIns = backendContext.irBuiltIns
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
error("Unexpected element of type ${element::class}")
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(declaration: IrTypeAlias) {
|
||||
// Type aliases are not material
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
// Inline class constructors are currently empty
|
||||
if (declaration is IrConstructor && backendContext.inlineClassesUtils.isClassInlineLike(declaration.parentAsClass))
|
||||
return
|
||||
|
||||
val importedName = declaration.getWasmImportAnnotation()
|
||||
|
||||
val isIntrinsic = declaration.hasWasmReinterpretAnnotation() || declaration.getWasmOpAnnotation() != null
|
||||
if (isIntrinsic) {
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration.isFakeOverride)
|
||||
return
|
||||
|
||||
// Generate function type
|
||||
val watName = declaration.fqNameWhenAvailable.toString()
|
||||
val irParameters = declaration.getEffectiveValueParameters()
|
||||
val wasmFunctionType =
|
||||
WasmFunctionType(
|
||||
name = watName,
|
||||
parameterTypes = irParameters.map {
|
||||
val t = context.transformValueParameterType(it)
|
||||
if (importedName != null && t is WasmRefNullType) {
|
||||
WasmEqRef
|
||||
} else {
|
||||
t
|
||||
}
|
||||
},
|
||||
resultTypes = listOfNotNull(
|
||||
context.transformResultType(declaration.returnType).let {
|
||||
if (importedName != null && it is WasmRefNullType) WasmEqRef else it
|
||||
}
|
||||
)
|
||||
)
|
||||
context.defineFunctionType(declaration.symbol, wasmFunctionType)
|
||||
|
||||
if (declaration is IrSimpleFunction) {
|
||||
if (declaration.modality == Modality.ABSTRACT) return
|
||||
if (declaration.isOverridableOrOverrides) {
|
||||
// Register function as virtual, meaning this function
|
||||
// will be stored Wasm table and could be called indirectly.
|
||||
context.registerVirtualFunction(declaration.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
assert(declaration == declaration.realOverrideTarget) {
|
||||
"Sanity check that $declaration is a real function that can be used in calls"
|
||||
}
|
||||
|
||||
if (importedName != null) {
|
||||
// Imported functions don't have bodies. Declaring the signature:
|
||||
context.defineFunction(
|
||||
declaration.symbol,
|
||||
WasmFunction.Imported(watName, wasmFunctionType, importedName)
|
||||
)
|
||||
// TODO: Support re-export of imported functions.
|
||||
return
|
||||
}
|
||||
|
||||
val function = WasmFunction.Defined(watName, wasmFunctionType)
|
||||
val functionCodegenContext = WasmFunctionCodegenContextImpl(
|
||||
declaration,
|
||||
function,
|
||||
backendContext,
|
||||
context
|
||||
)
|
||||
|
||||
for (irParameter in irParameters) {
|
||||
functionCodegenContext.defineLocal(irParameter.symbol)
|
||||
}
|
||||
|
||||
val exprGen = functionCodegenContext.bodyGen
|
||||
val bodyBuilder = BodyGenerator(functionCodegenContext)
|
||||
|
||||
when (val body = declaration.body) {
|
||||
is IrBlockBody ->
|
||||
for (statement in body.statements) {
|
||||
bodyBuilder.statementToWasmInstruction(statement)
|
||||
}
|
||||
|
||||
is IrExpressionBody ->
|
||||
bodyBuilder.generateExpression(body.expression)
|
||||
|
||||
else -> error("Unexpected body $body")
|
||||
}
|
||||
|
||||
// Return implicit this from constructions to avoid extra tmp
|
||||
// variables on constructor call sites.
|
||||
// TODO: Redesign construction scheme.
|
||||
if (declaration is IrConstructor) {
|
||||
exprGen.buildGetLocal(/*implicit this*/ function.locals[0])
|
||||
exprGen.buildInstr(WasmOp.RETURN)
|
||||
}
|
||||
|
||||
// Add unreachable if function returns something but not as a last instruction.
|
||||
if (wasmFunctionType.resultTypes.isNotEmpty() && declaration.body is IrBlockBody) {
|
||||
// TODO: Add unreachable only if needed
|
||||
exprGen.buildUnreachable()
|
||||
}
|
||||
|
||||
context.defineFunction(declaration.symbol, function)
|
||||
|
||||
if (declaration == backendContext.startFunction)
|
||||
context.setStartFunction(function)
|
||||
|
||||
if (declaration.isExported(backendContext)) {
|
||||
context.addExport(
|
||||
WasmExport.Function(
|
||||
field = function,
|
||||
// TODO: Add ability to specify exported name.
|
||||
name = declaration.name.identifier
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (declaration.isAnnotationClass) return
|
||||
val symbol = declaration.symbol
|
||||
|
||||
if (declaration.isInterface) {
|
||||
context.registerInterface(symbol)
|
||||
} else {
|
||||
val nameStr = declaration.fqNameWhenAvailable.toString()
|
||||
val structType = WasmStructDeclaration(
|
||||
name = nameStr,
|
||||
fields = declaration.allFields(irBuiltIns).map {
|
||||
WasmStructFieldDeclaration(
|
||||
name = it.name.toString(),
|
||||
type = context.transformType(it.type),
|
||||
isMutable = true
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
context.defineStructType(symbol, structType)
|
||||
|
||||
var depth = 2
|
||||
val metadata = context.getClassMetadata(symbol)
|
||||
var subMetadata = metadata
|
||||
while (true) {
|
||||
subMetadata = subMetadata.superClass ?: break
|
||||
depth++
|
||||
}
|
||||
|
||||
val initBody = mutableListOf<WasmInstr>()
|
||||
val wasmExpressionGenerator = WasmIrExpressionBuilder(initBody)
|
||||
|
||||
val superClass = metadata.superClass
|
||||
if (superClass != null) {
|
||||
val superRTT = context.referenceClassRTT(superClass.klass.symbol)
|
||||
wasmExpressionGenerator.buildGetGlobal(superRTT)
|
||||
} else {
|
||||
wasmExpressionGenerator.buildRttCanon(WasmRefType(WasmHeapType.Simple.Eq))
|
||||
}
|
||||
|
||||
wasmExpressionGenerator.buildRttSub(
|
||||
WasmRefType(WasmHeapType.Type(WasmSymbol(structType)))
|
||||
)
|
||||
|
||||
val rtt = WasmGlobal(
|
||||
name = "rtt_of_$nameStr",
|
||||
isMutable = false,
|
||||
type = WasmRtt(depth, WasmHeapType.Type(WasmSymbol(structType))),
|
||||
init = initBody
|
||||
)
|
||||
|
||||
context.defineRTT(symbol, rtt)
|
||||
context.registerClass(symbol)
|
||||
context.generateTypeInfo(symbol, binaryDataStruct(metadata))
|
||||
}
|
||||
|
||||
for (member in declaration.declarations) {
|
||||
member.acceptVoid(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun binaryDataStruct(classMetadata: ClassMetadata): ConstantDataStruct {
|
||||
val invalidIndex = -1
|
||||
val superClass = classMetadata.superClass?.klass
|
||||
|
||||
val superClassSymbol: WasmSymbol<Int> =
|
||||
superClass?.let { context.referenceClassId(it.symbol) } ?: WasmSymbol(invalidIndex)
|
||||
|
||||
val superTypeField =
|
||||
ConstantDataIntField("Super class", superClassSymbol)
|
||||
|
||||
val interfacesArray = ConstantDataIntArray(
|
||||
"data",
|
||||
classMetadata.interfaces.map { context.referenceInterfaceId(it.symbol) }
|
||||
)
|
||||
val interfacesArraySize = ConstantDataIntField(
|
||||
"size",
|
||||
interfacesArray.value.size
|
||||
)
|
||||
|
||||
val implementedInterfacesArrayWithSize = ConstantDataStruct(
|
||||
"Implemented interfaces array",
|
||||
listOf(interfacesArraySize, interfacesArray)
|
||||
)
|
||||
|
||||
val vtableSizeField = ConstantDataIntField(
|
||||
"V-table length",
|
||||
classMetadata.virtualMethods.size
|
||||
)
|
||||
|
||||
val vtableArray = ConstantDataIntArray(
|
||||
"V-table",
|
||||
classMetadata.virtualMethods.map {
|
||||
if (it.function.modality == Modality.ABSTRACT) {
|
||||
WasmSymbol(invalidIndex)
|
||||
} else {
|
||||
context.referenceVirtualFunctionId(it.function.symbol)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val signaturesArray = ConstantDataIntArray(
|
||||
"Signatures",
|
||||
classMetadata.virtualMethods.map {
|
||||
if (it.function.modality == Modality.ABSTRACT) {
|
||||
WasmSymbol(invalidIndex)
|
||||
} else {
|
||||
context.referenceSignatureId(it.signature)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return ConstantDataStruct(
|
||||
"Class TypeInfo: ${classMetadata.klass.fqNameWhenAvailable} ",
|
||||
listOf(
|
||||
superTypeField,
|
||||
vtableSizeField,
|
||||
vtableArray,
|
||||
signaturesArray,
|
||||
implementedInterfacesArrayWithSize,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) {
|
||||
// Member fields are generated as part of struct type
|
||||
if (!declaration.isStatic) return
|
||||
|
||||
val wasmType = context.transformType(declaration.type)
|
||||
|
||||
val initBody = mutableListOf<WasmInstr>()
|
||||
val wasmExpressionGenerator = WasmIrExpressionBuilder(initBody)
|
||||
generateDefaultInitializerForType(wasmType, wasmExpressionGenerator)
|
||||
|
||||
val global = WasmGlobal(
|
||||
name = declaration.fqNameWhenAvailable.toString(),
|
||||
type = wasmType,
|
||||
isMutable = true,
|
||||
// All globals are currently initialized in start function
|
||||
init = initBody
|
||||
)
|
||||
|
||||
context.defineGlobal(declaration.symbol, global)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun generateDefaultInitializerForType(type: WasmType, g: WasmExpressionBuilder) = when (type) {
|
||||
WasmI32 -> g.buildConstI32(0)
|
||||
WasmI1 -> g.buildConstI32(0)
|
||||
WasmI64 -> g.buildConstI64(0)
|
||||
WasmF32 -> g.buildConstF32(0f)
|
||||
WasmF64 -> g.buildConstF64(0.0)
|
||||
is WasmRefNullType -> g.buildRefNull(type.heapType)
|
||||
is WasmExternRef -> g.buildRefNull(WasmHeapType.Simple.Extern)
|
||||
WasmUnreachableType -> error("Unreachable type can't be initialized")
|
||||
else -> error("Unknown value type ${type.name}")
|
||||
}
|
||||
|
||||
fun IrFunction.getEffectiveValueParameters(): List<IrValueParameter> {
|
||||
val implicitThis = if (this is IrConstructor) parentAsClass.thisReceiver!! else null
|
||||
return listOfNotNull(implicitThis, dispatchReceiverParameter, extensionReceiverParameter) + valueParameters
|
||||
}
|
||||
|
||||
fun IrFunction.isExported(context: WasmBackendContext): Boolean =
|
||||
visibility == DescriptorVisibilities.PUBLIC && fqNameWhenAvailable in context.additionalExportedDeclarations
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsAssignment
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsArrayLiteral
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsBlock
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsStringLiteral
|
||||
|
||||
fun generateStringLiteralsSupport(literals: List<String>): String {
|
||||
return JsBlock(
|
||||
jsAssignment(
|
||||
JsNameRef("stringLiterals", "runtime"),
|
||||
JsArrayLiteral(literals.map { JsStringLiteral(it) })
|
||||
).makeStmt()
|
||||
).toString()
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.hasWasmForeignAnnotation
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.util.getInlineClassUnderlyingType
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
|
||||
class WasmTypeTransformer(
|
||||
val context: WasmBaseCodegenContext,
|
||||
val builtIns: IrBuiltIns
|
||||
) {
|
||||
fun IrType.toWasmResultType(): WasmType? =
|
||||
when (this) {
|
||||
builtIns.unitType,
|
||||
builtIns.nothingType ->
|
||||
null
|
||||
|
||||
else ->
|
||||
toWasmValueType()
|
||||
}
|
||||
|
||||
fun IrType.toWasmBlockResultType(): WasmType? =
|
||||
when (this) {
|
||||
builtIns.unitType ->
|
||||
null
|
||||
|
||||
// TODO: Lower blocks with Nothing type?
|
||||
builtIns.nothingType ->
|
||||
WasmUnreachableType
|
||||
|
||||
else ->
|
||||
toWasmValueType()
|
||||
}
|
||||
|
||||
fun IrType.toStructType(): WasmType =
|
||||
WasmRefNullType(WasmHeapType.Type(context.referenceStructType(erasedUpperBound?.symbol ?: builtIns.anyClass)))
|
||||
|
||||
fun IrType.toBoxedInlineClassType(): WasmType =
|
||||
toStructType()
|
||||
|
||||
fun IrType.toWasmValueType(): WasmType =
|
||||
when (this) {
|
||||
builtIns.booleanType,
|
||||
builtIns.byteType,
|
||||
builtIns.shortType,
|
||||
builtIns.intType,
|
||||
builtIns.charType ->
|
||||
WasmI32
|
||||
|
||||
builtIns.longType ->
|
||||
WasmI64
|
||||
|
||||
builtIns.floatType ->
|
||||
WasmF32
|
||||
|
||||
builtIns.doubleType ->
|
||||
WasmF64
|
||||
|
||||
builtIns.stringType ->
|
||||
WasmExternRef
|
||||
|
||||
builtIns.nothingNType ->
|
||||
WasmExternRef
|
||||
|
||||
// Value will not be created. Just using a random Wasm type.
|
||||
builtIns.nothingType ->
|
||||
WasmExternRef
|
||||
|
||||
else -> {
|
||||
val klass = this.getClass()
|
||||
val ic = context.backendContext.inlineClassesUtils.getInlinedClass(this)
|
||||
|
||||
if (klass != null && klass.hasWasmForeignAnnotation()) {
|
||||
WasmExternRef
|
||||
} else if (ic != null) {
|
||||
getInlineClassUnderlyingType(ic).toWasmValueType()
|
||||
} else {
|
||||
this.toStructType()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return null if upper bound is Any
|
||||
val IrTypeParameter.erasedUpperBound: IrClass?
|
||||
get() {
|
||||
// Pick the (necessarily unique) non-interface upper bound if it exists
|
||||
for (type in superTypes) {
|
||||
return type.erasedUpperBound ?: continue
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
val IrType.erasedUpperBound: IrClass?
|
||||
get() = when (val classifier = classifierOrNull) {
|
||||
is IrClassSymbol -> classifier.owner
|
||||
is IrTypeParameterSymbol -> classifier.owner.erasedUpperBound
|
||||
else -> throw IllegalStateException()
|
||||
}.let {
|
||||
if (it?.isInterface == true) null
|
||||
else it
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
|
||||
interface WasmBaseCodegenContext {
|
||||
val backendContext: WasmBackendContext
|
||||
|
||||
fun referenceFunction(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunction>
|
||||
fun referenceGlobal(irField: IrFieldSymbol): WasmSymbol<WasmGlobal>
|
||||
fun referenceStructType(irClass: IrClassSymbol): WasmSymbol<WasmStructDeclaration>
|
||||
fun referenceFunctionType(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunctionType>
|
||||
|
||||
fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int>
|
||||
fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int>
|
||||
fun referenceVirtualFunctionId(irFunction: IrSimpleFunctionSymbol): WasmSymbol<Int>
|
||||
fun referenceClassRTT(irClass: IrClassSymbol): WasmSymbol<WasmGlobal>
|
||||
|
||||
fun referenceSignatureId(signature: WasmSignature): WasmSymbol<Int>
|
||||
|
||||
fun referenceStringLiteral(string: String): WasmSymbol<Int>
|
||||
|
||||
fun transformType(irType: IrType): WasmType
|
||||
fun transformBoxedType(irType: IrType): WasmType
|
||||
fun transformValueParameterType(irValueParameter: IrValueParameter): WasmType
|
||||
fun transformResultType(irType: IrType): WasmType?
|
||||
fun transformBlockResultType(irType: IrType): WasmType?
|
||||
|
||||
|
||||
fun getStructFieldRef(field: IrField): WasmSymbol<Int>
|
||||
fun getClassMetadata(irClass: IrClassSymbol): ClassMetadata
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||
|
||||
class WasmCompiledModuleFragment {
|
||||
val functions =
|
||||
ReferencableAndDefinable<IrFunctionSymbol, WasmFunction>()
|
||||
val globals =
|
||||
ReferencableAndDefinable<IrFieldSymbol, WasmGlobal>()
|
||||
val functionTypes =
|
||||
ReferencableAndDefinable<IrFunctionSymbol, WasmFunctionType>()
|
||||
val structTypes =
|
||||
ReferencableAndDefinable<IrClassSymbol, WasmStructDeclaration>()
|
||||
val classIds =
|
||||
ReferencableElements<IrClassSymbol, Int>()
|
||||
val interfaceId =
|
||||
ReferencableElements<IrClassSymbol, Int>()
|
||||
val virtualFunctionId =
|
||||
ReferencableElements<IrFunctionSymbol, Int>()
|
||||
val signatureId =
|
||||
ReferencableElements<WasmSignature, Int>()
|
||||
val stringLiteralId =
|
||||
ReferencableElements<String, Int>()
|
||||
|
||||
val runtimeTypes =
|
||||
ReferencableAndDefinable<IrClassSymbol, WasmGlobal>()
|
||||
|
||||
val classes = mutableListOf<IrClassSymbol>()
|
||||
val interfaces = mutableListOf<IrClassSymbol>()
|
||||
val virtualFunctions = mutableListOf<IrSimpleFunctionSymbol>()
|
||||
val signatures = LinkedHashSet<WasmSignature>()
|
||||
val stringLiterals = mutableListOf<String>()
|
||||
|
||||
val typeInfo =
|
||||
ReferencableAndDefinable<IrClassSymbol, ConstantDataElement>()
|
||||
val exports = mutableListOf<WasmExport<*>>()
|
||||
|
||||
//
|
||||
var startFunction: WasmFunction? = null
|
||||
|
||||
open class ReferencableElements<Ir, Wasm : Any> {
|
||||
val unbound = mutableMapOf<Ir, WasmSymbol<Wasm>>()
|
||||
fun reference(ir: Ir): WasmSymbol<Wasm> {
|
||||
val declaration = (ir as? IrSymbol)?.owner as? IrDeclarationWithName
|
||||
if (declaration != null) {
|
||||
val packageFragment = declaration.getPackageFragment()
|
||||
?: error("Referencing declaration without package fragment ${declaration.fqNameWhenAvailable}")
|
||||
if (packageFragment is IrExternalPackageFragment) {
|
||||
error("Referencing declaration without package fragment ${declaration.fqNameWhenAvailable}")
|
||||
}
|
||||
}
|
||||
return unbound.getOrPut(ir) { WasmSymbol() }
|
||||
}
|
||||
}
|
||||
|
||||
class ReferencableAndDefinable<Ir, Wasm : Any> : ReferencableElements<Ir, Wasm>() {
|
||||
fun define(ir: Ir, wasm: Wasm) {
|
||||
if (ir in defined)
|
||||
error("Trying to redefine element: IR: $ir Wasm: $wasm")
|
||||
|
||||
elements += wasm
|
||||
defined[ir] = wasm
|
||||
wasmToIr[wasm] = ir
|
||||
}
|
||||
|
||||
val defined = LinkedHashMap<Ir, Wasm>()
|
||||
val elements = mutableListOf<Wasm>()
|
||||
|
||||
val wasmToIr = mutableMapOf<Wasm, Ir>()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
fun linkWasmCompiledFragments(): WasmModule {
|
||||
bind(functions.unbound, functions.defined)
|
||||
bind(globals.unbound, globals.defined)
|
||||
bind(functionTypes.unbound, functionTypes.defined)
|
||||
bind(structTypes.unbound, structTypes.defined)
|
||||
bind(runtimeTypes.unbound, runtimeTypes.defined)
|
||||
|
||||
val klassIds = mutableMapOf<IrClassSymbol, Int>()
|
||||
var classId = 0
|
||||
for (typeInfoElement in typeInfo.elements) {
|
||||
val ir = typeInfo.wasmToIr.getValue(typeInfoElement)
|
||||
klassIds[ir] = classId
|
||||
classId += typeInfoElement.sizeInBytes
|
||||
}
|
||||
|
||||
bind(classIds.unbound, klassIds)
|
||||
bindIndices(virtualFunctionId.unbound, virtualFunctions)
|
||||
bindIndices(signatureId.unbound, signatures.toList())
|
||||
bindIndices(interfaceId.unbound, interfaces)
|
||||
bindIndices(stringLiteralId.unbound, stringLiterals)
|
||||
|
||||
val data = typeInfo.elements.map {
|
||||
val ir = typeInfo.wasmToIr.getValue(it)
|
||||
val id = klassIds.getValue(ir)
|
||||
val offset = mutableListOf<WasmInstr>()
|
||||
WasmIrExpressionBuilder(offset).buildConstI32(id)
|
||||
WasmData(WasmDataMode.Active(0, offset), it.toBytes())
|
||||
}
|
||||
|
||||
val logTypeInfo = false
|
||||
if (logTypeInfo) {
|
||||
println("Signatures: ")
|
||||
for ((index, signature: WasmSignature) in signatures.withIndex()) {
|
||||
println(" -- $index $signature")
|
||||
}
|
||||
|
||||
println("Interfaces: ")
|
||||
for ((index, iface: IrClassSymbol) in interfaces.withIndex()) {
|
||||
println(" -- $index ${iface.owner.fqNameWhenAvailable}")
|
||||
}
|
||||
|
||||
println("Virtual functions: ")
|
||||
for ((index, vf: IrSimpleFunctionSymbol) in virtualFunctions.withIndex()) {
|
||||
println(" -- $index ${vf.owner.fqNameWhenAvailable}")
|
||||
}
|
||||
|
||||
println(
|
||||
ConstantDataStruct("typeInfo", typeInfo.elements).dump("", 0)
|
||||
)
|
||||
}
|
||||
|
||||
val table = WasmTable(
|
||||
limits = WasmLimits(virtualFunctions.size.toUInt(), virtualFunctions.size.toUInt()),
|
||||
elementType = WasmFuncRef,
|
||||
)
|
||||
|
||||
val offsetExpr = mutableListOf<WasmInstr>()
|
||||
WasmIrExpressionBuilder(offsetExpr).buildConstI32(0)
|
||||
|
||||
val elements = WasmElement(
|
||||
WasmFuncRef,
|
||||
values = virtualFunctions.map {
|
||||
WasmTable.Value.Function(functions.defined.getValue(it))
|
||||
},
|
||||
WasmElement.Mode.Active(table, offsetExpr)
|
||||
)
|
||||
|
||||
val typeInfoSize = classId
|
||||
val memorySizeInPages = (typeInfoSize / 65_536) + 1
|
||||
val memory = WasmMemory(WasmLimits(memorySizeInPages.toUInt(), memorySizeInPages.toUInt()))
|
||||
|
||||
val importedFunctions = functions.elements.filterIsInstance<WasmFunction.Imported>()
|
||||
|
||||
// Sorting by depth for a valid init order
|
||||
val sortedRttGlobals = runtimeTypes.elements.sortedBy { (it.type as WasmRtt).depth }
|
||||
|
||||
val module = WasmModule(
|
||||
functionTypes = functionTypes.elements,
|
||||
structs = structTypes.elements,
|
||||
importsInOrder = importedFunctions,
|
||||
importedFunctions = importedFunctions,
|
||||
definedFunctions = functions.elements.filterIsInstance<WasmFunction.Defined>(),
|
||||
tables = listOf(table),
|
||||
memories = listOf(memory),
|
||||
globals = globals.elements + sortedRttGlobals,
|
||||
exports = exports,
|
||||
startFunction = startFunction!!,
|
||||
elements = listOf(elements),
|
||||
data = data
|
||||
)
|
||||
module.calculateIds()
|
||||
return module
|
||||
}
|
||||
}
|
||||
|
||||
fun <IrSymbolType, WasmDeclarationType : Any, WasmSymbolType : WasmSymbol<WasmDeclarationType>> bind(
|
||||
unbound: Map<IrSymbolType, WasmSymbolType>,
|
||||
defined: Map<IrSymbolType, WasmDeclarationType>
|
||||
) {
|
||||
unbound.forEach { (irSymbol, wasmSymbol) ->
|
||||
if (irSymbol !in defined)
|
||||
error("Can't link symbol ${irSymbolDebugDump(irSymbol)}")
|
||||
wasmSymbol.bind(defined.getValue(irSymbol))
|
||||
}
|
||||
}
|
||||
|
||||
private fun irSymbolDebugDump(symbol: Any?): String =
|
||||
when (symbol) {
|
||||
is IrFunctionSymbol -> "function ${symbol.owner.fqNameWhenAvailable}"
|
||||
is IrClassSymbol -> "class ${symbol.owner.fqNameWhenAvailable}"
|
||||
else -> symbol.toString()
|
||||
}
|
||||
|
||||
fun <IrSymbolType> bindIndices(
|
||||
unbound: Map<IrSymbolType, WasmSymbol<Int>>,
|
||||
ordered: List<IrSymbolType>
|
||||
) {
|
||||
unbound.forEach { (irSymbol, wasmSymbol) ->
|
||||
val index = ordered.indexOf(irSymbol)
|
||||
if (index == -1)
|
||||
error("Can't link symbol with indices ${irSymbolDebugDump(irSymbol)}")
|
||||
wasmSymbol.bind(index)
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.wasm.ir.WasmExpressionBuilder
|
||||
import org.jetbrains.kotlin.wasm.ir.WasmInstr
|
||||
import org.jetbrains.kotlin.wasm.ir.WasmLocal
|
||||
|
||||
enum class LoopLabelType { BREAK, CONTINUE }
|
||||
|
||||
interface WasmFunctionCodegenContext : WasmBaseCodegenContext {
|
||||
val irFunction: IrFunction
|
||||
|
||||
fun defineLocal(irValueDeclaration: IrValueSymbol)
|
||||
fun referenceLocal(irValueDeclaration: IrValueSymbol): WasmLocal
|
||||
fun referenceLocal(index: Int): WasmLocal
|
||||
|
||||
fun defineLoopLevel(irLoop: IrLoop, labelType: LoopLabelType, level: Int)
|
||||
fun referenceLoopLevel(irLoop: IrLoop, labelType: LoopLabelType): Int
|
||||
|
||||
val bodyGen: WasmExpressionBuilder
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
|
||||
class WasmFunctionCodegenContextImpl(
|
||||
override val irFunction: IrFunction,
|
||||
private val wasmFunction: WasmFunction.Defined,
|
||||
override val backendContext: WasmBackendContext,
|
||||
private val referencing: WasmBaseCodegenContext
|
||||
) : WasmBaseCodegenContext by referencing,
|
||||
WasmFunctionCodegenContext {
|
||||
override val bodyGen: WasmExpressionBuilder =
|
||||
WasmIrExpressionBuilder(wasmFunction.instructions)
|
||||
|
||||
private val wasmLocals = LinkedHashMap<IrValueSymbol, WasmLocal>()
|
||||
private val loopLevels = LinkedHashMap<Pair<IrLoop, LoopLabelType>, Int>()
|
||||
|
||||
override fun defineLocal(irValueDeclaration: IrValueSymbol) {
|
||||
assert(irValueDeclaration !in wasmLocals) { "Redefinition of local" }
|
||||
|
||||
val owner = irValueDeclaration.owner
|
||||
val wasmLocal = WasmLocal(
|
||||
wasmFunction.locals.size,
|
||||
owner.name.asString(),
|
||||
if (owner is IrValueParameter) transformValueParameterType(owner) else transformType(owner.type),
|
||||
isParameter = irValueDeclaration is IrValueParameterSymbol
|
||||
)
|
||||
|
||||
wasmLocals[irValueDeclaration] = wasmLocal
|
||||
wasmFunction.locals += wasmLocal
|
||||
}
|
||||
|
||||
override fun referenceLocal(irValueDeclaration: IrValueSymbol): WasmLocal {
|
||||
return wasmLocals.getValue(irValueDeclaration)
|
||||
}
|
||||
|
||||
override fun referenceLocal(index: Int): WasmLocal {
|
||||
return wasmFunction.locals[index]
|
||||
}
|
||||
|
||||
override fun defineLoopLevel(irLoop: IrLoop, labelType: LoopLabelType, level: Int) {
|
||||
val loopKey = Pair(irLoop, labelType)
|
||||
assert(loopKey !in loopLevels) { "Redefinition of loop" }
|
||||
loopLevels[loopKey] = level
|
||||
}
|
||||
|
||||
override fun referenceLoopLevel(irLoop: IrLoop, labelType: LoopLabelType): Int {
|
||||
return loopLevels.getValue(Pair(irLoop, labelType))
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.ConstantDataElement
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmBaseCodegenContext
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
|
||||
/**
|
||||
* Interface for generating WebAssembly module.
|
||||
*/
|
||||
interface WasmModuleCodegenContext : WasmBaseCodegenContext {
|
||||
fun defineFunction(irFunction: IrFunctionSymbol, wasmFunction: WasmFunction)
|
||||
fun defineGlobal(irField: IrFieldSymbol, wasmGlobal: WasmGlobal)
|
||||
fun defineStructType(irClass: IrClassSymbol, wasmStruct: WasmStructDeclaration)
|
||||
fun defineRTT(irClass: IrClassSymbol, wasmGlobal: WasmGlobal)
|
||||
fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: WasmFunctionType)
|
||||
|
||||
fun setStartFunction(wasmFunction: WasmFunction)
|
||||
fun addExport(wasmExport: WasmExport<*>)
|
||||
|
||||
fun registerVirtualFunction(irFunction: IrSimpleFunctionSymbol)
|
||||
fun registerInterface(irInterface: IrClassSymbol)
|
||||
fun registerClass(irClass: IrClassSymbol)
|
||||
|
||||
fun generateTypeInfo(irClass: IrClassSymbol, typeInfo: ConstantDataElement)
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.wasm.ir.*
|
||||
import org.jetbrains.kotlin.backend.wasm.lower.WasmSignature
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.util.isFunction
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
|
||||
|
||||
class WasmModuleCodegenContextImpl(
|
||||
override val backendContext: WasmBackendContext,
|
||||
private val wasmFragment: WasmCompiledModuleFragment
|
||||
) : WasmModuleCodegenContext {
|
||||
private val typeTransformer =
|
||||
WasmTypeTransformer(this, backendContext.irBuiltIns)
|
||||
|
||||
override fun transformType(irType: IrType): WasmType {
|
||||
return with(typeTransformer) { irType.toWasmValueType() }
|
||||
}
|
||||
|
||||
override fun transformBoxedType(irType: IrType): WasmType {
|
||||
return with(typeTransformer) { irType.toBoxedInlineClassType() }
|
||||
}
|
||||
|
||||
override fun transformValueParameterType(irValueParameter: IrValueParameter): WasmType {
|
||||
return with(typeTransformer) {
|
||||
if (context.backendContext.inlineClassesUtils.shouldValueParameterBeBoxed(irValueParameter)) {
|
||||
irValueParameter.type.toBoxedInlineClassType()
|
||||
} else {
|
||||
irValueParameter.type.toWasmValueType()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformResultType(irType: IrType): WasmType? {
|
||||
return with(typeTransformer) { irType.toWasmResultType() }
|
||||
}
|
||||
|
||||
override fun transformBlockResultType(irType: IrType): WasmType? {
|
||||
return with(typeTransformer) { irType.toWasmBlockResultType() }
|
||||
}
|
||||
|
||||
override fun referenceStringLiteral(string: String): WasmSymbol<Int> {
|
||||
wasmFragment.stringLiterals.add(string)
|
||||
return wasmFragment.stringLiteralId.reference(string)
|
||||
}
|
||||
|
||||
override fun generateTypeInfo(irClass: IrClassSymbol, typeInfo: ConstantDataElement) {
|
||||
wasmFragment.typeInfo.define(irClass, typeInfo)
|
||||
}
|
||||
|
||||
override fun setStartFunction(wasmFunction: WasmFunction) {
|
||||
wasmFragment.startFunction = wasmFunction
|
||||
}
|
||||
|
||||
override fun addExport(wasmExport: WasmExport<*>) {
|
||||
wasmFragment.exports += wasmExport
|
||||
}
|
||||
|
||||
override fun registerVirtualFunction(irFunction: IrSimpleFunctionSymbol) {
|
||||
wasmFragment.virtualFunctions += irFunction
|
||||
}
|
||||
|
||||
override fun registerInterface(irInterface: IrClassSymbol) {
|
||||
wasmFragment.interfaces += irInterface
|
||||
}
|
||||
|
||||
override fun registerClass(irClass: IrClassSymbol) {
|
||||
wasmFragment.classes += irClass
|
||||
}
|
||||
|
||||
override fun defineFunction(irFunction: IrFunctionSymbol, wasmFunction: WasmFunction) {
|
||||
wasmFragment.functions.define(irFunction, wasmFunction)
|
||||
}
|
||||
|
||||
override fun defineGlobal(irField: IrFieldSymbol, wasmGlobal: WasmGlobal) {
|
||||
wasmFragment.globals.define(irField, wasmGlobal)
|
||||
}
|
||||
|
||||
override fun defineStructType(irClass: IrClassSymbol, wasmStruct: WasmStructDeclaration) {
|
||||
wasmFragment.structTypes.define(irClass, wasmStruct)
|
||||
}
|
||||
|
||||
override fun defineRTT(irClass: IrClassSymbol, wasmGlobal: WasmGlobal) {
|
||||
wasmFragment.runtimeTypes.define(irClass, wasmGlobal)
|
||||
}
|
||||
|
||||
override fun defineFunctionType(irFunction: IrFunctionSymbol, wasmFunctionType: WasmFunctionType) {
|
||||
wasmFragment.functionTypes.define(irFunction, wasmFunctionType)
|
||||
}
|
||||
|
||||
private val classMetadataCache = mutableMapOf<IrClassSymbol, ClassMetadata>()
|
||||
override fun getClassMetadata(irClass: IrClassSymbol): ClassMetadata =
|
||||
classMetadataCache.getOrPut(irClass) {
|
||||
val superClass = irClass.owner.getSuperClass(backendContext.irBuiltIns)
|
||||
val superClassMetadata = superClass?.let { getClassMetadata(it.symbol) }
|
||||
ClassMetadata(
|
||||
irClass.owner,
|
||||
superClassMetadata,
|
||||
backendContext.irBuiltIns
|
||||
)
|
||||
}
|
||||
|
||||
override fun referenceFunction(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunction> =
|
||||
wasmFragment.functions.reference(irFunction)
|
||||
|
||||
override fun referenceGlobal(irField: IrFieldSymbol): WasmSymbol<WasmGlobal> =
|
||||
wasmFragment.globals.reference(irField)
|
||||
|
||||
override fun referenceStructType(irClass: IrClassSymbol): WasmSymbol<WasmStructDeclaration> {
|
||||
val type = irClass.defaultType
|
||||
require(!type.isNothing()) {
|
||||
"Can't reference Nothing type"
|
||||
}
|
||||
return wasmFragment.structTypes.reference(irClass)
|
||||
}
|
||||
|
||||
override fun referenceClassRTT(irClass: IrClassSymbol): WasmSymbol<WasmGlobal> =
|
||||
wasmFragment.runtimeTypes.reference(irClass)
|
||||
|
||||
override fun referenceFunctionType(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunctionType> =
|
||||
wasmFragment.functionTypes.reference(irFunction)
|
||||
|
||||
override fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int> =
|
||||
wasmFragment.classIds.reference(irClass)
|
||||
|
||||
override fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int> {
|
||||
// HACK to substitute kotlin.Function5 with kotlin.wasm.internal.Function5
|
||||
val defaultType = irInterface.defaultType
|
||||
if (defaultType.isFunction()) {
|
||||
val n = irInterface.owner.typeParameters.size - 1
|
||||
return wasmFragment.interfaceId.reference(backendContext.wasmSymbols.functionN(n))
|
||||
}
|
||||
return wasmFragment.interfaceId.reference(irInterface)
|
||||
}
|
||||
|
||||
override fun referenceVirtualFunctionId(irFunction: IrSimpleFunctionSymbol): WasmSymbol<Int> {
|
||||
if (irFunction.owner.modality == Modality.ABSTRACT)
|
||||
error("Abstract functions are not stored in table")
|
||||
return wasmFragment.virtualFunctionId.reference(irFunction)
|
||||
}
|
||||
|
||||
override fun referenceSignatureId(signature: WasmSignature): WasmSymbol<Int> {
|
||||
wasmFragment.signatures.add(signature)
|
||||
return wasmFragment.signatureId.reference(signature)
|
||||
}
|
||||
|
||||
override fun getStructFieldRef(field: IrField): WasmSymbol<Int> {
|
||||
val klass = field.parentAsClass
|
||||
val metadata = getClassMetadata(klass.symbol)
|
||||
val fieldId = metadata.fields.indexOf(field)
|
||||
return WasmSymbol(fieldId)
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.ir2wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
|
||||
class WasmModuleFragmentGenerator(
|
||||
backendContext: WasmBackendContext,
|
||||
wasmModuleFragment: WasmCompiledModuleFragment
|
||||
) {
|
||||
private val declarationGenerator =
|
||||
DeclarationGenerator(
|
||||
WasmModuleCodegenContextImpl(
|
||||
backendContext,
|
||||
wasmModuleFragment
|
||||
)
|
||||
)
|
||||
|
||||
fun generateModule(irModuleFragment: IrModuleFragment) {
|
||||
for (irFile in irModuleFragment.files) {
|
||||
generatePackageFragment(irFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun generatePackageFragment(irPackageFragment: IrPackageFragment) {
|
||||
for (irDeclaration in irPackageFragment.declarations) {
|
||||
generateDeclaration(irDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateDeclaration(irDeclaration: IrDeclaration) {
|
||||
irDeclaration.acceptVoid(declarationGenerator)
|
||||
}
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.AbstractBlockDecomposerLowering
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
|
||||
class WasmBlockDecomposerLowering(val context: WasmBackendContext) : AbstractBlockDecomposerLowering(context) {
|
||||
override fun unreachableExpression(): IrExpression = TODO()
|
||||
}
|
||||
+110
-11
@@ -6,40 +6,139 @@
|
||||
package org.jetbrains.kotlin.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isEqualsInheritedFromAny
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irComposite
|
||||
import org.jetbrains.kotlin.ir.builders.irInt
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.irCall
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.util.isFunction
|
||||
import org.jetbrains.kotlin.ir.util.isNullConst
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||
private val irBuiltins = context.irBuiltIns
|
||||
private val symbols = context.wasmSymbols
|
||||
|
||||
fun transformCall(call: IrCall): IrExpression {
|
||||
private fun IrType.findEqualsMethod(): IrSimpleFunction {
|
||||
val klass = getClass() ?: irBuiltins.anyClass.owner
|
||||
return klass.functions.single { it.isEqualsInheritedFromAny() }
|
||||
}
|
||||
|
||||
fun transformCall(
|
||||
call: IrCall,
|
||||
builder: DeclarationIrBuilder
|
||||
): IrExpression {
|
||||
when (val symbol = call.symbol) {
|
||||
irBuiltins.eqeqSymbol, irBuiltins.eqeqeqSymbol, in irBuiltins.ieee754equalsFunByOperandType.values -> {
|
||||
irBuiltins.ieee754equalsFunByOperandType[irBuiltins.floatClass] -> {
|
||||
if (call.getValueArgument(0)!!.type.isNullable() || call.getValueArgument(1)!!.type.isNullable()) {
|
||||
return irCall(call, symbols.nullableFloatIeee754Equals)
|
||||
}
|
||||
return irCall(call, symbols.floatEqualityFunctions.getValue(irBuiltins.floatType))
|
||||
}
|
||||
irBuiltins.ieee754equalsFunByOperandType[irBuiltins.doubleClass] -> {
|
||||
if (call.getValueArgument(0)!!.type.isNullable() || call.getValueArgument(1)!!.type.isNullable()) {
|
||||
return irCall(call, symbols.nullableDoubleIeee754Equals)
|
||||
}
|
||||
return irCall(call, symbols.floatEqualityFunctions.getValue(irBuiltins.doubleType))
|
||||
}
|
||||
irBuiltins.eqeqSymbol -> {
|
||||
val lhs = call.getValueArgument(0)!!
|
||||
val rhs = call.getValueArgument(1)!!
|
||||
val lhsType = lhs.type
|
||||
val rhsType = rhs.type
|
||||
if (lhsType == rhsType) {
|
||||
val newSymbol = symbols.equalityFunctions[lhsType]
|
||||
if (newSymbol != null) {
|
||||
return irCall(call, newSymbol)
|
||||
}
|
||||
}
|
||||
if (lhs.isNullConst()) {
|
||||
return builder.irCall(symbols.refIsNull).apply { putValueArgument(0, rhs) }
|
||||
}
|
||||
if (rhs.isNullConst()) {
|
||||
return builder.irCall(symbols.refIsNull).apply { putValueArgument(0, lhs) }
|
||||
}
|
||||
if (!lhsType.isNullable()) {
|
||||
return irCall(call, lhsType.findEqualsMethod().symbol, argumentsAsReceivers = true)
|
||||
}
|
||||
return irCall(call, symbols.nullableEquals)
|
||||
}
|
||||
|
||||
irBuiltins.eqeqeqSymbol -> {
|
||||
val type = call.getValueArgument(0)!!.type
|
||||
val newSymbol = symbols.equalityFunctions[type]
|
||||
?: error("Unsupported equality operator with type: ${type.render()}")
|
||||
val newSymbol = symbols.equalityFunctions[type] ?: symbols.floatEqualityFunctions[type] ?: symbols.refEq
|
||||
return irCall(call, newSymbol)
|
||||
}
|
||||
in symbols.irBuiltInsToWasmIntrinsics.keys -> {
|
||||
val newSymbol = symbols.irBuiltInsToWasmIntrinsics[symbol]!!
|
||||
|
||||
irBuiltins.checkNotNullSymbol -> {
|
||||
return irCall(call, symbols.ensureNotNull).also {
|
||||
it.putTypeArgument(0, call.type)
|
||||
}
|
||||
}
|
||||
in symbols.comparisonBuiltInsToWasmIntrinsics.keys -> {
|
||||
val newSymbol = symbols.comparisonBuiltInsToWasmIntrinsics[symbol]!!
|
||||
return irCall(call, newSymbol)
|
||||
}
|
||||
|
||||
// TODO: Implement
|
||||
irBuiltins.noWhenBranchMatchedExceptionSymbol ->
|
||||
return builder.irCall(symbols.wasmUnreachable, irBuiltins.nothingType)
|
||||
|
||||
// TODO: Implement
|
||||
irBuiltins.illegalArgumentExceptionSymbol ->
|
||||
return builder.irCall(symbols.wasmUnreachable, irBuiltins.nothingType)
|
||||
|
||||
irBuiltins.dataClassArrayMemberHashCodeSymbol -> {
|
||||
// TODO: Implement
|
||||
return builder.irComposite {
|
||||
+call.getValueArgument(0)!!
|
||||
+irInt(7777)
|
||||
}
|
||||
}
|
||||
irBuiltins.dataClassArrayMemberToStringSymbol -> {
|
||||
// TODO: Implement
|
||||
return builder.irCall(symbols.anyNtoString).apply {
|
||||
putValueArgument(0, call.getValueArgument(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val nativeInvokeArity = getKotlinFunctionInvokeArity(call)
|
||||
if (nativeInvokeArity != null) {
|
||||
return irCall(call, symbols.functionNInvokeMethods[nativeInvokeArity])
|
||||
}
|
||||
|
||||
return call
|
||||
}
|
||||
|
||||
private fun getKotlinFunctionInvokeArity(call: IrCall): Int? {
|
||||
val simpleFunction = call.symbol.owner as? IrSimpleFunction ?: return null
|
||||
val receiverType = simpleFunction.dispatchReceiverParameter?.type ?: return null
|
||||
if (simpleFunction.isSuspend) return null
|
||||
if (simpleFunction.name == OperatorNameConventions.INVOKE && receiverType.isFunction()) {
|
||||
return simpleFunction.valueParameters.size
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
val builder = context.createIrBuilder(irFile.symbol)
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val newExpression = transformCall(expression)
|
||||
val newExpression = transformCall(expression, builder)
|
||||
newExpression.transformChildrenVoid(this)
|
||||
return newExpression
|
||||
}
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irImplicitCast
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
* This lowering erases dispatch receiver types of virtual functions down to Any.
|
||||
*
|
||||
* WebAssembly function types are contravariant on their parameter types.
|
||||
* But since child classes are not supertypes of parents, in order for virtual method
|
||||
* reference to share the same v-table slot as parent's method, it's dispatch receiver type
|
||||
* has to be erased at least down to type of the parent class.
|
||||
*
|
||||
* Current implementation is rather conservative:
|
||||
* - Always erases parameter type down to Any
|
||||
* - Inserts casts back to original type in every usage of dispatch receiver.
|
||||
*
|
||||
* Possible optimisations:
|
||||
* - Instead of erasing type to Any, erase type down to least concrete supertype containing virtual method
|
||||
* - Don't erase type at all if bridge will be needed anyway
|
||||
* Cast receiver in bridge. This would keep precise type for direct calls
|
||||
* - Cast `this` and assign it to local variable if dispatch receiver is used often
|
||||
* - Don't cast if usages of `this` don't require precise type
|
||||
* - Always use bridge + Wasm tail call
|
||||
*
|
||||
* Related issue: [https://github.com/WebAssembly/gc/issues/29]
|
||||
*/
|
||||
class EraseVirtualDispatchReceiverParametersTypes(val context: CommonBackendContext) : FileLoweringPass {
|
||||
override fun lower(file: IrFile) {
|
||||
file.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
lower(declaration)
|
||||
super.visitFunction(declaration)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun lower(irFunction: IrFunction) {
|
||||
// Lower only functions that override other functions
|
||||
if (irFunction !is IrSimpleFunction) return
|
||||
if (!irFunction.isOverridableOrOverrides) return
|
||||
|
||||
val oldReceiver = irFunction.dispatchReceiverParameter!!
|
||||
val originalReceiverType = oldReceiver.type
|
||||
|
||||
// Interfaces in Wasm are erased to Any, so they already have appropriate type
|
||||
if (originalReceiverType.isInterface() || originalReceiverType.isAny()) return
|
||||
|
||||
val builder = context.createIrBuilder(irFunction.symbol)
|
||||
val newReceiver = oldReceiver.copyTo(irFunction, type = context.irBuiltIns.anyType)
|
||||
irFunction.dispatchReceiverParameter = newReceiver
|
||||
|
||||
// Cast receiver usages back to original type
|
||||
irFunction.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
if (expression.symbol == oldReceiver.symbol) {
|
||||
return with(builder) {
|
||||
irImplicitCast(irGet(newReceiver), originalReceiverType)
|
||||
}
|
||||
}
|
||||
return expression
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+12
-91
@@ -8,102 +8,22 @@ package org.jetbrains.kotlin.backend.wasm.lower
|
||||
import org.jetbrains.kotlin.backend.common.ir.addChild
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.utils.hasExcludedFromCodegenAnnotation
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
private val BODILESS_BUILTIN_CLASSES = listOf(
|
||||
"kotlin.Nothing",
|
||||
"kotlin.Array",
|
||||
"kotlin.Any",
|
||||
"kotlin.ByteArray",
|
||||
"kotlin.CharArray",
|
||||
"kotlin.ShortArray",
|
||||
"kotlin.IntArray",
|
||||
"kotlin.LongArray",
|
||||
"kotlin.FloatArray",
|
||||
"kotlin.DoubleArray",
|
||||
"kotlin.BooleanArray",
|
||||
"kotlin.Boolean",
|
||||
"kotlin.Function",
|
||||
"kotlin.Throwable",
|
||||
"kotlin.Suppress",
|
||||
"kotlin.SinceKotlin",
|
||||
"kotlin.Deprecated",
|
||||
"kotlin.ReplaceWith",
|
||||
"kotlin.DeprecationLevel",
|
||||
"kotlin.UnsafeVariance",
|
||||
"kotlin.reflect.KType",
|
||||
"kotlin.reflect.KTypeProjection",
|
||||
"kotlin.reflect.Companion",
|
||||
"kotlin.reflect.KTypeParameter",
|
||||
"kotlin.reflect.KDeclarationContainer",
|
||||
"kotlin.reflect.KProperty",
|
||||
"kotlin.reflect.KProperty0",
|
||||
"kotlin.reflect.KProperty1",
|
||||
"kotlin.reflect.KProperty2",
|
||||
"kotlin.reflect.KMutableProperty0",
|
||||
"kotlin.reflect.KMutableProperty",
|
||||
"kotlin.reflect.KMutableProperty1",
|
||||
"kotlin.reflect.KMutableProperty2",
|
||||
"kotlin.reflect.Accessor",
|
||||
"kotlin.reflect.Getter",
|
||||
"kotlin.reflect.KFunction",
|
||||
"kotlin.reflect.KVariance",
|
||||
"kotlin.reflect.KVisibility",
|
||||
"kotlin.reflect.KClass",
|
||||
"kotlin.reflect.KCallable",
|
||||
"kotlin.reflect.KClassifier",
|
||||
"kotlin.reflect.KParameter",
|
||||
"kotlin.reflect.Kind",
|
||||
"kotlin.reflect.KAnnotatedElement",
|
||||
"kotlin.annotation.Target",
|
||||
"kotlin.annotation.AnnotationTarget",
|
||||
"kotlin.annotation.Retention",
|
||||
"kotlin.annotation.AnnotationRetention",
|
||||
"kotlin.annotation.MustBeDocumented",
|
||||
"kotlin.Unit",
|
||||
"kotlin.collections.BooleanIterator",
|
||||
"kotlin.collections.CharIterator",
|
||||
"kotlin.collections.ByteIterator",
|
||||
"kotlin.collections.ShortIterator",
|
||||
"kotlin.collections.IntIterator",
|
||||
"kotlin.collections.FloatIterator",
|
||||
"kotlin.collections.LongIterator",
|
||||
"kotlin.collections.DoubleIterator",
|
||||
"kotlin.internal.PlatformDependent",
|
||||
"kotlin.CharSequence",
|
||||
"kotlin.Annotation",
|
||||
"kotlin.Comparable",
|
||||
"kotlin.collections.Collection",
|
||||
"kotlin.collections.Iterable",
|
||||
"kotlin.collections.List",
|
||||
"kotlin.collections.Map",
|
||||
"kotlin.collections.Set",
|
||||
"kotlin.collections.MutableCollection",
|
||||
"kotlin.collections.MutableIterable",
|
||||
"kotlin.collections.MutableSet",
|
||||
"kotlin.collections.MutableList",
|
||||
"kotlin.collections.MutableMap",
|
||||
"kotlin.collections.Entry",
|
||||
"kotlin.collections.MutableEntry",
|
||||
"kotlin.Number",
|
||||
"kotlin.Enum",
|
||||
"kotlin.collections.Iterator",
|
||||
"kotlin.collections.ListIterator",
|
||||
"kotlin.collections.MutableIterator",
|
||||
"kotlin.collections.MutableListIterator"
|
||||
).map { FqName(it) }.toSet()
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
|
||||
/**
|
||||
* Move intrinsics marked with @ExcludedFromCodegen to special excluded files.
|
||||
* All references to these declarations must be lowered or treated in a special way in a codegen.
|
||||
*/
|
||||
fun excludeDeclarationsFromCodegen(context: WasmBackendContext, module: IrModuleFragment) {
|
||||
|
||||
fun isExcluded(declaration: IrDeclaration): Boolean {
|
||||
if (declaration is IrDeclarationWithName && declaration.fqNameWhenAvailable in BODILESS_BUILTIN_CLASSES)
|
||||
return true
|
||||
|
||||
// Annotation can be applied to top-level declarations ...
|
||||
if (declaration.hasExcludedFromCodegenAnnotation())
|
||||
return true
|
||||
|
||||
// ... or files as a whole
|
||||
val parentFile = declaration.parent as? IrFile
|
||||
if (parentFile?.hasExcludedFromCodegenAnnotation() == true)
|
||||
return true
|
||||
@@ -117,7 +37,8 @@ fun excludeDeclarationsFromCodegen(context: WasmBackendContext, module: IrModule
|
||||
val d = it.next() as? IrDeclarationWithName ?: continue
|
||||
if (isExcluded(d)) {
|
||||
it.remove()
|
||||
context.excludedDeclarations.addChild(d)
|
||||
// Move to "excluded" package fragment preserving fq-name
|
||||
context.getExcludedPackageFragment(file.fqName).addChild(d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.irSetField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
/**
|
||||
* Move initialization of global fields to start function.
|
||||
*
|
||||
* WebAssembly allows only constant expressions to be used directly in
|
||||
* field initializers.
|
||||
*
|
||||
* TODO: Don't move constant expression initializers
|
||||
* TODO: Make field initialization lazy. Needs design.
|
||||
*/
|
||||
class FieldInitializersLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
val builder = context.createIrBuilder(context.startFunction.symbol)
|
||||
val startFunctionBody = context.startFunction.body as IrBlockBody
|
||||
|
||||
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) {
|
||||
super.visitField(declaration)
|
||||
if (!declaration.isStatic) return
|
||||
val initValue: IrExpression = declaration.initializer?.expression ?: return
|
||||
|
||||
startFunctionBody.statements.add(
|
||||
builder.at(initValue).irSetField(null, declaration, initValue)
|
||||
)
|
||||
// Replace initializer with default one
|
||||
declaration.initializer = null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irComposite
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.erasedUpperBound
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.builders.irImplicitCast
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.irCall
|
||||
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
* This lowering adds implicit casts in places where erased generic function return type
|
||||
* differs from expected type on the call site.
|
||||
*/
|
||||
class GenericReturnTypeLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun visitCall(expression: IrCall): IrExpression =
|
||||
transformGenericCall(
|
||||
super.visitCall(expression) as IrCall,
|
||||
currentScope!!.scope.scopeOwnerSymbol
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
private fun IrType.eraseUpperBoundType(): IrType {
|
||||
val type = erasedUpperBound?.defaultType ?: return context.irBuiltIns.anyNType
|
||||
return if (this.isNullable())
|
||||
type.makeNullable()
|
||||
else
|
||||
type
|
||||
}
|
||||
|
||||
private fun transformGenericCall(call: IrCall, scopeOwnerSymbol: IrSymbol): IrExpression {
|
||||
val function: IrSimpleFunction =
|
||||
call.symbol.owner as? IrSimpleFunction ?: return call
|
||||
|
||||
if (!function.realOverrideTarget.returnType.isTypeParameter())
|
||||
return call
|
||||
|
||||
val erasedReturnType: IrType =
|
||||
function.realOverrideTarget.returnType.eraseUpperBoundType()
|
||||
|
||||
val callType = call.type
|
||||
|
||||
if (erasedReturnType != call.type) {
|
||||
if (callType.isNothing()) return call
|
||||
if (erasedReturnType.isSubtypeOf(callType, context.irBuiltIns)) return call
|
||||
|
||||
// Erase type parameter from call return type
|
||||
val newCall = irCall(
|
||||
call,
|
||||
function.symbol,
|
||||
newReturnType = erasedReturnType,
|
||||
newSuperQualifierSymbol = call.superQualifierSymbol
|
||||
)
|
||||
|
||||
context.createIrBuilder(scopeOwnerSymbol).apply {
|
||||
if (call.type.isUnit()) {
|
||||
return irComposite(call) {
|
||||
+newCall
|
||||
}
|
||||
}
|
||||
return irImplicitCast(newCall, call.type)
|
||||
}
|
||||
}
|
||||
return call
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irString
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.isString
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
* Replace string concatenation with a chain of String.plus calls.
|
||||
* TODO: Reuse common StringConcatenationLowering which uses string builder
|
||||
*/
|
||||
class SimpleStringConcatenationLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(StringConcatenationTransformer(this))
|
||||
}
|
||||
}
|
||||
|
||||
private class StringConcatenationTransformer(val lower: SimpleStringConcatenationLowering) : IrElementTransformerVoidWithContext() {
|
||||
private val context = lower.context
|
||||
private val irBuiltIns = context.irBuiltIns
|
||||
private val stringPlus = irBuiltIns.stringClass.owner.declarations.filterIsInstance<IrSimpleFunction>().find {
|
||||
it.name == Name.identifier("plus")
|
||||
}!!
|
||||
|
||||
private val anyToString = irBuiltIns.anyClass.owner.declarations.filterIsInstance<IrSimpleFunction>().find {
|
||||
it.name == Name.identifier("toString")
|
||||
}!!
|
||||
|
||||
private val anyNToString = context.wasmSymbols.anyNtoString
|
||||
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression {
|
||||
val transformed = super.visitStringConcatenation(expression) as IrStringConcatenation
|
||||
val builder: DeclarationIrBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).at(expression)
|
||||
return transformed.arguments.fold<IrExpression, IrExpression>(
|
||||
builder.irString("")
|
||||
) { acc, el ->
|
||||
builder.irCall(stringPlus).apply {
|
||||
dispatchReceiver = acc
|
||||
putValueArgument(0, expressionToString(el, builder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun expressionToString(expression: IrExpression, builder: DeclarationIrBuilder): IrExpression {
|
||||
if (expression.type.isString()) return expression
|
||||
builder.at(expression)
|
||||
val klass = expression.type.getClass()
|
||||
|
||||
if (expression.type.isNullable()) {
|
||||
return builder.irCall(anyNToString).apply {
|
||||
putValueArgument(0, expression)
|
||||
}
|
||||
}
|
||||
|
||||
val toStringMethod: IrSimpleFunction = if (klass != null) {
|
||||
klass.declarations.filterIsInstance<IrSimpleFunction>().find { it.isToStringInheritedFromAny() }!!
|
||||
} else {
|
||||
anyToString
|
||||
}
|
||||
|
||||
return builder.irCall(toStringMethod).apply {
|
||||
dispatchReceiver = expression
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun IrFunction.isToStringInheritedFromAny() =
|
||||
name == Name.identifier("toString") &&
|
||||
dispatchReceiverParameter != null &&
|
||||
extensionReceiverParameter == null &&
|
||||
valueParameters.isEmpty()
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.isOverridable
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.builders.createTmpVariable
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
* During Wasm code generation, dispatch receiver can be used multiple times.
|
||||
* Move it to temporary variable if it is complex or can have side effects.
|
||||
*/
|
||||
class VirtualDispatchReceiverExtraction(val context: CommonBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
lower(declaration)
|
||||
super.visitFunction(declaration)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun lower(irFunction: IrFunction) {
|
||||
irFunction.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
val function = expression.symbol.owner.realOverrideTarget
|
||||
val receiver = expression.dispatchReceiver
|
||||
if (receiver == null || !function.isOverridable)
|
||||
return expression
|
||||
// TODO: Keep other simple receivers without side effects
|
||||
// receiver.isPure(true) ?
|
||||
if (receiver is IrGetValue)
|
||||
return expression
|
||||
return with(context.createIrBuilder(irFunction.symbol)) {
|
||||
irBlock(expression) {
|
||||
val tmp = createTmpVariable(receiver)
|
||||
expression.dispatchReceiver = irGet(tmp)
|
||||
+expression
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.erasedUpperBound
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.BridgesConstruction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class WasmBridgesConstruction(context: JsCommonBackendContext) : BridgesConstruction(context) {
|
||||
override fun getFunctionSignature(function: IrSimpleFunction): WasmSignature =
|
||||
function.wasmSignature(context.irBuiltIns)
|
||||
|
||||
// Dispatch receiver type must be casted when types are different.
|
||||
override val shouldCastDispatchReceiver: Boolean = true
|
||||
}
|
||||
|
||||
data class WasmSignature(
|
||||
val name: Name,
|
||||
val extensionReceiverType: IrType?,
|
||||
val valueParametersType: List<IrType>,
|
||||
val returnType: IrType
|
||||
) {
|
||||
override fun toString(): String {
|
||||
val er = extensionReceiverType?.let { "(er: ${it.render()}) " } ?: ""
|
||||
val parameters = valueParametersType.joinToString(", ") { it.render() }
|
||||
return "[$er$name($parameters) -> ${returnType.render()}]"
|
||||
}
|
||||
}
|
||||
|
||||
fun IrSimpleFunction.wasmSignature(irBuiltIns: IrBuiltIns): WasmSignature =
|
||||
WasmSignature(
|
||||
name,
|
||||
extensionReceiverParameter?.type?.eraseGenerics(irBuiltIns),
|
||||
valueParameters.map { it.type.eraseGenerics(irBuiltIns) },
|
||||
returnType.eraseGenerics(irBuiltIns)
|
||||
)
|
||||
|
||||
private fun IrType.eraseGenerics(irBuiltIns: IrBuiltIns): IrType {
|
||||
val defaultType = this.erasedUpperBound?.defaultType ?: irBuiltIns.anyType
|
||||
if (!this.isNullable()) return defaultType
|
||||
return defaultType.makeNullable()
|
||||
}
|
||||
|
||||
+314
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.ir.isSuspend
|
||||
import org.jetbrains.kotlin.backend.common.ir.moveBodyTo
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
|
||||
/**
|
||||
* TODO: Temporary lowering stub. Needs to be redone.
|
||||
* This is a copy of JVM lowering, but parts that don't compile are commented out.
|
||||
* Turns out this works decently as a stub in most tests.
|
||||
*/
|
||||
|
||||
val IrStatementOrigin?.isLambda: Boolean
|
||||
get() = this == IrStatementOrigin.LAMBDA || this == IrStatementOrigin.ANONYMOUS_FUNCTION
|
||||
|
||||
// Originally copied from K/Native
|
||||
internal class WasmCallableReferenceLowering(private val context: WasmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||
// This pass ignores suspend function references and function references used in inline arguments to inline functions.
|
||||
private val ignoredFunctionReferences = mutableSetOf<IrFunctionReference>()
|
||||
|
||||
private val IrFunctionReference.isIgnored: Boolean
|
||||
get() = (!type.isFunctionOrKFunction() || ignoredFunctionReferences.contains(this)) && !isSuspendCallableReference()
|
||||
|
||||
// TODO: Currently, origin of callable references is null. Do we need to create one?
|
||||
private fun IrFunctionReference.isSuspendCallableReference(): Boolean = isSuspend && origin == null
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
// ignoredFunctionReferences.addAll(IrInlineReferenceLocator.scan(context, irFile))
|
||||
irFile.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitBlock(expression: IrBlock): IrExpression {
|
||||
if (!expression.origin.isLambda)
|
||||
return super.visitBlock(expression)
|
||||
|
||||
val reference = expression.statements.last() as IrFunctionReference
|
||||
if (reference.isIgnored)
|
||||
return super.visitBlock(expression)
|
||||
|
||||
expression.statements.dropLast(1).forEach { it.transform(this, null) }
|
||||
reference.transformChildrenVoid(this)
|
||||
return FunctionReferenceBuilder(reference).build()
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
return if (expression.isIgnored) expression else FunctionReferenceBuilder(expression).build()
|
||||
}
|
||||
|
||||
// Handle SAM conversions which wrap a function reference:
|
||||
// class sam$n(private val receiver: R) : Interface { override fun method(...) = receiver.target(...) }
|
||||
//
|
||||
// This avoids materializing an invokable KFunction representing, thus producing one less class.
|
||||
// This is actually very common, as `Interface { something }` is a local function + a SAM-conversion
|
||||
// of a reference to it into an implementation.
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
||||
if (expression.operator == IrTypeOperator.SAM_CONVERSION) {
|
||||
val invokable = expression.argument
|
||||
val reference = if (invokable is IrFunctionReference) {
|
||||
invokable
|
||||
} else if (invokable is IrBlock && invokable.origin.isLambda && invokable.statements.last() is IrFunctionReference) {
|
||||
invokable.statements.dropLast(1).forEach { it.transform(this, null) }
|
||||
invokable.statements.last() as IrFunctionReference
|
||||
} else {
|
||||
return super.visitTypeOperator(expression)
|
||||
}
|
||||
reference.transformChildrenVoid()
|
||||
return FunctionReferenceBuilder(reference, expression.typeOperand).build()
|
||||
}
|
||||
return super.visitTypeOperator(expression)
|
||||
}
|
||||
|
||||
private inner class FunctionReferenceBuilder(val irFunctionReference: IrFunctionReference, val samSuperType: IrType? = null) {
|
||||
private val isLambda = irFunctionReference.origin.isLambda
|
||||
|
||||
private val callee = irFunctionReference.symbol.owner
|
||||
|
||||
// Only function references can bind a receiver and even then we can only bind either an extension or a dispatch receiver.
|
||||
// However, when we bind a value of an inline class type as a receiver, the receiver will turn into an argument of
|
||||
// the function in question. Yet we still need to record it as the "receiver" in CallableReference in order for reflection
|
||||
// to work correctly.
|
||||
private val boundReceiver: Pair<IrValueParameter, IrExpression>? = irFunctionReference.getArgumentsWithIr().singleOrNull()
|
||||
|
||||
// The type of the reference is KFunction<in A1, ..., in An, out R>
|
||||
private val parameterTypes = (irFunctionReference.type as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
|
||||
private val argumentTypes = parameterTypes.dropLast(1)
|
||||
|
||||
private val typeArgumentsMap = irFunctionReference.typeSubstitutionMap
|
||||
|
||||
private val functionSuperClass =
|
||||
samSuperType?.classOrNull
|
||||
?: if (irFunctionReference.isSuspend)
|
||||
context.ir.symbols.suspendFunctionN(argumentTypes.size)
|
||||
else
|
||||
context.ir.symbols.functionN(argumentTypes.size)
|
||||
|
||||
private val superMethod =
|
||||
functionSuperClass.functions.single { it.owner.modality == Modality.ABSTRACT }
|
||||
// TODO(WASM)
|
||||
// private val superType =
|
||||
// samSuperType ?: (if (isLambda) context.ir.symbols.lambdaClass else context.ir.symbols.functionReference).defaultType
|
||||
|
||||
private val functionReferenceClass = context.irFactory.buildClass {
|
||||
setSourceRange(irFunctionReference)
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
// A callable reference results in a synthetic class, while a lambda is not synthetic.
|
||||
// We don't produce GENERATED_SAM_IMPLEMENTATION, which is always synthetic.
|
||||
// TODO(WASM)
|
||||
// origin = if (isLambda) JvmLoweredDeclarationOrigin.LAMBDA_IMPL else JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
||||
name = SpecialNames.NO_NAME_PROVIDED
|
||||
}.apply {
|
||||
parent = currentDeclarationParent!!
|
||||
// TODO(WASM)
|
||||
// superTypes += superType
|
||||
if (samSuperType == null)
|
||||
superTypes += functionSuperClass.typeWith(parameterTypes)
|
||||
// TODO(WASM)
|
||||
// if (irFunctionReference.isSuspend) superTypes += context.ir.symbols.suspendFunctionInterface.defaultType
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
copyAttributes(irFunctionReference)
|
||||
if (isLambda) {
|
||||
this.metadata = irFunctionReference.symbol.owner.metadata
|
||||
}
|
||||
}
|
||||
|
||||
// WASM(TODO)
|
||||
// private val receiverFieldFromSuper = context.ir.symbols.functionReferenceReceiverField.owner
|
||||
//
|
||||
// val fakeOverrideReceiverField = functionReferenceClass.addField {
|
||||
// name = receiverFieldFromSuper.name
|
||||
// origin = IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
// type = receiverFieldFromSuper.type
|
||||
// isFinal = receiverFieldFromSuper.isFinal
|
||||
// isStatic = receiverFieldFromSuper.isStatic
|
||||
// visibility = receiverFieldFromSuper.visibility
|
||||
// }
|
||||
|
||||
fun build(): IrExpression = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run {
|
||||
irBlock {
|
||||
val constructor = createConstructor()
|
||||
createInvokeMethod(
|
||||
if (samSuperType != null && boundReceiver != null) {
|
||||
irTemporary(boundReceiver.second)
|
||||
} else null
|
||||
)
|
||||
|
||||
// WASM(TODO)
|
||||
// if (!isLambda && samSuperType == null) {
|
||||
// createGetSignatureMethod(this@run.irSymbols.functionReferenceGetSignature.owner)
|
||||
// createGetNameMethod(this@run.irSymbols.functionReferenceGetName.owner)
|
||||
// createGetOwnerMethod(this@run.irSymbols.functionReferenceGetOwner.owner)
|
||||
// }
|
||||
|
||||
+functionReferenceClass
|
||||
+irCall(constructor.symbol).apply {
|
||||
if (valueArgumentsCount > 0) putValueArgument(0, boundReceiver!!.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createConstructor(): IrConstructor =
|
||||
functionReferenceClass.addConstructor {
|
||||
// origin = JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE
|
||||
returnType = functionReferenceClass.defaultType
|
||||
isPrimary = true
|
||||
}.apply {
|
||||
// Add receiver parameter for bound function references
|
||||
if (samSuperType == null) {
|
||||
boundReceiver?.first?.let { param ->
|
||||
valueParameters += param.copyTo(
|
||||
irFunction = this,
|
||||
index = 0,
|
||||
type = param.type.substitute(typeArgumentsMap)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Super constructor:
|
||||
// - For SAM references, the super class is Any
|
||||
// - For function references with bound receivers, accepts arity and receiver
|
||||
// - For lambdas and function references without bound receivers, accepts arity
|
||||
|
||||
// WASM_TODO
|
||||
// val constructor = if (samSuperType != null) {
|
||||
// context.irBuiltIns.anyClass.owner.constructors.single()
|
||||
// } else {
|
||||
// superType.getClass()!!.constructors.single {
|
||||
// it.valueParameters.size == if (boundReceiver != null) 2 else 1
|
||||
// }
|
||||
// }
|
||||
|
||||
val constructor = context.irBuiltIns.anyClass.owner.constructors.single()
|
||||
|
||||
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
||||
+irDelegatingConstructorCall(constructor).apply {
|
||||
// WASM_TODO
|
||||
// if (samSuperType == null) {
|
||||
// putValueArgument(0, irInt(argumentTypes.size + if (irFunctionReference.isSuspend) 1 else 0))
|
||||
// if (boundReceiver != null)
|
||||
// putValueArgument(1, irGet(valueParameters.first()))
|
||||
// }
|
||||
}
|
||||
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, context.irBuiltIns.unitType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createInvokeMethod(receiverVar: IrValueDeclaration?): IrSimpleFunction =
|
||||
functionReferenceClass.addFunction {
|
||||
setSourceRange(if (isLambda) callee else irFunctionReference)
|
||||
name = superMethod.owner.name
|
||||
returnType = callee.returnType
|
||||
isSuspend = callee.isSuspend
|
||||
}.apply {
|
||||
overriddenSymbols += superMethod
|
||||
dispatchReceiverParameter = parentAsClass.thisReceiver!!.copyTo(this)
|
||||
if (isLambda) createLambdaInvokeMethod() else createFunctionReferenceInvokeMethod(receiverVar)
|
||||
}
|
||||
|
||||
// Inline the body of an anonymous function into the generated lambda subclass.
|
||||
private fun IrSimpleFunction.createLambdaInvokeMethod() {
|
||||
annotations += callee.annotations
|
||||
val valueParameterMap = callee.explicitParameters.withIndex().associate { (index, param) ->
|
||||
param to param.copyTo(this, index = index)
|
||||
}
|
||||
valueParameters += valueParameterMap.values
|
||||
body = callee.moveBodyTo(this, valueParameterMap)
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.createFunctionReferenceInvokeMethod(receiver: IrValueDeclaration?) {
|
||||
for ((index, argumentType) in argumentTypes.withIndex()) {
|
||||
addValueParameter {
|
||||
name = Name.identifier("p$index")
|
||||
type = argumentType
|
||||
}
|
||||
}
|
||||
|
||||
body = context.createIrBuilder(symbol).run {
|
||||
var unboundIndex = 0
|
||||
irExprBody(irCall(callee).apply {
|
||||
for ((typeParameter, typeArgument) in typeArgumentsMap) {
|
||||
putTypeArgument(typeParameter.owner.index, typeArgument)
|
||||
}
|
||||
|
||||
for (parameter in callee.explicitParameters) {
|
||||
when {
|
||||
boundReceiver?.first == parameter ->
|
||||
// Bound receiver parameter. For function references, this is stored in a field of the superclass.
|
||||
// For sam references, we just capture the value in a local variable and LocalDeclarationsLowering
|
||||
// will put it into a field.
|
||||
// if (samSuperType == null)
|
||||
// irImplicitCast(
|
||||
// irGetField(irGet(dispatchReceiverParameter!!), fakeOverrideReceiverField),
|
||||
// boundReceiver.second.type
|
||||
// )
|
||||
// else
|
||||
irGet(receiver ?: error("Binding receivers is not supported yet"))
|
||||
|
||||
// If a vararg parameter corresponds to exactly one KFunction argument, which is an array, that array
|
||||
// is forwarded as is.
|
||||
//
|
||||
// fun f(x: (Int, Array<String>) -> String) = x(0, arrayOf("OK", "FAIL"))
|
||||
// fun h(i: Int, vararg xs: String) = xs[i]
|
||||
// f(::h)
|
||||
//
|
||||
parameter.isVararg && unboundIndex < argumentTypes.size && parameter.type == valueParameters[unboundIndex].type ->
|
||||
irGet(valueParameters[unboundIndex++])
|
||||
// In all other cases, excess arguments are packed into a new array.
|
||||
//
|
||||
// fun g(x: (Int, String, String) -> String) = x(0, "OK", "FAIL")
|
||||
// f(::h) == g(::h)
|
||||
//
|
||||
parameter.isVararg && (unboundIndex < argumentTypes.size || !parameter.hasDefaultValue()) ->
|
||||
TODO()
|
||||
|
||||
unboundIndex >= argumentTypes.size ->
|
||||
// Default value argument (this pass doesn't handle suspend functions, otherwise
|
||||
// it could also be the continuation argument)
|
||||
null
|
||||
|
||||
else ->
|
||||
irGet(valueParameters[unboundIndex++])
|
||||
}?.let { putArgument(callee, parameter, it) }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.AbstractValueUsageLowering
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
|
||||
/**
|
||||
* Replace null constants of type Nothing? with null constants of a concrete class types.
|
||||
*
|
||||
* Wasm GC doesn't have a nullref type anymore.
|
||||
*/
|
||||
class WasmNullCoercingLowering(context: JsCommonBackendContext) : AbstractValueUsageLowering(context) {
|
||||
override fun IrExpression.useExpressionAsType(actualType: IrType, expectedType: IrType): IrExpression =
|
||||
if (actualType.makeNotNull().isNothing() && actualType.isNullable() && !expectedType.makeNotNull().isNothing())
|
||||
JsIrBuilder.buildComposite(
|
||||
type,
|
||||
listOf(this, IrConstImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, expectedType, IrConstKind.Null, null))
|
||||
)
|
||||
else
|
||||
this
|
||||
}
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
|
||||
import org.jetbrains.kotlin.backend.common.lower.InnerClassesSupport
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
* This is a copy of an old version of JS lowering, because JS did platform-specific optimization incompatible with Wasm.
|
||||
* TODO: Revisit
|
||||
*/
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class WasmSharedVariablesManager(val context: JsCommonBackendContext, val builtIns: IrBuiltIns, val implicitDeclarationsFile: IrPackageFragment) : SharedVariablesManager {
|
||||
override fun declareSharedVariable(originalDeclaration: IrVariable): IrVariable {
|
||||
val initializer = originalDeclaration.initializer ?: IrConstImpl.constNull(
|
||||
originalDeclaration.startOffset,
|
||||
originalDeclaration.endOffset,
|
||||
builtIns.nothingNType
|
||||
)
|
||||
|
||||
val constructorSymbol = closureBoxConstructorDeclaration.symbol
|
||||
|
||||
val irCall =
|
||||
IrConstructorCallImpl.fromSymbolDescriptor(initializer.startOffset, initializer.endOffset, closureBoxType, constructorSymbol)
|
||||
.apply {
|
||||
putValueArgument(0, initializer)
|
||||
}
|
||||
|
||||
val descriptor = WrappedVariableDescriptor()
|
||||
return IrVariableImpl(
|
||||
originalDeclaration.startOffset,
|
||||
originalDeclaration.endOffset,
|
||||
originalDeclaration.origin,
|
||||
IrVariableSymbolImpl(descriptor),
|
||||
originalDeclaration.name,
|
||||
irCall.type,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
it.parent = originalDeclaration.parent
|
||||
it.initializer = irCall
|
||||
}
|
||||
}
|
||||
|
||||
override fun defineSharedValue(originalDeclaration: IrVariable, sharedVariableDeclaration: IrVariable) = sharedVariableDeclaration
|
||||
|
||||
override fun getSharedValue(sharedVariableSymbol: IrVariableSymbol, originalGet: IrGetValue): IrExpression {
|
||||
val getField = IrGetFieldImpl(
|
||||
originalGet.startOffset, originalGet.endOffset,
|
||||
closureBoxFieldDeclaration.symbol,
|
||||
closureBoxFieldDeclaration.type,
|
||||
IrGetValueImpl(
|
||||
originalGet.startOffset,
|
||||
originalGet.endOffset,
|
||||
closureBoxType,
|
||||
sharedVariableSymbol,
|
||||
originalGet.origin
|
||||
),
|
||||
originalGet.origin
|
||||
)
|
||||
|
||||
return IrTypeOperatorCallImpl(
|
||||
originalGet.startOffset,
|
||||
originalGet.endOffset,
|
||||
originalGet.type,
|
||||
IrTypeOperator.IMPLICIT_CAST,
|
||||
originalGet.type,
|
||||
getField
|
||||
)
|
||||
}
|
||||
|
||||
override fun setSharedValue(sharedVariableSymbol: IrVariableSymbol, originalSet: IrSetValue): IrExpression =
|
||||
IrSetFieldImpl(
|
||||
originalSet.startOffset,
|
||||
originalSet.endOffset,
|
||||
closureBoxFieldDeclaration.symbol,
|
||||
IrGetValueImpl(
|
||||
originalSet.startOffset,
|
||||
originalSet.endOffset,
|
||||
closureBoxType,
|
||||
sharedVariableSymbol,
|
||||
originalSet.origin
|
||||
),
|
||||
originalSet.value,
|
||||
originalSet.type,
|
||||
originalSet.origin
|
||||
)
|
||||
|
||||
private val boxTypeName = "\$closureBox\$"
|
||||
|
||||
private val closureBoxClassDeclaration by lazy {
|
||||
createClosureBoxClassDeclaration()
|
||||
}
|
||||
|
||||
private val closureBoxConstructorDeclaration by lazy {
|
||||
createClosureBoxConstructorDeclaration()
|
||||
}
|
||||
|
||||
private val closureBoxFieldDeclaration by lazy {
|
||||
closureBoxPropertyDeclaration
|
||||
}
|
||||
|
||||
private val closureBoxPropertyDeclaration by lazy {
|
||||
createClosureBoxPropertyDeclaration()
|
||||
}
|
||||
|
||||
private lateinit var closureBoxType: IrType
|
||||
|
||||
private fun createClosureBoxClassDeclaration(): IrClass {
|
||||
val declaration = context.irFactory.buildClass {
|
||||
origin = JsLoweredDeclarationOrigin.JS_CLOSURE_BOX_CLASS_DECLARATION
|
||||
name = Name.identifier(boxTypeName)
|
||||
visibility = DescriptorVisibilities.PUBLIC
|
||||
modality = Modality.FINAL
|
||||
isCompanion = false
|
||||
isInner = false
|
||||
isData = false
|
||||
isExternal = false
|
||||
isInline = false
|
||||
isExpect = false
|
||||
isFun = false
|
||||
}
|
||||
|
||||
declaration.parent = implicitDeclarationsFile
|
||||
// TODO: substitute
|
||||
closureBoxType = IrSimpleTypeImpl(declaration.symbol, false, emptyList(), emptyList())
|
||||
declaration.thisReceiver = buildValueParameter(declaration) {
|
||||
name = Name.identifier("_this_")
|
||||
index = -1
|
||||
type = closureBoxType
|
||||
}
|
||||
implicitDeclarationsFile.declarations += declaration
|
||||
|
||||
return declaration
|
||||
}
|
||||
|
||||
private fun createClosureBoxPropertyDeclaration(): IrField {
|
||||
val descriptor = WrappedFieldDescriptor()
|
||||
val symbol = IrFieldSymbolImpl(descriptor)
|
||||
val fieldName = Name.identifier("v")
|
||||
return context.irFactory.createField(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
InnerClassesSupport.FIELD_FOR_OUTER_THIS,
|
||||
symbol,
|
||||
fieldName,
|
||||
builtIns.anyNType,
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
isFinal = false,
|
||||
isExternal = false,
|
||||
isStatic = false,
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
it.parent = closureBoxClassDeclaration
|
||||
closureBoxClassDeclaration.declarations += it
|
||||
}
|
||||
}
|
||||
|
||||
private fun createClosureBoxConstructorDeclaration(): IrConstructor {
|
||||
val descriptor = WrappedClassConstructorDescriptor()
|
||||
val symbol = IrConstructorSymbolImpl(descriptor)
|
||||
|
||||
val declaration = context.irFactory.createConstructor(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, JsLoweredDeclarationOrigin.JS_CLOSURE_BOX_CLASS_DECLARATION, symbol,
|
||||
Name.special("<init>"), DescriptorVisibilities.PUBLIC, closureBoxClassDeclaration.defaultType,
|
||||
isInline = false, isExternal = false, isPrimary = true, isExpect = false
|
||||
)
|
||||
|
||||
descriptor.bind(declaration)
|
||||
declaration.parent = closureBoxClassDeclaration
|
||||
|
||||
val parameterDeclaration = createClosureBoxConstructorParameterDeclaration(declaration)
|
||||
|
||||
declaration.valueParameters += parameterDeclaration
|
||||
|
||||
val receiver = JsIrBuilder.buildGetValue(closureBoxClassDeclaration.thisReceiver!!.symbol)
|
||||
val value = JsIrBuilder.buildGetValue(parameterDeclaration.symbol)
|
||||
|
||||
val setField = JsIrBuilder.buildSetField(closureBoxFieldDeclaration.symbol, receiver, value, builtIns.unitType)
|
||||
|
||||
declaration.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(setField))
|
||||
|
||||
closureBoxClassDeclaration.declarations += declaration
|
||||
return declaration
|
||||
}
|
||||
|
||||
private fun createClosureBoxConstructorParameterDeclaration(irConstructor: IrConstructor): IrValueParameter {
|
||||
return JsIrBuilder.buildValueParameter(irConstructor,"p", 0, closureBoxPropertyDeclaration.type)
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrThrow
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
* Replace throw expressions with a runtime function call.
|
||||
* TODO: Remove when full-blown exception handling is implemented
|
||||
*/
|
||||
internal class WasmThrowDebugLowering(
|
||||
private val context: WasmBackendContext
|
||||
) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitThrow(expression: IrThrow): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
val builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol)
|
||||
|
||||
return builder.irCall(context.wasmSymbols.wasmThrow).apply {
|
||||
this.putValueArgument(0, expression.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irNot
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.erasedUpperBound
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isPure
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
|
||||
class WasmTypeOperatorLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(WasmBaseTypeOperatorTransformer(context))
|
||||
}
|
||||
}
|
||||
|
||||
class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrElementTransformerVoidWithContext() {
|
||||
private val symbols = context.wasmSymbols
|
||||
private val builtIns = context.irBuiltIns
|
||||
|
||||
private lateinit var builder: DeclarationIrBuilder
|
||||
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
||||
super.visitTypeOperator(expression)
|
||||
builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).at(expression)
|
||||
|
||||
return when (expression.operator) {
|
||||
IrTypeOperator.IMPLICIT_CAST -> lowerImplicitCast(expression)
|
||||
IrTypeOperator.IMPLICIT_DYNAMIC_CAST -> error("Dynamic casts are not supported in Wasm backend")
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> expression.argument
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> lowerIntegerCoercion(expression)
|
||||
IrTypeOperator.IMPLICIT_NOTNULL -> lowerImplicitCast(expression)
|
||||
IrTypeOperator.INSTANCEOF -> lowerInstanceOf(expression, inverted = false)
|
||||
IrTypeOperator.NOT_INSTANCEOF -> lowerInstanceOf(expression, inverted = true)
|
||||
IrTypeOperator.CAST -> lowerCast(expression, isSafe = false)
|
||||
IrTypeOperator.SAFE_CAST -> lowerCast(expression, isSafe = true)
|
||||
IrTypeOperator.SAM_CONVERSION -> TODO("SAM conversion: ${expression.render()}")
|
||||
IrTypeOperator.REINTERPRET_CAST -> expression
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerInstanceOf(
|
||||
expression: IrTypeOperatorCall,
|
||||
inverted: Boolean
|
||||
): IrExpression {
|
||||
return builder.irComposite(resultType = builtIns.booleanType) {
|
||||
val argument = cacheValue(expression.argument)
|
||||
val check = generateTypeCheck(argument, expression.typeOperand)
|
||||
if (inverted) {
|
||||
+builder.irNot(check)
|
||||
} else {
|
||||
+check
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrBlockBuilder.cacheValue(value: IrExpression): () -> IrExpressionWithCopy {
|
||||
if (value.isPure(true) && value is IrExpressionWithCopy) {
|
||||
return { value.deepCopyWithSymbols() }
|
||||
}
|
||||
val tmpVal = createTmpVariable(value)
|
||||
return { builder.irGet(tmpVal) }
|
||||
}
|
||||
|
||||
private fun IrType.isInlined(): Boolean =
|
||||
context.inlineClassesUtils.isTypeInlined(this)
|
||||
|
||||
private val IrType.erasedType: IrType
|
||||
get() = this.erasedUpperBound?.defaultType ?: builtIns.anyType
|
||||
|
||||
private fun generateTypeCheck(
|
||||
valueProvider: () -> IrExpressionWithCopy,
|
||||
toType: IrType
|
||||
): IrExpression {
|
||||
val toNotNullable = toType.makeNotNull()
|
||||
val valueInstance: IrExpressionWithCopy = valueProvider()
|
||||
val fromType = (valueInstance as IrExpression).type
|
||||
|
||||
// Inlined values have no type information on runtime.
|
||||
// But since they are final we can compute type checks on compile time.
|
||||
if (fromType.isInlined()) {
|
||||
val result = fromType.erasedType.isSubtypeOf(toType.erasedType, builtIns)
|
||||
return builder.irBoolean(result)
|
||||
}
|
||||
|
||||
val instanceCheck = generateTypeCheckNonNull(valueInstance, toNotNullable)
|
||||
val isFromNullable = valueInstance.type.isNullable()
|
||||
val isToNullable = toType.isNullable()
|
||||
|
||||
return when {
|
||||
!isFromNullable -> instanceCheck
|
||||
|
||||
else ->
|
||||
builder.irIfThenElse(
|
||||
type = builtIns.booleanType,
|
||||
condition = builder.irEqualsNull(valueProvider() as IrExpression),
|
||||
thenPart = builder.irBoolean(isToNullable),
|
||||
elsePart = instanceCheck
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerIntegerCoercion(expression: IrTypeOperatorCall): IrExpression =
|
||||
when (expression.typeOperand) {
|
||||
builtIns.byteType,
|
||||
builtIns.shortType ->
|
||||
expression.argument
|
||||
|
||||
builtIns.longType ->
|
||||
builder.irCall(symbols.intToLong).apply {
|
||||
putValueArgument(0, expression.argument)
|
||||
}
|
||||
|
||||
else -> error("Unreachable execution (coercion to non-Integer type")
|
||||
}
|
||||
|
||||
private fun generateTypeCheckNonNull(argument: IrExpressionWithCopy, toType: IrType): IrExpression {
|
||||
assert(!toType.isMarkedNullable())
|
||||
return when {
|
||||
toType.isNothing() -> builder.irComposite(resultType = builtIns.booleanType) {
|
||||
+(argument as IrExpression)
|
||||
+builder.irFalse()
|
||||
}
|
||||
toType.isTypeParameter() -> generateTypeCheckWithTypeParameter(argument, toType)
|
||||
toType.isInterface() -> generateIsInterface(argument as IrExpression, toType)
|
||||
else -> generateIsSubClass(argument as IrExpression, toType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun narrowType(fromType: IrType, toType: IrType, value: IrExpression): IrExpression {
|
||||
if (fromType == toType) return value
|
||||
|
||||
if (toType == builtIns.nothingNType) {
|
||||
return builder.irComposite(resultType = builtIns.nothingNType) {
|
||||
+value
|
||||
+builder.irNull()
|
||||
}
|
||||
}
|
||||
|
||||
// Handled by autoboxing transformer
|
||||
if (toType.isInlined() && !fromType.isInlined()) {
|
||||
return builder.irCall(
|
||||
symbols.unboxIntrinsic,
|
||||
toType,
|
||||
typeArguments = listOf(fromType, toType)
|
||||
).also {
|
||||
it.putValueArgument(0, value)
|
||||
}
|
||||
}
|
||||
|
||||
if (!toType.isInlined() && fromType.isInlined()) {
|
||||
return builder.irCall(
|
||||
symbols.boxIntrinsic,
|
||||
toType,
|
||||
typeArguments = listOf(fromType, toType)
|
||||
).also {
|
||||
it.putValueArgument(0, value)
|
||||
}
|
||||
}
|
||||
|
||||
if (fromType.erasedType.isSubtypeOf(toType.erasedType, context.irBuiltIns)) {
|
||||
return value
|
||||
}
|
||||
if (toType.isNothing()) {
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
// Ref casts traps on null (https://github.com/WebAssembly/gc/issues/152)
|
||||
// Handling null manually
|
||||
if (toType.isNullable() && fromType.isNullable()) {
|
||||
return builder.irComposite {
|
||||
val value = cacheValue(value)
|
||||
+builder.irIfNull(
|
||||
type = toType,
|
||||
subject = value() as IrExpression,
|
||||
thenPart = builder.irNull(toType),
|
||||
elsePart = builder.irCall(symbols.wasmRefCast, type = toType).apply {
|
||||
putTypeArgument(0, fromType)
|
||||
putTypeArgument(1, toType)
|
||||
putValueArgument(0, value() as IrExpression)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return builder.irCall(symbols.wasmRefCast, type = toType).apply {
|
||||
putTypeArgument(0, fromType)
|
||||
putTypeArgument(1, toType)
|
||||
putValueArgument(0, value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerCast(
|
||||
expression: IrTypeOperatorCall,
|
||||
isSafe: Boolean
|
||||
): IrExpression {
|
||||
val toType = expression.typeOperand
|
||||
val fromType = expression.argument.type
|
||||
|
||||
if (fromType.erasedType.isSubtypeOf(expression.type.erasedType, context.irBuiltIns)) {
|
||||
return narrowType(fromType, expression.type, expression.argument)
|
||||
}
|
||||
|
||||
val failResult = if (isSafe) {
|
||||
builder.irNull()
|
||||
} else {
|
||||
builder.irCall(context.ir.symbols.throwTypeCastException)
|
||||
}
|
||||
|
||||
return builder.irComposite(resultType = expression.type) {
|
||||
val argument = cacheValue(expression.argument)
|
||||
val narrowArg = narrowType(fromType, expression.type, argument() as IrExpression)
|
||||
val check = generateTypeCheck(argument, toType)
|
||||
if (check is IrConst<*>) {
|
||||
val value = check.value as Boolean
|
||||
if (value) {
|
||||
+narrowArg
|
||||
} else {
|
||||
+failResult
|
||||
}
|
||||
} else {
|
||||
+builder.irIfThenElse(
|
||||
type = expression.type,
|
||||
condition = check,
|
||||
thenPart = narrowArg,
|
||||
elsePart = failResult
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerImplicitCast(expression: IrTypeOperatorCall): IrExpression =
|
||||
narrowType(
|
||||
fromType = expression.argument.type,
|
||||
toType = expression.typeOperand,
|
||||
value = expression.argument
|
||||
)
|
||||
|
||||
private fun generateTypeCheckWithTypeParameter(argument: IrExpressionWithCopy, toType: IrType): IrExpression {
|
||||
val typeParameter = toType.classifierOrNull?.owner as? IrTypeParameter
|
||||
?: error("expected type parameter, but got $toType")
|
||||
|
||||
return typeParameter.superTypes.fold(builder.irTrue() as IrExpression) { r, t ->
|
||||
val check = generateTypeCheckNonNull(argument.copy() as IrExpressionWithCopy, t.makeNotNull())
|
||||
builder.irCall(symbols.booleanAnd).apply {
|
||||
putValueArgument(0, r)
|
||||
putValueArgument(1, check)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateIsInterface(argument: IrExpression, toType: IrType): IrExpression {
|
||||
val interfaceId = builder.irCall(symbols.wasmInterfaceId).apply {
|
||||
putTypeArgument(0, toType)
|
||||
}
|
||||
return builder.irCall(symbols.isInterface).apply {
|
||||
putValueArgument(0, argument)
|
||||
putValueArgument(1, interfaceId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateIsSubClass(argument: IrExpression, toType: IrType): IrExpression {
|
||||
val classId = builder.irCall(symbols.wasmClassId).apply {
|
||||
putTypeArgument(0, toType)
|
||||
}
|
||||
return builder.irCall(symbols.isSubClass).apply {
|
||||
putValueArgument(0, argument)
|
||||
putValueArgument(1, classId)
|
||||
}
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irComposite
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irInt
|
||||
import org.jetbrains.kotlin.ir.builders.irTemporary
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVarargElement
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal class WasmVarargExpressionLowering(
|
||||
private val context: WasmBackendContext
|
||||
) : FileLoweringPass, IrElementTransformerVoidWithContext() {
|
||||
val symbols = context.wasmSymbols
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitVararg(expression: IrVararg): IrExpression {
|
||||
val irVararg = super.visitVararg(expression) as IrVararg
|
||||
val builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol)
|
||||
val arrayClass = irVararg.type.classOrNull!!.owner
|
||||
val primaryConstructor = arrayClass.primaryConstructor!!
|
||||
val setMethod = arrayClass.declarations.filterIsInstance<IrSimpleFunction>().find {
|
||||
it.name == Name.identifier("set")
|
||||
}!!
|
||||
return builder.irComposite(irVararg) {
|
||||
val arrayTempVariable = irTemporary(
|
||||
value = irCall(primaryConstructor).apply {
|
||||
putValueArgument(0, irInt(irVararg.elements.size))
|
||||
if (primaryConstructor.typeParameters.isNotEmpty()) {
|
||||
check(primaryConstructor.typeParameters.size == 1)
|
||||
putTypeArgument(0, irVararg.varargElementType)
|
||||
}
|
||||
},
|
||||
nameHint = "array_tmp"
|
||||
)
|
||||
for ((index: Int, element: IrVarargElement) in irVararg.elements.withIndex()) {
|
||||
check(element is IrExpression) {
|
||||
"TODO: Support $element as vararg elements"
|
||||
}
|
||||
|
||||
+irCall(setMethod).apply {
|
||||
dispatchReceiver = irGet(arrayTempVariable)
|
||||
putValueArgument(0, irInt(index))
|
||||
putValueArgument(1, element)
|
||||
}
|
||||
}
|
||||
+irGet(arrayTempVariable)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) =
|
||||
transformFunctionAccessExpression(expression)
|
||||
|
||||
private fun transformFunctionAccessExpression(expression: IrFunctionAccessExpression): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
val builder by lazy { context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol) }
|
||||
|
||||
// Replace empty vararg arguments with empty array construction
|
||||
for (argumentIdx in 0 until expression.valueArgumentsCount) {
|
||||
val argument = expression.getValueArgument(argumentIdx)
|
||||
val parameter = expression.symbol.owner.valueParameters[argumentIdx]
|
||||
val varargElementType = parameter.varargElementType
|
||||
if (argument == null && varargElementType != null) {
|
||||
val arrayClass = parameter.type.classOrNull!!.owner
|
||||
val primaryConstructor = arrayClass.primaryConstructor!!
|
||||
val emptyArrayCall = with(builder) {
|
||||
irCall(primaryConstructor).apply {
|
||||
putValueArgument(0, irInt(0))
|
||||
if (primaryConstructor.typeParameters.isNotEmpty()) {
|
||||
check(primaryConstructor.typeParameters.size == 1)
|
||||
putTypeArgument(0, parameter.varargElementType)
|
||||
}
|
||||
}
|
||||
}
|
||||
expression.putValueArgument(argumentIdx, emptyArrayCall)
|
||||
}
|
||||
}
|
||||
return expression
|
||||
}
|
||||
}
|
||||
+14
-6
@@ -11,19 +11,27 @@ import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.util.getAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.wasm.ir.WasmImportPair
|
||||
|
||||
fun IrAnnotationContainer.hasExcludedFromCodegenAnnotation(): Boolean =
|
||||
hasAnnotation(FqName("kotlin.wasm.internal.ExcludedFromCodegen"))
|
||||
|
||||
fun IrAnnotationContainer.getWasmInstructionAnnotation(): String? =
|
||||
getAnnotation(FqName("kotlin.wasm.internal.WasmInstruction"))?.getSingleConstStringArgument()
|
||||
fun IrAnnotationContainer.getWasmOpAnnotation(): String? =
|
||||
getAnnotation(FqName("kotlin.wasm.internal.WasmOp"))?.getSingleConstStringArgument()
|
||||
|
||||
fun IrAnnotationContainer.hasWasmReinterpretAnnotation(): Boolean =
|
||||
hasAnnotation(FqName("kotlin.wasm.internal.WasmReinterpret"))
|
||||
|
||||
fun IrAnnotationContainer.hasWasmForeignAnnotation(): Boolean =
|
||||
hasAnnotation(FqName("kotlin.wasm.internal.WasmForeign"))
|
||||
|
||||
fun IrAnnotationContainer.hasWasmPrimitiveAnnotation(): Boolean =
|
||||
hasAnnotation(FqName("kotlin.wasm.internal.WasmPrimitive"))
|
||||
|
||||
class WasmImportPair(val module: String, val name: String)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun IrAnnotationContainer.getWasmImportAnnotation(): WasmImportPair? =
|
||||
getAnnotation(FqName("kotlin.wasm.internal.WasmImport"))?.let {
|
||||
WasmImportPair(
|
||||
(it.getValueArgument(0) as IrConst<String>).value,
|
||||
(it.getValueArgument(1) as IrConst<String>).value
|
||||
(it.getValueArgument(0) as IrConst<*>).value as String,
|
||||
(it.getValueArgument(1) as IrConst<*>).value as String
|
||||
)
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.backend.wasm.utils
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmSymbols
|
||||
import org.jetbrains.kotlin.ir.backend.js.InlineClassesUtils
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.erase
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
|
||||
class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : InlineClassesUtils {
|
||||
override fun isTypeInlined(type: IrType): Boolean {
|
||||
return getInlinedClass(type) != null
|
||||
}
|
||||
|
||||
override fun getInlinedClass(type: IrType): IrClass? {
|
||||
if (type is IrSimpleType) {
|
||||
// TODO: Make inlining less strict
|
||||
if (type.isNullable()) return null
|
||||
val erased = erase(type) ?: return null
|
||||
if (isClassInlineLike(erased)) {
|
||||
return erased
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun isClassInlineLike(klass: IrClass): Boolean {
|
||||
return klass.isInline || klass.hasWasmPrimitiveAnnotation()
|
||||
}
|
||||
|
||||
override val boxIntrinsic: IrSimpleFunctionSymbol
|
||||
get() = wasmSymbols.boxIntrinsic
|
||||
|
||||
override val unboxIntrinsic: IrSimpleFunctionSymbol
|
||||
get() = wasmSymbols.unboxIntrinsic
|
||||
}
|
||||
@@ -404,14 +404,16 @@ fun irCall(
|
||||
newFunction: IrSimpleFunction,
|
||||
receiversAsArguments: Boolean = false,
|
||||
argumentsAsReceivers: Boolean = false,
|
||||
newSuperQualifierSymbol: IrClassSymbol? = null
|
||||
newSuperQualifierSymbol: IrClassSymbol? = null,
|
||||
newReturnType: IrType? = null
|
||||
): IrCall =
|
||||
irCall(
|
||||
call,
|
||||
newFunction.symbol,
|
||||
receiversAsArguments,
|
||||
argumentsAsReceivers,
|
||||
newSuperQualifierSymbol
|
||||
newSuperQualifierSymbol,
|
||||
newReturnType
|
||||
)
|
||||
|
||||
fun irCall(
|
||||
@@ -419,13 +421,14 @@ fun irCall(
|
||||
newSymbol: IrSimpleFunctionSymbol,
|
||||
receiversAsArguments: Boolean = false,
|
||||
argumentsAsReceivers: Boolean = false,
|
||||
newSuperQualifierSymbol: IrClassSymbol? = null
|
||||
newSuperQualifierSymbol: IrClassSymbol? = null,
|
||||
newReturnType: IrType? = null
|
||||
): IrCall =
|
||||
call.run {
|
||||
IrCallImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
type,
|
||||
newReturnType ?: type,
|
||||
newSymbol,
|
||||
typeArgumentsCount,
|
||||
valueArgumentsCount = newSymbol.owner.valueParameters.size,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
class C(val x: String)
|
||||
|
||||
fun <T1 : C, T2 : T1> foo(x: T2): String =
|
||||
x.x
|
||||
|
||||
fun box(): String {
|
||||
return foo(C("OK"))
|
||||
}
|
||||
+5
@@ -13815,6 +13815,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterAsUpperBound.kt")
|
||||
public void testTypeParameterAsUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParameterAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersInLocalFunction.kt")
|
||||
public void testTypeParametersInLocalFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParametersInLocalFunction.kt");
|
||||
|
||||
+5
@@ -13815,6 +13815,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterAsUpperBound.kt")
|
||||
public void testTypeParameterAsUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParameterAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersInLocalFunction.kt")
|
||||
public void testTypeParametersInLocalFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParametersInLocalFunction.kt");
|
||||
|
||||
+5
@@ -12415,6 +12415,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterAsUpperBound.kt")
|
||||
public void testTypeParameterAsUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParameterAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersInLocalFunction.kt")
|
||||
public void testTypeParametersInLocalFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParametersInLocalFunction.kt");
|
||||
|
||||
@@ -232,7 +232,7 @@ val currentOsType = run {
|
||||
OsType(osName, osArch)
|
||||
}
|
||||
|
||||
val jsShellDirectory = "https://archive.mozilla.org/pub/firefox/nightly/2019/08/2019-08-11-09-56-40-mozilla-central"
|
||||
val jsShellDirectory = "https://archive.mozilla.org/pub/firefox/nightly/2020/06/2020-06-29-15-46-04-mozilla-central"
|
||||
val jsShellSuffix = when (currentOsType) {
|
||||
OsType(OsName.LINUX, OsArch.X86_32) -> "linux-i686"
|
||||
OsType(OsName.LINUX, OsArch.X86_64) -> "linux-x86_64"
|
||||
@@ -248,6 +248,7 @@ val downloadedTools = File(buildDir, "tools")
|
||||
val downloadJsShell by task<Download> {
|
||||
src(jsShellLocation)
|
||||
dest(File(downloadedTools, "jsshell-$jsShellSuffix.zip"))
|
||||
overwrite(false)
|
||||
}
|
||||
|
||||
val unzipJsShell by task<Copy> {
|
||||
@@ -257,13 +258,45 @@ val unzipJsShell by task<Copy> {
|
||||
into(unpackedDir)
|
||||
}
|
||||
|
||||
val v8osString = when (currentOsType) {
|
||||
OsType(OsName.LINUX, OsArch.X86_32) -> "linux32"
|
||||
OsType(OsName.LINUX, OsArch.X86_64) -> "linux64"
|
||||
OsType(OsName.MAC, OsArch.X86_64) -> "mac64"
|
||||
OsType(OsName.WINDOWS, OsArch.X86_32) -> "win32"
|
||||
OsType(OsName.WINDOWS, OsArch.X86_64) -> "win64"
|
||||
else -> error("unsupported os type $currentOsType")
|
||||
}
|
||||
|
||||
val v8edition = "rel" // rel or dbg
|
||||
val v8version = "8.8.104"
|
||||
val v8fileName = "v8-${v8osString}-${v8edition}-${v8version}"
|
||||
val v8url = "https://storage.googleapis.com/chromium-v8/official/canary/$v8fileName.zip"
|
||||
|
||||
val downloadV8 by task<Download> {
|
||||
src(v8url)
|
||||
dest(File(downloadedTools, "$v8fileName.zip"))
|
||||
overwrite(false)
|
||||
}
|
||||
|
||||
val unzipV8 by task<Copy> {
|
||||
dependsOn(downloadV8)
|
||||
from(zipTree(downloadV8.get().dest))
|
||||
val unpackedDir = File(downloadedTools, v8fileName)
|
||||
into(unpackedDir)
|
||||
}
|
||||
|
||||
projectTest("wasmTest", true) {
|
||||
dependsOn(unzipJsShell)
|
||||
dependsOn(unzipV8)
|
||||
include("org/jetbrains/kotlin/js/test/wasm/semantics/*")
|
||||
val jsShellExecutablePath = File(unzipJsShell.get().destinationDir, "js").absolutePath
|
||||
systemProperty("javascript.engine.path.SpiderMonkey", jsShellExecutablePath)
|
||||
val v8ExecutablePath = File(unzipV8.get().destinationDir, "d8").absolutePath
|
||||
println(v8ExecutablePath)
|
||||
|
||||
dependsOn(":kotlin-stdlib-js-ir:compileKotlinJs")
|
||||
systemProperty("javascript.engine.path.SpiderMonkey", jsShellExecutablePath)
|
||||
systemProperty("javascript.engine.path.V8", v8ExecutablePath)
|
||||
|
||||
dependsOn(":kotlin-stdlib-wasm:compileKotlinJs")
|
||||
systemProperty("kotlin.wasm.stdlib.path", "libraries/stdlib/wasm/build/classes/kotlin/js/main")
|
||||
|
||||
setUpBoxTests()
|
||||
|
||||
@@ -956,3 +956,14 @@ abstract class BasicBoxTest(
|
||||
else ScriptEngineV8Lazy(KotlinTestUtils.tmpDirForReusableFolder("j2v8_library_path").path)
|
||||
}
|
||||
}
|
||||
|
||||
fun KotlinTestWithEnvironment.createPsiFile(fileName: String): KtFile {
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
|
||||
val file = fileSystem.findFileByPath(fileName) ?: error("File not found: $fileName")
|
||||
|
||||
return psiManager.findFile(file) as KtFile
|
||||
}
|
||||
|
||||
fun KotlinTestWithEnvironment.createPsiFiles(fileNames: List<String>): List<KtFile> = fileNames.map(this::createPsiFile)
|
||||
@@ -9,18 +9,20 @@ import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiManager
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.toPhaseMap
|
||||
import org.jetbrains.kotlin.backend.wasm.compileWasm
|
||||
import org.jetbrains.kotlin.backend.wasm.wasmPhases
|
||||
import org.jetbrains.kotlin.checkers.parseLanguageVersionSettings
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.loadKlib
|
||||
import org.jetbrains.kotlin.js.config.JsConfig
|
||||
import org.jetbrains.kotlin.js.facade.TranslationUnit
|
||||
import org.jetbrains.kotlin.js.test.engines.ExternalTool
|
||||
import org.jetbrains.kotlin.js.test.engines.SpiderMonkeyEngine
|
||||
import org.jetbrains.kotlin.library.resolver.impl.KotlinLibraryResolverResultImpl
|
||||
import org.jetbrains.kotlin.library.resolver.impl.KotlinResolvedLibraryImpl
|
||||
@@ -28,10 +30,11 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.Directives
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
|
||||
import org.jetbrains.kotlin.test.TestFiles
|
||||
import org.jetbrains.kotlin.test.*
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.lang.Boolean.getBoolean
|
||||
@@ -48,8 +51,13 @@ abstract class BasicWasmBoxTest(
|
||||
|
||||
private val spiderMonkey by lazy { SpiderMonkeyEngine() }
|
||||
|
||||
fun doTestWithCoroutinesPackageReplacement(filePath: String, coroutinesPackage: String) {
|
||||
TODO("TestWithCoroutinesPackageReplacement are not supported")
|
||||
}
|
||||
|
||||
fun doTest(filePath: String) {
|
||||
val file = File(filePath)
|
||||
|
||||
val outputDir = getOutputDir(file)
|
||||
val fileContent = KotlinTestUtils.doLoadFile(file)
|
||||
|
||||
@@ -58,21 +66,31 @@ abstract class BasicWasmBoxTest(
|
||||
val testPackage = testFactory.testPackage
|
||||
val outputFileBase = outputDir.absolutePath + "/" + getTestName(true)
|
||||
val outputWatFile = outputFileBase + ".wat"
|
||||
val outputWasmFile = outputFileBase + ".wasm"
|
||||
val outputJsFile = outputFileBase + ".js"
|
||||
|
||||
val languageVersionSettings = inputFiles.mapNotNull { it.languageVersionSettings }.firstOrNull()
|
||||
|
||||
val kotlinFiles = inputFiles.filter { it.fileName.endsWith(".kt") }
|
||||
val psiFiles = createPsiFiles(kotlinFiles.map { File(it.fileName).canonicalPath }.sorted())
|
||||
val config = createConfig()
|
||||
val config = createConfig(languageVersionSettings)
|
||||
translateFiles(
|
||||
file,
|
||||
psiFiles.map(TranslationUnit::SourceFile),
|
||||
File(outputWatFile),
|
||||
File(outputWasmFile),
|
||||
File(outputJsFile),
|
||||
config,
|
||||
testPackage,
|
||||
TEST_FUNCTION
|
||||
)
|
||||
|
||||
spiderMonkey.runFile(outputJsFile)
|
||||
ExternalTool(System.getProperty("javascript.engine.path.V8"))
|
||||
.run(
|
||||
"--experimental-wasm-typed-funcref",
|
||||
"--experimental-wasm-gc",
|
||||
outputJsFile
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,26 +104,32 @@ abstract class BasicWasmBoxTest(
|
||||
}
|
||||
|
||||
private fun translateFiles(
|
||||
testFile: File,
|
||||
units: List<TranslationUnit>,
|
||||
outputWatFile: File,
|
||||
outputWasmFile: File,
|
||||
outputJsFile: File,
|
||||
config: JsConfig,
|
||||
testPackage: String?,
|
||||
testFunction: String
|
||||
) {
|
||||
val filesToCompile = units.map { (it as TranslationUnit.SourceFile).file }
|
||||
val debugMode = getBoolean("kotlin.js.debugMode")
|
||||
val debugMode =getBoolean("kotlin.js.debugMode")
|
||||
|
||||
val phaseConfig = if (debugMode) {
|
||||
val allPhasesSet = wasmPhases.toPhaseMap().values.toSet()
|
||||
val dumpOutputDir = File(outputWatFile.parent, outputWatFile.nameWithoutExtension + "-irdump")
|
||||
println("\n ------ Dumping phases to file://$dumpOutputDir")
|
||||
println("\n ------ KT file://${testFile.absolutePath}")
|
||||
println("\n ------ WAT file://$outputWatFile")
|
||||
println("\n ------ WASM file://$outputWasmFile")
|
||||
println(" ------ JS file://$outputJsFile")
|
||||
PhaseConfig(
|
||||
wasmPhases,
|
||||
dumpToDirectory = dumpOutputDir.path,
|
||||
toDumpStateAfter = allPhasesSet,
|
||||
toValidateStateAfter = allPhasesSet,
|
||||
dumpOnlyFqName = null
|
||||
// toDumpStateAfter = allPhasesSet,
|
||||
// toValidateStateAfter = allPhasesSet,
|
||||
// dumpOnlyFqName = null
|
||||
)
|
||||
} else {
|
||||
PhaseConfig(wasmPhases)
|
||||
@@ -124,12 +148,12 @@ abstract class BasicWasmBoxTest(
|
||||
)
|
||||
|
||||
outputWatFile.write(compilerResult.wat)
|
||||
outputWasmFile.writeBytes(compilerResult.wasm)
|
||||
|
||||
val runtime = File("libraries/stdlib/wasm/runtime/runtime.js").readText()
|
||||
|
||||
val testRunner = """
|
||||
const wat = read(String.raw`${outputWatFile.absoluteFile}`);
|
||||
const wasmBinary = wasmTextToBinary(wat);
|
||||
const wasmBinary = read(String.raw`${outputWasmFile.absoluteFile}`, 'binary');
|
||||
const wasmModule = new WebAssembly.Module(wasmBinary);
|
||||
const wasmInstance = new WebAssembly.Instance(wasmModule, { runtime });
|
||||
|
||||
@@ -141,20 +165,11 @@ abstract class BasicWasmBoxTest(
|
||||
outputJsFile.write(runtime + "\n" + compilerResult.js + "\n" + testRunner)
|
||||
}
|
||||
|
||||
private fun createPsiFile(fileName: String): KtFile {
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
|
||||
val file = fileSystem.findFileByPath(fileName) ?: error("File not found: $fileName")
|
||||
|
||||
return psiManager.findFile(file) as KtFile
|
||||
}
|
||||
|
||||
private fun createPsiFiles(fileNames: List<String>): List<KtFile> = fileNames.map(this::createPsiFile)
|
||||
|
||||
private fun createConfig(): JsConfig {
|
||||
private fun createConfig(languageVersionSettings: LanguageVersionSettings?): JsConfig {
|
||||
val configuration = environment.configuration.copy()
|
||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, TEST_MODULE)
|
||||
configuration.languageVersionSettings = languageVersionSettings ?: LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE)
|
||||
return JsConfig(project, configuration, null, null)
|
||||
}
|
||||
|
||||
@@ -169,11 +184,13 @@ abstract class BasicWasmBoxTest(
|
||||
}
|
||||
}
|
||||
|
||||
val languageVersionSettings = parseLanguageVersionSettings(directives)
|
||||
|
||||
val temporaryFile = File(tmpDir, "WASM_TEST/$fileName")
|
||||
KotlinTestUtils.mkdirs(temporaryFile.parentFile)
|
||||
temporaryFile.writeText(text, Charsets.UTF_8)
|
||||
|
||||
return TestFile(temporaryFile.absolutePath)
|
||||
return TestFile(temporaryFile.absolutePath, languageVersionSettings)
|
||||
}
|
||||
|
||||
var testPackage: String? = null
|
||||
@@ -184,7 +201,7 @@ abstract class BasicWasmBoxTest(
|
||||
}
|
||||
}
|
||||
|
||||
private class TestFile(val fileName: String)
|
||||
private class TestFile(val fileName: String, val languageVersionSettings: LanguageVersionSettings?)
|
||||
|
||||
override fun createEnvironment() =
|
||||
KotlinCoreEnvironment.createForTests(testRootDisposable, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
|
||||
|
||||
@@ -39,6 +39,6 @@ class SpiderMonkeyEngine(
|
||||
private val jsShell = ExternalTool(jsShellPath)
|
||||
|
||||
fun runFile(file: String) {
|
||||
jsShell.run(file)
|
||||
jsShell.run("--wasm-gc", file)
|
||||
}
|
||||
}
|
||||
Generated
+5
@@ -10655,6 +10655,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
||||
runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterAsUpperBound.kt")
|
||||
public void testTypeParameterAsUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParameterAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersInLocalFunction.kt")
|
||||
public void testTypeParametersInLocalFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParametersInLocalFunction.kt");
|
||||
|
||||
Generated
+5
@@ -10655,6 +10655,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterAsUpperBound.kt")
|
||||
public void testTypeParameterAsUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParameterAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersInLocalFunction.kt")
|
||||
public void testTypeParametersInLocalFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParametersInLocalFunction.kt");
|
||||
|
||||
+5
@@ -10655,6 +10655,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/functions/recursiveIncrementCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterAsUpperBound.kt")
|
||||
public void testTypeParameterAsUpperBound() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParameterAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParametersInLocalFunction.kt")
|
||||
public void testTypeParametersInLocalFunction() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/typeParametersInLocalFunction.kt");
|
||||
|
||||
@@ -1,19 +1,65 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType.IR
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
val unimplementedNativeBuiltIns =
|
||||
(file("$rootDir/core/builtins/native/kotlin/").list().toSortedSet() - file("$rootDir/libraries/stdlib/wasm/builtins/kotlin/").list())
|
||||
.map { "core/builtins/native/kotlin/$it" }
|
||||
|
||||
|
||||
|
||||
val builtInsSources by task<Sync> {
|
||||
val sources = listOf(
|
||||
"core/builtins/src/kotlin/"
|
||||
) + unimplementedNativeBuiltIns
|
||||
|
||||
val excluded = listOf(
|
||||
// JS-specific optimized version of emptyArray() already defined
|
||||
"core/builtins/src/kotlin/ArrayIntrinsics.kt"
|
||||
)
|
||||
|
||||
sources.forEach { path ->
|
||||
from("$rootDir/$path") {
|
||||
into(path.dropLastWhile { it != '/' })
|
||||
excluded.filter { it.startsWith(path) }.forEach {
|
||||
exclude(it.substring(path.length))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
into("$buildDir/builtInsSources")
|
||||
}
|
||||
|
||||
val commonMainSources by task<Sync> {
|
||||
val sources = listOf(
|
||||
"libraries/stdlib/common/src/",
|
||||
"libraries/stdlib/src/kotlin/",
|
||||
"libraries/stdlib/unsigned/"
|
||||
)
|
||||
|
||||
sources.forEach { path ->
|
||||
from("$rootDir/$path") {
|
||||
into(path.dropLastWhile { it != '/' })
|
||||
}
|
||||
}
|
||||
|
||||
into("$buildDir/commonMainSources")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
js(IR) {
|
||||
nodejs()
|
||||
}
|
||||
sourceSets {
|
||||
val jsMain by getting {
|
||||
kotlin.srcDirs("builtins", "internal", "runtime")
|
||||
kotlin.srcDirs("builtins", "internal", "runtime", "src", "stubs")
|
||||
kotlin.srcDirs(files(builtInsSources.map { it.destinationDir }))
|
||||
}
|
||||
|
||||
val commonMain by getting {
|
||||
kotlin.srcDirs(files(commonMainSources.map { it.destinationDir }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,10 +74,13 @@ tasks.withType<KotlinCompile<*>>().configureEach {
|
||||
"-Xinline-classes",
|
||||
"-Xopt-in=kotlin.RequiresOptIn",
|
||||
"-Xopt-in=kotlin.ExperimentalUnsignedTypes",
|
||||
"-Xopt-in=kotlin.ExperimentalStdlibApi"
|
||||
"-Xopt-in=kotlin.ExperimentalStdlibApi",
|
||||
"-Xexplicit-api=warning"
|
||||
)
|
||||
}
|
||||
|
||||
tasks.named("compileKotlinJs") {
|
||||
(this as KotlinCompile<*>).kotlinOptions.freeCompilerArgs += "-Xir-module-name=kotlin"
|
||||
dependsOn(commonMainSources)
|
||||
dependsOn(builtInsSources)
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
This directory is a modified copy of `core/builtins` adapted for current
|
||||
needs of WASM backend.
|
||||
|
||||
This is a temporary solution for a development convenience. Most of files
|
||||
from `core/builtins` will be reused once compiler implementation and
|
||||
stdlib become stable.
|
||||
+13
-11
@@ -3,20 +3,19 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress(
|
||||
"NON_ABSTRACT_FUNCTION_WITH_NO_BODY",
|
||||
"MUST_BE_INITIALIZED_OR_BE_ABSTRACT",
|
||||
"EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE",
|
||||
"PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED",
|
||||
"WRONG_MODIFIER_TARGET"
|
||||
)
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.wasm.internal.*
|
||||
|
||||
/**
|
||||
* The root of the Kotlin class hierarchy. Every Kotlin class has [Any] as a superclass.
|
||||
*/
|
||||
public open class Any {
|
||||
// Pointer to runtime type info
|
||||
// Initialized by a compiler
|
||||
@Suppress("MUST_BE_INITIALIZED_OR_BE_ABSTRACT")
|
||||
internal var typeInfo: Int
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one. Implementations must fulfil the following
|
||||
* requirements:
|
||||
@@ -29,7 +28,8 @@ public open class Any {
|
||||
*
|
||||
* Read more about [equality](https://kotlinlang.org/docs/reference/equality.html) in Kotlin.
|
||||
*/
|
||||
public open operator fun equals(other: Any?): Boolean
|
||||
public open operator fun equals(other: Any?): Boolean =
|
||||
wasm_ref_eq(this, other)
|
||||
|
||||
/**
|
||||
* Returns a hash code value for the object. The general contract of `hashCode` is:
|
||||
@@ -37,10 +37,12 @@ public open class Any {
|
||||
* * Whenever it is invoked on the same object more than once, the `hashCode` method must consistently return the same integer, provided no information used in `equals` comparisons on the object is modified.
|
||||
* * If two objects are equal according to the `equals()` method, then calling the `hashCode` method on each of the two objects must produce the same integer result.
|
||||
*/
|
||||
public open fun hashCode(): Int
|
||||
// TODO: Implement
|
||||
public open fun hashCode(): Int = 100
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object.
|
||||
*/
|
||||
public open fun toString(): String
|
||||
// TODO: Implement
|
||||
public open fun toString(): String = "[Object object]"
|
||||
}
|
||||
+24
-13
@@ -3,16 +3,10 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress(
|
||||
"NON_ABSTRACT_FUNCTION_WITH_NO_BODY",
|
||||
"MUST_BE_INITIALIZED_OR_BE_ABSTRACT",
|
||||
"EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE",
|
||||
"PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED",
|
||||
"WRONG_MODIFIER_TARGET"
|
||||
)
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.wasm.internal.*
|
||||
|
||||
/**
|
||||
* Represents an array (specifically, a Java array when targeting the JVM platform).
|
||||
* Array instances can be created using the [arrayOf], [arrayOfNulls] and [emptyArray]
|
||||
@@ -20,7 +14,9 @@ package kotlin
|
||||
* See [Kotlin language documentation](https://kotlinlang.org/docs/reference/basic-types.html#arrays)
|
||||
* for more information on arrays.
|
||||
*/
|
||||
public class Array<T> {
|
||||
public class Array<T> constructor(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
/**
|
||||
* Creates a new array with the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
@@ -28,7 +24,10 @@ public class Array<T> {
|
||||
* The function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for an array element given its index.
|
||||
*/
|
||||
public inline constructor(size: Int, init: (Int) -> T)
|
||||
@Suppress("TYPE_PARAMETER_AS_REIFIED")
|
||||
public constructor(size: Int, init: (Int) -> T) : this(size) {
|
||||
JsArray_fill_T(jsArray, size, init)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array element at the specified [index]. This method can be called using the
|
||||
@@ -40,7 +39,9 @@ public class Array<T> {
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun get(index: Int): T
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public operator fun get(index: Int): T =
|
||||
WasmExternRefToAny(JsArray_get_WasmExternRef(jsArray, index)) as T
|
||||
|
||||
/**
|
||||
* Sets the array element at the specified [index] to the specified [value]. This method can
|
||||
@@ -52,15 +53,25 @@ public class Array<T> {
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: T): Unit
|
||||
public operator fun set(index: Int, value: T) {
|
||||
JsArray_set_WasmExternRef(jsArray, index, value.toWasmExternRef())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the array.
|
||||
*/
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
/**
|
||||
* Creates an iterator for iterating over the elements of the array.
|
||||
*/
|
||||
public operator fun iterator(): Iterator<T>
|
||||
public operator fun iterator(): Iterator<T> = arrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun <T> arrayIterator(array: Array<T>) = object : Iterator<T> {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun next() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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 kotlin
|
||||
|
||||
import kotlin.wasm.internal.*
|
||||
|
||||
public class ByteArray(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
init {
|
||||
JsArray_fill_Byte(jsArray, size) { 0 }
|
||||
}
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Byte) : this(size) {
|
||||
jsArray = JsArray_new(size)
|
||||
JsArray_fill_Byte(jsArray, size, init)
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Byte =
|
||||
JsArray_get_Byte(jsArray, index)
|
||||
|
||||
public operator fun set(index: Int, value: Byte) {
|
||||
JsArray_set_Byte(jsArray, index, value)
|
||||
}
|
||||
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
|
||||
public operator fun iterator(): ByteIterator = byteArrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun byteArrayIterator(array: ByteArray) = object : ByteIterator() {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun nextByte() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
|
||||
|
||||
public class CharArray(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
init {
|
||||
JsArray_fill_Char(jsArray, size) { 0.toChar() }
|
||||
}
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Char) : this(size) {
|
||||
jsArray = JsArray_new(size)
|
||||
JsArray_fill_Char(jsArray, size, init)
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Char =
|
||||
JsArray_get_Char(jsArray, index)
|
||||
|
||||
public operator fun set(index: Int, value: Char) {
|
||||
JsArray_set_Char(jsArray, index, value)
|
||||
}
|
||||
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
|
||||
public operator fun iterator(): CharIterator = charArrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun charArrayIterator(array: CharArray) = object : CharIterator() {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun nextChar() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
|
||||
|
||||
public class ShortArray(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
init {
|
||||
JsArray_fill_Short(jsArray, size) { 0 }
|
||||
}
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Short) : this(size) {
|
||||
JsArray_fill_Short(jsArray, size, init)
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Short =
|
||||
JsArray_get_Short(jsArray, index)
|
||||
|
||||
public operator fun set(index: Int, value: Short) {
|
||||
JsArray_set_Short(jsArray, index, value)
|
||||
}
|
||||
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
|
||||
public operator fun iterator(): ShortIterator = shortArrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun shortArrayIterator(array: ShortArray) = object : ShortIterator() {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun nextShort() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
|
||||
|
||||
public class IntArray(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
init {
|
||||
JsArray_fill_Int(jsArray, size) { 0 }
|
||||
}
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Int) : this(size) {
|
||||
JsArray_fill_Int(jsArray, size, init)
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Int =
|
||||
JsArray_get_Int(jsArray, index)
|
||||
|
||||
public operator fun set(index: Int, value: Int) {
|
||||
JsArray_set_Int(jsArray, index, value)
|
||||
}
|
||||
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
|
||||
public operator fun iterator(): IntIterator = intArrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun intArrayIterator(array: IntArray) = object : IntIterator() {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun nextInt() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
|
||||
|
||||
public class LongArray(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
init {
|
||||
JsArray_fill_Long(jsArray, size) { 0L }
|
||||
}
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Long) : this(size) {
|
||||
JsArray_fill_Long(jsArray, size, init)
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Long =
|
||||
JsArray_get_Long(jsArray, index)
|
||||
|
||||
public operator fun set(index: Int, value: Long) {
|
||||
JsArray_set_Long(jsArray, index, value)
|
||||
}
|
||||
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
|
||||
public operator fun iterator(): LongIterator = longArrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun longArrayIterator(array: LongArray) = object : LongIterator() {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun nextLong() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
|
||||
|
||||
public class FloatArray(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
init {
|
||||
JsArray_fill_Float(jsArray, size) { 0.0f }
|
||||
}
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Float) : this(size) {
|
||||
JsArray_fill_Float(jsArray, size, init)
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Float =
|
||||
JsArray_get_Float(jsArray, index)
|
||||
|
||||
public operator fun set(index: Int, value: Float) {
|
||||
JsArray_set_Float(jsArray, index, value)
|
||||
}
|
||||
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
|
||||
public operator fun iterator(): FloatIterator = floatArrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun floatArrayIterator(array: FloatArray) = object : FloatIterator() {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun nextFloat() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
|
||||
|
||||
public class DoubleArray(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
init {
|
||||
JsArray_fill_Double(jsArray, size) { 0.0 }
|
||||
}
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Double) : this(size) {
|
||||
JsArray_fill_Double(jsArray, size, init)
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Double =
|
||||
JsArray_get_Double(jsArray, index)
|
||||
|
||||
public operator fun set(index: Int, value: Double) {
|
||||
JsArray_set_Double(jsArray, index, value)
|
||||
}
|
||||
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
|
||||
public operator fun iterator(): DoubleIterator = doubleArrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun doubleArrayIterator(array: DoubleArray) = object : DoubleIterator() {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun nextDouble() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
|
||||
|
||||
public class BooleanArray(size: Int) {
|
||||
private var jsArray: WasmExternRef = JsArray_new(size)
|
||||
|
||||
init {
|
||||
JsArray_fill_Boolean(jsArray, size) { false }
|
||||
}
|
||||
|
||||
public constructor(size: Int, init: (Int) -> Boolean) : this(size) {
|
||||
JsArray_fill_Boolean(jsArray, size, init)
|
||||
}
|
||||
|
||||
public operator fun get(index: Int): Boolean =
|
||||
JsArray_get_Boolean(jsArray, index)
|
||||
|
||||
public operator fun set(index: Int, value: Boolean) {
|
||||
JsArray_set_Boolean(jsArray, index, value)
|
||||
}
|
||||
|
||||
public val size: Int
|
||||
get() = JsArray_getSize(jsArray)
|
||||
|
||||
|
||||
public operator fun iterator(): BooleanIterator = booleanArrayIterator(this)
|
||||
}
|
||||
|
||||
internal fun booleanArrayIterator(array: BooleanArray) = object : BooleanIterator() {
|
||||
var index = 0
|
||||
override fun hasNext() = index != array.size
|
||||
override fun nextBoolean() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
|
||||
}
|
||||
+34
-23
@@ -3,56 +3,67 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress(
|
||||
"NON_ABSTRACT_FUNCTION_WITH_NO_BODY",
|
||||
"MUST_BE_INITIALIZED_OR_BE_ABSTRACT",
|
||||
"EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE",
|
||||
"PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED",
|
||||
"WRONG_MODIFIER_TARGET"
|
||||
)
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.wasm.internal.WasmInstruction
|
||||
import kotlin.wasm.internal.wasm_i32_compareTo
|
||||
import kotlin.wasm.internal.*
|
||||
|
||||
/**
|
||||
* Represents a value which is either `true` or `false`. On the JVM, non-nullable values of this type are
|
||||
* represented as values of the primitive type `boolean`.
|
||||
*/
|
||||
public class Boolean private constructor() : Comparable<Boolean> {
|
||||
@WasmPrimitive
|
||||
public class Boolean private constructor(private val value: Boolean) : Comparable<Boolean> {
|
||||
/**
|
||||
* Returns the inverse of this boolean.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I32_EQZ)
|
||||
public operator fun not(): Boolean
|
||||
@WasmOp(WasmOp.I32_EQZ)
|
||||
public operator fun not(): Boolean =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/**
|
||||
* Performs a logical `and` operation between this Boolean and the [other] one. Unlike the `&&` operator,
|
||||
* this function does not perform short-circuit evaluation. Both `this` and [other] will always be evaluated.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I32_AND)
|
||||
public infix fun and(other: Boolean): Boolean
|
||||
@WasmOp(WasmOp.I32_AND)
|
||||
public infix fun and(other: Boolean): Boolean =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/**
|
||||
* Performs a logical `or` operation between this Boolean and the [other] one. Unlike the `||` operator,
|
||||
* this function does not perform short-circuit evaluation. Both `this` and [other] will always be evaluated.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I32_OR)
|
||||
public infix fun or(other: Boolean): Boolean
|
||||
@WasmOp(WasmOp.I32_OR)
|
||||
public infix fun or(other: Boolean): Boolean =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/**
|
||||
* Performs a logical `xor` operation between this Boolean and the [other] one.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I32_XOR)
|
||||
public infix fun xor(other: Boolean): Boolean
|
||||
@WasmOp(WasmOp.I32_XOR)
|
||||
public infix fun xor(other: Boolean): Boolean =
|
||||
implementedAsIntrinsic
|
||||
|
||||
public override fun compareTo(other: Boolean): Int =
|
||||
wasm_i32_compareTo(this.asInt(), other.asInt())
|
||||
wasm_i32_compareTo(this.toInt(), other.toInt())
|
||||
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
internal fun asInt(): Int
|
||||
override fun toString(): String =
|
||||
if (this) "true" else "false"
|
||||
|
||||
override fun hashCode(): Int =
|
||||
toInt()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return if (other !is Boolean) {
|
||||
false
|
||||
} else {
|
||||
this === (other as Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
@WasmReinterpret
|
||||
internal fun toInt(): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@SinceKotlin("1.3")
|
||||
companion object {}
|
||||
public companion object
|
||||
}
|
||||
+31
-13
@@ -3,30 +3,34 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.wasm.internal.ExcludedFromCodegen
|
||||
import kotlin.wasm.internal.WasmInstruction
|
||||
import kotlin.wasm.internal.implementedAsIntrinsic
|
||||
import kotlin.wasm.internal.wasm_i32_compareTo
|
||||
import kotlin.wasm.internal.*
|
||||
|
||||
/**
|
||||
* Represents a 16-bit Unicode character.
|
||||
*
|
||||
* On the JVM, non-nullable values of this type are represented as values of the primitive type `char`.
|
||||
*/
|
||||
public class Char private constructor() : Comparable<Char> {
|
||||
@WasmPrimitive
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public class Char private constructor(public val value: Char) : Comparable<Char> {
|
||||
/**
|
||||
* Compares this value with the specified value for order.
|
||||
*
|
||||
* Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
|
||||
* or a positive number if it's greater than other.
|
||||
*/
|
||||
public override inline fun compareTo(other: Char): Int =
|
||||
public override fun compareTo(other: Char): Int =
|
||||
wasm_i32_compareTo(this.toInt(), other.toInt())
|
||||
|
||||
public override fun equals(other: Any?): Boolean {
|
||||
if (other is Char)
|
||||
return this === (other as Char)
|
||||
return false
|
||||
}
|
||||
|
||||
/** Adds the other Int value to this value resulting a Char. */
|
||||
public inline operator fun plus(other: Int): Char =
|
||||
(this.toInt() + other).toChar()
|
||||
@@ -47,34 +51,46 @@ public class Char private constructor() : Comparable<Char> {
|
||||
public inline operator fun dec(): Char =
|
||||
(this.toInt() - 1).toChar()
|
||||
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Char): CharRange
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Char): CharRange =
|
||||
CharRange(this, other)
|
||||
|
||||
/** Returns the value of this character as a `Byte`. */
|
||||
public inline fun toByte(): Byte =
|
||||
this.toInt().toByte()
|
||||
|
||||
/** Returns the value of this character as a `Char`. */
|
||||
public inline fun toChar(): Char =
|
||||
this
|
||||
|
||||
/** Returns the value of this character as a `Short`. */
|
||||
public inline fun toShort(): Short =
|
||||
this.toInt().toShort()
|
||||
|
||||
/** Returns the value of this character as a `Int`. */
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
@WasmReinterpret
|
||||
public fun toInt(): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Returns the value of this character as a `Long`. */
|
||||
public inline fun toLong(): Long =
|
||||
this.toInt().toLong()
|
||||
|
||||
/** Returns the value of this character as a `Float`. */
|
||||
public inline fun toFloat(): Float =
|
||||
this.toInt().toFloat()
|
||||
|
||||
/** Returns the value of this character as a `Double`. */
|
||||
public inline fun toDouble(): Double =
|
||||
this.toInt().toDouble()
|
||||
|
||||
@ExcludedFromCodegen
|
||||
companion object {
|
||||
override fun toString(): String =
|
||||
charToString(this)
|
||||
|
||||
override fun hashCode(): Int =
|
||||
this.toInt().hashCode()
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* The minimum value of a character code unit.
|
||||
*/
|
||||
@@ -129,6 +145,8 @@ public class Char private constructor() : Comparable<Char> {
|
||||
@SinceKotlin("1.3")
|
||||
public const val SIZE_BITS: Int = 16
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@WasmImport("runtime", "Char_toString")
|
||||
private fun charToString(c: Char): String = implementedAsIntrinsic
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 kotlin
|
||||
|
||||
public abstract class Enum<E : Enum<E>>(
|
||||
public val name: String,
|
||||
public val ordinal: Int
|
||||
) : Comparable<E> {
|
||||
|
||||
override fun compareTo(other: E): Int =
|
||||
ordinal.compareTo(other.ordinal)
|
||||
|
||||
override fun toString(): String =
|
||||
name
|
||||
|
||||
public companion object
|
||||
}
|
||||
+21
-17
@@ -2,86 +2,90 @@
|
||||
* Copyright 2010-2019 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.
|
||||
*/
|
||||
@file:Suppress(
|
||||
"NON_MEMBER_FUNCTION_NO_BODY",
|
||||
"REIFIED_TYPE_PARAMETER_NO_INLINE"
|
||||
)
|
||||
@file:kotlin.wasm.internal.ExcludedFromCodegen
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.internal.PureReifiable
|
||||
|
||||
public inline fun <T> emptyArray(): Array<T> = arrayOf()
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object. Can be called with a null receiver, in which case
|
||||
* it returns the string "null".
|
||||
*/
|
||||
public fun Any?.toString(): String
|
||||
public fun Any?.toString(): String = this?.toString() ?: "null"
|
||||
|
||||
/**
|
||||
* Concatenates this string with the string representation of the given [other] object. If either the receiver
|
||||
* or the [other] object are null, they are represented as the string "null".
|
||||
*/
|
||||
public operator fun String?.plus(other: Any?): String
|
||||
public operator fun String?.plus(other: Any?): String = (this ?: "null") + other.toString()
|
||||
|
||||
/**
|
||||
* Returns an array of objects of the given type with the given [size], initialized with null values.
|
||||
*/
|
||||
public fun <reified @PureReifiable T> arrayOfNulls(size: Int): Array<T?>
|
||||
// TODO: Should T be reified?
|
||||
@Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE")
|
||||
public fun <@PureReifiable reified T> arrayOfNulls(size: Int): Array<T?> = Array(size) { null }
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified elements.
|
||||
*/
|
||||
public inline fun <reified @PureReifiable T> arrayOf(vararg elements: T): Array<T>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline fun <T> arrayOf(vararg elements: T): Array<T> = elements as Array<T>
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified [Double] numbers.
|
||||
*/
|
||||
public fun doubleArrayOf(vararg elements: Double): DoubleArray
|
||||
public inline fun doubleArrayOf(vararg elements: Double): DoubleArray = elements
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified [Float] numbers.
|
||||
*/
|
||||
public fun floatArrayOf(vararg elements: Float): FloatArray
|
||||
public inline fun floatArrayOf(vararg elements: Float): FloatArray = elements
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified [Long] numbers.
|
||||
*/
|
||||
public fun longArrayOf(vararg elements: Long): LongArray
|
||||
public inline fun longArrayOf(vararg elements: Long): LongArray = elements
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified [Int] numbers.
|
||||
*/
|
||||
public fun intArrayOf(vararg elements: Int): IntArray
|
||||
public inline fun intArrayOf(vararg elements: Int): IntArray = elements
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified characters.
|
||||
*/
|
||||
public fun charArrayOf(vararg elements: Char): CharArray
|
||||
public inline fun charArrayOf(vararg elements: Char): CharArray = elements
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified [Short] numbers.
|
||||
*/
|
||||
public fun shortArrayOf(vararg elements: Short): ShortArray
|
||||
public inline fun shortArrayOf(vararg elements: Short): ShortArray = elements
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified [Byte] numbers.
|
||||
*/
|
||||
public fun byteArrayOf(vararg elements: Byte): ByteArray
|
||||
public inline fun byteArrayOf(vararg elements: Byte): ByteArray = elements
|
||||
|
||||
/**
|
||||
* Returns an array containing the specified boolean values.
|
||||
*/
|
||||
public fun booleanArrayOf(vararg elements: Boolean): BooleanArray
|
||||
public inline fun booleanArrayOf(vararg elements: Boolean): BooleanArray = elements
|
||||
|
||||
/**
|
||||
* Returns an array containing enum T entries.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@Suppress("NON_MEMBER_FUNCTION_NO_BODY")
|
||||
public inline fun <reified T : Enum<T>> enumValues(): Array<T>
|
||||
|
||||
/**
|
||||
* Returns an enum entry with specified name.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@Suppress("NON_MEMBER_FUNCTION_NO_BODY")
|
||||
public inline fun <reified T : Enum<T>> enumValueOf(name: String): T
|
||||
+3
@@ -16,8 +16,11 @@
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.wasm.internal.ExcludedFromCodegen
|
||||
|
||||
/**
|
||||
* Nothing has no instances. You can use Nothing to represent "a value that never exists": for example,
|
||||
* if a function has the return type of Nothing, it means that it never returns (always throws an exception).
|
||||
*/
|
||||
@ExcludedFromCodegen
|
||||
public class Nothing private constructor()
|
||||
+269
-209
@@ -2,7 +2,11 @@
|
||||
* Copyright 2010-2019 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.
|
||||
*/
|
||||
@file:Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
|
||||
@file:Suppress(
|
||||
"OVERRIDE_BY_INLINE",
|
||||
"NOTHING_TO_INLINE",
|
||||
"unused"
|
||||
)
|
||||
|
||||
package kotlin
|
||||
|
||||
@@ -11,9 +15,9 @@ import kotlin.wasm.internal.*
|
||||
/**
|
||||
* Represents a 8-bit signed integer.
|
||||
*/
|
||||
public class Byte private constructor() : Number(), Comparable<Byte> {
|
||||
@ExcludedFromCodegen
|
||||
companion object {
|
||||
@WasmPrimitive
|
||||
public class Byte private constructor(public val value: Byte) : Number(), Comparable<Byte> {
|
||||
public companion object {
|
||||
/**
|
||||
* A constant holding the minimum value an instance of Byte can have.
|
||||
*/
|
||||
@@ -233,8 +237,7 @@ public class Byte private constructor() : Number(), Comparable<Byte> {
|
||||
* The least significant 8 bits of the resulting `Char` code are the same as the bits of this `Byte` value,
|
||||
* whereas the most significant 8 bits are filled with the sign bit of this value.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
public override fun toChar(): Char = implementedAsIntrinsic
|
||||
public override fun toChar(): Char = reinterpretAsInt().reinterpretAsChar()
|
||||
|
||||
/**
|
||||
* Converts this [Byte] value to [Short].
|
||||
@@ -244,8 +247,7 @@ public class Byte private constructor() : Number(), Comparable<Byte> {
|
||||
* The least significant 8 bits of the resulting `Short` value are the same as the bits of this `Byte` value,
|
||||
* whereas the most significant 8 bits are filled with the sign bit of this value.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
public override fun toShort(): Short = implementedAsIntrinsic
|
||||
public override fun toShort(): Short = reinterpretAsInt().reinterpretAsShort()
|
||||
|
||||
/**
|
||||
* Converts this [Byte] value to [Int].
|
||||
@@ -255,8 +257,7 @@ public class Byte private constructor() : Number(), Comparable<Byte> {
|
||||
* The least significant 8 bits of the resulting `Int` value are the same as the bits of this `Byte` value,
|
||||
* whereas the most significant 24 bits are filled with the sign bit of this value.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
public override fun toInt(): Int = implementedAsIntrinsic
|
||||
public override fun toInt(): Int = reinterpretAsInt()
|
||||
|
||||
/**
|
||||
* Converts this [Byte] value to [Long].
|
||||
@@ -266,62 +267,93 @@ public class Byte private constructor() : Number(), Comparable<Byte> {
|
||||
* The least significant 8 bits of the resulting `Long` value are the same as the bits of this `Byte` value,
|
||||
* whereas the most significant 56 bits are filled with the sign bit of this value.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I64_EXTEND_I32_S)
|
||||
public override fun toLong(): Long = implementedAsIntrinsic
|
||||
public override fun toLong(): Long = wasm_i64_extend_i32_s(this.toInt())
|
||||
|
||||
/**
|
||||
* Converts this [Byte] value to [Float].
|
||||
*
|
||||
* The resulting `Float` value represents the same numerical value as this `Byte`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F32_CONVERT_I32_S)
|
||||
public override fun toFloat(): Float = implementedAsIntrinsic
|
||||
public override fun toFloat(): Float = wasm_f32_convert_i32_s(this.toInt())
|
||||
|
||||
/**
|
||||
* Converts this [Byte] value to [Double].
|
||||
*
|
||||
* The resulting `Double` value represents the same numerical value as this `Byte`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F64_CONVERT_I32_S)
|
||||
public override fun toDouble(): Double = implementedAsIntrinsic
|
||||
public override fun toDouble(): Double = wasm_f64_convert_i32_s(this.toInt())
|
||||
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Byte): IntRange {
|
||||
// return IntRange(this.toInt(), other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Short): IntRange {
|
||||
// return IntRange(this.toInt(), other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Int): IntRange {
|
||||
// return IntRange(this.toInt(), other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Long): LongRange {
|
||||
// return LongRange(this.toLong(), other.toLong())
|
||||
// }
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Byte): IntRange {
|
||||
return IntRange(this.toInt(), other.toInt())
|
||||
}
|
||||
|
||||
// TODO: Support Any? and type operators
|
||||
// public override fun equals(other: Any?): Boolean =
|
||||
// other is Byte && wasm_i32_eq(this.toInt(), other.toInt()).reinterpretAsBoolean()
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Short): IntRange {
|
||||
return IntRange(this.toInt(), other.toInt())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Int): IntRange {
|
||||
return IntRange(this.toInt(), other.toInt())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Long): LongRange {
|
||||
return LongRange(this.toLong(), other.toLong())
|
||||
}
|
||||
|
||||
/** Performs a bitwise AND operation between the two values. */
|
||||
@SinceKotlin("1.1")
|
||||
@WasmOp(WasmOp.I32_AND)
|
||||
public infix fun and(other: Byte): Byte =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise OR operation between the two values. */
|
||||
@SinceKotlin("1.1")
|
||||
@WasmOp(WasmOp.I32_OR)
|
||||
public infix fun or(other: Byte): Byte =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise XOR operation between the two values. */
|
||||
@SinceKotlin("1.1")
|
||||
@WasmOp(WasmOp.I32_XOR)
|
||||
public infix fun xor(other: Byte): Byte =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Inverts the bits in this value/ */
|
||||
@SinceKotlin("1.1")
|
||||
public inline fun inv(): Byte = this.xor(-1)
|
||||
|
||||
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Byte && wasm_i32_eq(this.toInt(), other.toInt())
|
||||
|
||||
public inline fun equals(other: Byte): Boolean =
|
||||
wasm_i32_eq(this.toInt(), other.toInt()).reinterpretAsBoolean()
|
||||
wasm_i32_eq(this.toInt(), other.toInt())
|
||||
|
||||
// TODO: Implement Byte.toString()
|
||||
// public override fun toString(): String
|
||||
public override fun toString(): String =
|
||||
byteToStringImpl(this)
|
||||
|
||||
public override inline fun hashCode(): Int =
|
||||
this.toInt()
|
||||
|
||||
@WasmReinterpret
|
||||
@PublishedApi
|
||||
internal fun reinterpretAsInt(): Int =
|
||||
implementedAsIntrinsic
|
||||
}
|
||||
|
||||
@WasmImport("runtime", "coerceToString")
|
||||
private fun byteToStringImpl(byte: Byte): String =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/**
|
||||
* Represents a 16-bit signed integer.
|
||||
*/
|
||||
public class Short private constructor() : Number(), Comparable<Short> {
|
||||
@ExcludedFromCodegen
|
||||
companion object {
|
||||
@WasmPrimitive
|
||||
public class Short private constructor(public val value: Short) : Number(), Comparable<Short> {
|
||||
public companion object {
|
||||
/**
|
||||
* A constant holding the minimum value an instance of Short can have.
|
||||
*/
|
||||
@@ -529,22 +561,48 @@ public class Short private constructor() : Number(), Comparable<Short> {
|
||||
public inline operator fun unaryMinus(): Int =
|
||||
-this.toInt()
|
||||
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Byte): IntRange {
|
||||
// return IntRange(this.toInt(), other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Short): IntRange {
|
||||
// return IntRange(this.toInt(), other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Int): IntRange {
|
||||
// return IntRange(this.toInt(), other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Long): LongRange {
|
||||
// return LongRange(this.toLong(), other.toLong())
|
||||
// }
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Byte): IntRange {
|
||||
return IntRange(this.toInt(), other.toInt())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Short): IntRange {
|
||||
return IntRange(this.toInt(), other.toInt())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Int): IntRange {
|
||||
return IntRange(this.toInt(), other)
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Long): LongRange {
|
||||
return LongRange(this.toLong(), other)
|
||||
}
|
||||
|
||||
/** Performs a bitwise AND operation between the two values. */
|
||||
@SinceKotlin("1.1")
|
||||
@WasmOp(WasmOp.I32_AND)
|
||||
public infix fun and(other: Short): Short =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise OR operation between the two values. */
|
||||
@SinceKotlin("1.1")
|
||||
@WasmOp(WasmOp.I32_OR)
|
||||
public infix fun or(other: Short): Short =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise XOR operation between the two values. */
|
||||
@SinceKotlin("1.1")
|
||||
@WasmOp(WasmOp.I32_XOR)
|
||||
public infix fun xor(other: Short): Short =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Inverts the bits in this value */
|
||||
@SinceKotlin("1.1")
|
||||
public fun inv(): Short =
|
||||
this.xor(-1)
|
||||
|
||||
/**
|
||||
* Converts this [Short] value to [Byte].
|
||||
@@ -563,9 +621,7 @@ public class Short private constructor() : Number(), Comparable<Short> {
|
||||
* The resulting `Char` code is equal to this value reinterpreted as an unsigned number,
|
||||
* i.e. it has the same binary representation as this `Short`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
public override fun toChar(): Char =
|
||||
implementedAsIntrinsic
|
||||
public override fun toChar(): Char = reinterpretAsInt().reinterpretAsChar()
|
||||
|
||||
/** Returns this value. */
|
||||
public override inline fun toShort(): Short =
|
||||
@@ -579,9 +635,7 @@ public class Short private constructor() : Number(), Comparable<Short> {
|
||||
* The least significant 16 bits of the resulting `Int` value are the same as the bits of this `Short` value,
|
||||
* whereas the most significant 16 bits are filled with the sign bit of this value.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
public override fun toInt(): Int =
|
||||
implementedAsIntrinsic
|
||||
public override fun toInt(): Int = reinterpretAsInt()
|
||||
|
||||
/**
|
||||
* Converts this [Short] value to [Long].
|
||||
@@ -591,49 +645,50 @@ public class Short private constructor() : Number(), Comparable<Short> {
|
||||
* The least significant 16 bits of the resulting `Long` value are the same as the bits of this `Short` value,
|
||||
* whereas the most significant 48 bits are filled with the sign bit of this value.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I64_EXTEND_I32_S)
|
||||
public override fun toLong(): Long =
|
||||
implementedAsIntrinsic
|
||||
public override fun toLong(): Long = wasm_i64_extend_i32_s(this.toInt())
|
||||
|
||||
/**
|
||||
* Converts this [Short] value to [Float].
|
||||
*
|
||||
* The resulting `Float` value represents the same numerical value as this `Short`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F32_CONVERT_I32_S)
|
||||
public override fun toFloat(): Float =
|
||||
implementedAsIntrinsic
|
||||
public override fun toFloat(): Float = wasm_f32_convert_i32_s(this.toInt())
|
||||
|
||||
/**
|
||||
* Converts this [Short] value to [Double].
|
||||
*
|
||||
* The resulting `Double` value represents the same numerical value as this `Short`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F64_CONVERT_I32_S)
|
||||
public override fun toDouble(): Double =
|
||||
implementedAsIntrinsic
|
||||
wasm_f64_convert_i32_s(this.toInt())
|
||||
|
||||
public inline fun equals(other: Short): Boolean =
|
||||
wasm_i32_eq(this.toInt(), other.toInt()).reinterpretAsBoolean()
|
||||
wasm_i32_eq(this.toInt(), other.toInt())
|
||||
|
||||
// TODO: Support Any? and type operators
|
||||
// public override fun equals(other: Any?): Boolean =
|
||||
// other is Short && wasm_i32_eq(this.toInt(), other.toInt()).reinterpretAsBoolean()
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Short && wasm_i32_eq(this.toInt(), other.toInt())
|
||||
|
||||
// TODO: Implement Short.toString()
|
||||
// public override fun toString(): String
|
||||
public override fun toString(): String = shortToStringImpl(this)
|
||||
|
||||
public override inline fun hashCode(): Int =
|
||||
this.toInt()
|
||||
|
||||
@WasmReinterpret
|
||||
@PublishedApi
|
||||
internal fun reinterpretAsInt(): Int =
|
||||
implementedAsIntrinsic
|
||||
}
|
||||
|
||||
@WasmImport("runtime", "coerceToString")
|
||||
private fun shortToStringImpl(x: Short): String = implementedAsIntrinsic
|
||||
|
||||
/**
|
||||
* Represents a 32-bit signed integer.
|
||||
*/
|
||||
public class Int private constructor() : Number(), Comparable<Int> {
|
||||
@WasmPrimitive
|
||||
public class Int private constructor(val value: Int) : Number(), Comparable<Int> {
|
||||
|
||||
@ExcludedFromCodegen
|
||||
companion object {
|
||||
public companion object {
|
||||
/**
|
||||
* A constant holding the minimum value an instance of Int can have.
|
||||
*/
|
||||
@@ -714,7 +769,7 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
this + other.toInt()
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
@WasmInstruction(WasmInstruction.I32_ADD)
|
||||
@WasmOp(WasmOp.I32_ADD)
|
||||
public operator fun plus(other: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -739,7 +794,7 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
this - other.toInt()
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
@WasmInstruction(WasmInstruction.I32_SUB)
|
||||
@WasmOp(WasmOp.I32_SUB)
|
||||
public operator fun minus(other: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -764,7 +819,7 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
this * other.toInt()
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.I32_MUL)
|
||||
@WasmOp(WasmOp.I32_MUL)
|
||||
public operator fun times(other: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -789,7 +844,7 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
this / other.toInt()
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.I32_DIV_S)
|
||||
@WasmOp(WasmOp.I32_DIV_S)
|
||||
public operator fun div(other: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -814,7 +869,7 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
this % other.toInt()
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.I32_REM_S)
|
||||
@WasmOp(WasmOp.I32_REM_S)
|
||||
public operator fun rem(other: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -835,7 +890,8 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
this + 1
|
||||
|
||||
/** Decrements this value. */
|
||||
public inline operator fun dec(): Int =
|
||||
// TODO: Fix test compiler/testData/codegen/box/functions/invoke/invoke.kt with inline dec
|
||||
public operator fun dec(): Int =
|
||||
this - 1
|
||||
|
||||
/** Returns this value. */
|
||||
@@ -850,7 +906,7 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
* Note that only the five lowest-order bits of the [bitCount] are used as the shift distance.
|
||||
* The shift distance actually used is therefore always in the range `0..31`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I32_SHL)
|
||||
@WasmOp(WasmOp.I32_SHL)
|
||||
public infix fun shl(bitCount: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -860,7 +916,7 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
* Note that only the five lowest-order bits of the [bitCount] are used as the shift distance.
|
||||
* The shift distance actually used is therefore always in the range `0..31`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I32_SHR_S)
|
||||
@WasmOp(WasmOp.I32_SHR_S)
|
||||
public infix fun shr(bitCount: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -870,22 +926,22 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
* Note that only the five lowest-order bits of the [bitCount] are used as the shift distance.
|
||||
* The shift distance actually used is therefore always in the range `0..31`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I32_SHR_U)
|
||||
@WasmOp(WasmOp.I32_SHR_U)
|
||||
public infix fun ushr(bitCount: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise AND operation between the two values. */
|
||||
@WasmInstruction(WasmInstruction.I32_AND)
|
||||
@WasmOp(WasmOp.I32_AND)
|
||||
public infix fun and(other: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise OR operation between the two values. */
|
||||
@WasmInstruction(WasmInstruction.I32_OR)
|
||||
@WasmOp(WasmOp.I32_OR)
|
||||
public infix fun or(other: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise XOR operation between the two values. */
|
||||
@WasmInstruction(WasmInstruction.I32_XOR)
|
||||
@WasmOp(WasmOp.I32_XOR)
|
||||
public infix fun xor(other: Int): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -893,22 +949,25 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
public inline fun inv(): Int =
|
||||
this.xor(-1)
|
||||
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Byte): IntRange {
|
||||
// return IntRange(this, other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Short): IntRange {
|
||||
// return IntRange(this, other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Int): IntRange {
|
||||
// return IntRange(this, other.toInt())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Long): LongRange {
|
||||
// return LongRange(this.toLong(), other.toLong())
|
||||
// }
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Byte): IntRange {
|
||||
return IntRange(this, other.toInt())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Short): IntRange {
|
||||
return IntRange(this, other.toInt())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Int): IntRange {
|
||||
return IntRange(this, other.toInt())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Long): LongRange {
|
||||
return LongRange(this.toLong(), other.toLong())
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this [Int] value to [Byte].
|
||||
@@ -955,9 +1014,8 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
* The least significant 32 bits of the resulting `Long` value are the same as the bits of this `Int` value,
|
||||
* whereas the most significant 32 bits are filled with the sign bit of this value.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I64_EXTEND_I32_S)
|
||||
public override fun toLong(): Long =
|
||||
implementedAsIntrinsic
|
||||
wasm_i64_extend_i32_s(this)
|
||||
|
||||
/**
|
||||
* Converts this [Int] value to [Float].
|
||||
@@ -966,60 +1024,61 @@ public class Int private constructor() : Number(), Comparable<Int> {
|
||||
* In case when this `Int` value is exactly between two `Float`s,
|
||||
* the one with zero at least significant bit of mantissa is selected.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F32_CONVERT_I32_S)
|
||||
public override fun toFloat(): Float =
|
||||
implementedAsIntrinsic
|
||||
wasm_f32_convert_i32_s(this)
|
||||
|
||||
/**
|
||||
* Converts this [Int] value to [Double].
|
||||
*
|
||||
* The resulting `Double` value represents the same numerical value as this `Int`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F64_CONVERT_I32_S)
|
||||
public override fun toDouble(): Double =
|
||||
implementedAsIntrinsic
|
||||
wasm_f64_convert_i32_s(this)
|
||||
|
||||
public inline fun equals(other: Int): Boolean =
|
||||
wasm_i32_eq(this, other).reinterpretAsBoolean()
|
||||
wasm_i32_eq(this, other)
|
||||
|
||||
// TODO: Support Any? and type operators
|
||||
// public override fun equals(other: Any?): Boolean =
|
||||
// other is Int && wasm_i32_eq(this, other).reinterpretAsBoolean()
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Int && wasm_i32_eq(this, other)
|
||||
|
||||
// TODO: Implement Int.toString()
|
||||
// public override fun toString(): String
|
||||
public override fun toString(): String =
|
||||
intToStringImpl(this)
|
||||
|
||||
public override inline fun hashCode(): Int =
|
||||
this
|
||||
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
@WasmReinterpret
|
||||
@PublishedApi
|
||||
internal fun reinterpretAsBoolean(): Boolean =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@PublishedApi
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
@WasmReinterpret
|
||||
internal fun reinterpretAsByte(): Byte =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@PublishedApi
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
@WasmReinterpret
|
||||
internal fun reinterpretAsShort(): Short =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@PublishedApi
|
||||
@WasmInstruction(WasmInstruction.NOP)
|
||||
@WasmReinterpret
|
||||
internal fun reinterpretAsChar(): Char =
|
||||
implementedAsIntrinsic
|
||||
}
|
||||
|
||||
@WasmImport("runtime", "coerceToString")
|
||||
private fun intToStringImpl(x: Int): String =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/**
|
||||
* Represents a 64-bit signed integer.
|
||||
*/
|
||||
public class Long private constructor() : Number(), Comparable<Long> {
|
||||
@WasmPrimitive
|
||||
public class Long private constructor(val value: Long) : Number(), Comparable<Long> {
|
||||
|
||||
@ExcludedFromCodegen
|
||||
companion object {
|
||||
public companion object {
|
||||
/**
|
||||
* A constant holding the minimum value an instance of Long can have.
|
||||
*/
|
||||
@@ -1104,7 +1163,7 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
this + other.toLong()
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
@WasmInstruction(WasmInstruction.I64_ADD)
|
||||
@WasmOp(WasmOp.I64_ADD)
|
||||
public operator fun plus(other: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1129,7 +1188,7 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
this - other.toLong()
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
@WasmInstruction(WasmInstruction.I64_SUB)
|
||||
@WasmOp(WasmOp.I64_SUB)
|
||||
public operator fun minus(other: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1154,7 +1213,7 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
this * other.toLong()
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.I64_MUL)
|
||||
@WasmOp(WasmOp.I64_MUL)
|
||||
public operator fun times(other: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1179,7 +1238,7 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
this / other.toLong()
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.I64_DIV_S)
|
||||
@WasmOp(WasmOp.I64_DIV_S)
|
||||
public operator fun div(other: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1204,7 +1263,7 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
this % other.toLong()
|
||||
|
||||
/** Calculates the remainder of dividing this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.I64_REM_S)
|
||||
@WasmOp(WasmOp.I64_REM_S)
|
||||
public operator fun rem(other: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1231,22 +1290,25 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
/** Returns the negative of this value. */
|
||||
public inline operator fun unaryMinus(): Long = 0L - this
|
||||
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Byte): LongRange {
|
||||
// return LongRange(this, other.toLong())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Short): LongRange {
|
||||
// return LongRange(this, other.toLong())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Int): LongRange {
|
||||
// return LongRange(this, other.toLong())
|
||||
// }
|
||||
// /** Creates a range from this value to the specified [other] value. */
|
||||
// public operator fun rangeTo(other: Long): LongRange {
|
||||
// return LongRange(this, other.toLong())
|
||||
// }
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Byte): LongRange {
|
||||
return LongRange(this, other.toLong())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Short): LongRange {
|
||||
return LongRange(this, other.toLong())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Int): LongRange {
|
||||
return LongRange(this, other.toLong())
|
||||
}
|
||||
|
||||
/** Creates a range from this value to the specified [other] value. */
|
||||
public operator fun rangeTo(other: Long): LongRange {
|
||||
return LongRange(this, other.toLong())
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts this value left by the [bitCount] number of bits.
|
||||
@@ -1276,17 +1338,17 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
wasm_i64_shr_u(this, bitCount.toLong())
|
||||
|
||||
/** Performs a bitwise AND operation between the two values. */
|
||||
@WasmInstruction(WasmInstruction.I64_AND)
|
||||
@WasmOp(WasmOp.I64_AND)
|
||||
public infix fun and(other: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise OR operation between the two values. */
|
||||
@WasmInstruction(WasmInstruction.I64_OR)
|
||||
@WasmOp(WasmOp.I64_OR)
|
||||
public infix fun or(other: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/** Performs a bitwise XOR operation between the two values. */
|
||||
@WasmInstruction(WasmInstruction.I64_XOR)
|
||||
@WasmOp(WasmOp.I64_XOR)
|
||||
public infix fun xor(other: Long): Long =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1335,9 +1397,8 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
*
|
||||
* The resulting `Int` value is represented by the least significant 32 bits of this `Long` value.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.I32_WRAP_I64)
|
||||
public override fun toInt(): Int =
|
||||
implementedAsIntrinsic
|
||||
wasm_i32_wrap_i64(this)
|
||||
|
||||
/** Returns this value. */
|
||||
public override inline fun toLong(): Long =
|
||||
@@ -1350,9 +1411,8 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
* In case when this `Long` value is exactly between two `Float`s,
|
||||
* the one with zero at least significant bit of mantissa is selected.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F32_CONVERT_I64_S)
|
||||
public override fun toFloat(): Float =
|
||||
implementedAsIntrinsic
|
||||
wasm_f32_convert_i64_s(this)
|
||||
|
||||
/**
|
||||
* Converts this [Long] value to [Double].
|
||||
@@ -1361,19 +1421,18 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
* In case when this `Long` value is exactly between two `Double`s,
|
||||
* the one with zero at least significant bit of mantissa is selected.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F64_CONVERT_I64_S)
|
||||
public override fun toDouble(): Double =
|
||||
implementedAsIntrinsic
|
||||
wasm_f64_convert_i64_s(this)
|
||||
|
||||
public inline fun equals(other: Long): Boolean =
|
||||
wasm_i64_eq(this, other).reinterpretAsBoolean()
|
||||
wasm_i64_eq(this, other)
|
||||
|
||||
// TODO: Support Any? and type operators
|
||||
// public override fun equals(other: Any?): Boolean =
|
||||
// other is Long && wasm_i64_eq(this, other).reinterpretAsBoolean()
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Long && wasm_i64_eq(this, other)
|
||||
|
||||
// TODO: Implement Long.toString()
|
||||
// public override fun toString(): String
|
||||
// TODO: Implement proper Long.toString
|
||||
public override fun toString(): String =
|
||||
toDouble().toString()
|
||||
|
||||
public override fun hashCode(): Int =
|
||||
((this ushr 32) xor this).toInt()
|
||||
@@ -1382,10 +1441,10 @@ public class Long private constructor() : Number(), Comparable<Long> {
|
||||
/**
|
||||
* Represents a single-precision 32-bit IEEE 754 floating point number.
|
||||
*/
|
||||
public class Float private constructor() : Number(), Comparable<Float> {
|
||||
@WasmPrimitive
|
||||
public class Float private constructor(public val value: Float) : Number(), Comparable<Float> {
|
||||
|
||||
@ExcludedFromCodegen
|
||||
companion object {
|
||||
public companion object {
|
||||
/**
|
||||
* A constant holding the smallest *positive* nonzero value of Float.
|
||||
*/
|
||||
@@ -1411,7 +1470,9 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
/**
|
||||
* A constant holding the "not a number" value of Float.
|
||||
*/
|
||||
public val NaN: Float = wasm_f32_const_nan()
|
||||
public val NaN: Float
|
||||
get() =
|
||||
wasm_float_nan()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1483,7 +1544,7 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
this + other.toFloat()
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
@WasmInstruction(WasmInstruction.F32_ADD)
|
||||
@WasmOp(WasmOp.F32_ADD)
|
||||
public operator fun plus(other: Float): Float =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1508,7 +1569,7 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
this - other.toFloat()
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
@WasmInstruction(WasmInstruction.F32_SUB)
|
||||
@WasmOp(WasmOp.F32_SUB)
|
||||
public operator fun minus(other: Float): Float =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1533,7 +1594,7 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
this * other.toFloat()
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.F32_MUL)
|
||||
@WasmOp(WasmOp.F32_MUL)
|
||||
public operator fun times(other: Float): Float =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1558,7 +1619,7 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
this / other.toFloat()
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.F32_DIV)
|
||||
@WasmOp(WasmOp.F32_DIV)
|
||||
public operator fun div(other: Float): Float =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1602,7 +1663,7 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
public inline operator fun unaryPlus(): Float = this
|
||||
|
||||
/** Returns the negative of this value. */
|
||||
@WasmInstruction(WasmInstruction.F32_NEG)
|
||||
@WasmOp(WasmOp.F32_NEG)
|
||||
public operator fun unaryMinus(): Float =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1634,10 +1695,8 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
* Returns zero if this `Float` value is `NaN`, [Int.MIN_VALUE] if it's less than `Int.MIN_VALUE`,
|
||||
* [Int.MAX_VALUE] if it's bigger than `Int.MAX_VALUE`.
|
||||
*/
|
||||
// TODO: Implement Float.toInt()
|
||||
public override fun toInt(): Int {
|
||||
wasm_unreachable()
|
||||
return 0
|
||||
return wasm_i32_trunc_sat_f32_s(this)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1647,10 +1706,8 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
* Returns zero if this `Float` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`,
|
||||
* [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`.
|
||||
*/
|
||||
// TODO: Implement Float.toLong()
|
||||
public override fun toLong(): Long {
|
||||
wasm_unreachable()
|
||||
return 0
|
||||
return wasm_i64_trunc_sat_f32_s(this)
|
||||
}
|
||||
|
||||
/** Returns this value. */
|
||||
@@ -1662,35 +1719,37 @@ public class Float private constructor() : Number(), Comparable<Float> {
|
||||
*
|
||||
* The resulting `Double` value represents the same numerical value as this `Float`.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F64_PROMOTE_F32)
|
||||
public override fun toDouble(): Double =
|
||||
implementedAsIntrinsic
|
||||
wasm_f64_promote_f32(this)
|
||||
|
||||
public inline fun equals(other: Float): Boolean =
|
||||
bits() == other.bits()
|
||||
|
||||
// TODO: Support Any? and type operators
|
||||
// public override fun equals(other: Any?): Boolean =
|
||||
// other is Float && this.equals(other)
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Float && this.equals(other)
|
||||
|
||||
// TODO: Implement Float.toString()
|
||||
// public override fun toString(): String
|
||||
public override fun toString(): String =
|
||||
floatToStringImpl(this)
|
||||
|
||||
public override inline fun hashCode(): Int =
|
||||
bits()
|
||||
|
||||
@PublishedApi
|
||||
@WasmInstruction(WasmInstruction.I32_REINTERPRET_F32)
|
||||
@WasmOp(WasmOp.I32_REINTERPRET_F32)
|
||||
internal fun bits(): Int = implementedAsIntrinsic
|
||||
}
|
||||
|
||||
@WasmImport("runtime", "coerceToString")
|
||||
private fun floatToStringImpl(x: Float): String =
|
||||
implementedAsIntrinsic
|
||||
|
||||
/**
|
||||
* Represents a double-precision 64-bit IEEE 754 floating point number.
|
||||
*/
|
||||
public class Double private constructor() : Number(), Comparable<Double> {
|
||||
@WasmPrimitive
|
||||
public class Double private constructor(public val value: Double) : Number(), Comparable<Double> {
|
||||
|
||||
@ExcludedFromCodegen
|
||||
companion object {
|
||||
public companion object {
|
||||
/**
|
||||
* A constant holding the smallest *positive* nonzero value of Double.
|
||||
*/
|
||||
@@ -1716,7 +1775,10 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
/**
|
||||
* A constant holding the "not a number" value of Double.
|
||||
*/
|
||||
public val NaN: Double = wasm_f64_const_nan()
|
||||
public val NaN: Double
|
||||
get() =
|
||||
wasm_double_nan()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1792,7 +1854,7 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
this + other.toDouble()
|
||||
|
||||
/** Adds the other value to this value. */
|
||||
@WasmInstruction(WasmInstruction.F64_ADD)
|
||||
@WasmOp(WasmOp.F64_ADD)
|
||||
public operator fun plus(other: Double): Double =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1817,7 +1879,7 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
this - other.toDouble()
|
||||
|
||||
/** Subtracts the other value from this value. */
|
||||
@WasmInstruction(WasmInstruction.F64_SUB)
|
||||
@WasmOp(WasmOp.F64_SUB)
|
||||
public operator fun minus(other: Double): Double =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1842,7 +1904,7 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
this * other.toDouble()
|
||||
|
||||
/** Multiplies this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.F64_MUL)
|
||||
@WasmOp(WasmOp.F64_MUL)
|
||||
public operator fun times(other: Double): Double =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1867,7 +1929,7 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
this / other.toDouble()
|
||||
|
||||
/** Divides this value by the other value. */
|
||||
@WasmInstruction(WasmInstruction.F64_DIV)
|
||||
@WasmOp(WasmOp.F64_DIV)
|
||||
public operator fun div(other: Double): Double =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1908,7 +1970,7 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
this
|
||||
|
||||
/** Returns the negative of this value. */
|
||||
@WasmInstruction(WasmInstruction.F64_NEG)
|
||||
@WasmOp(WasmOp.F64_NEG)
|
||||
public operator fun unaryMinus(): Double =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@@ -1940,10 +2002,8 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
* Returns zero if this `Double` value is `NaN`, [Int.MIN_VALUE] if it's less than `Int.MIN_VALUE`,
|
||||
* [Int.MAX_VALUE] if it's bigger than `Int.MAX_VALUE`.
|
||||
*/
|
||||
// TODO: Implement Double.toInt()
|
||||
public override fun toInt(): Int {
|
||||
wasm_unreachable()
|
||||
return 0
|
||||
return wasm_i32_trunc_sat_f64_s(this)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1953,10 +2013,8 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
* Returns zero if this `Double` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`,
|
||||
* [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`.
|
||||
*/
|
||||
// TODO: Implement Double.toLong()
|
||||
public override fun toLong(): Long {
|
||||
wasm_unreachable()
|
||||
return 0
|
||||
return wasm_i64_trunc_sat_f64_s(this)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1966,9 +2024,8 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
* In case when this `Double` value is exactly between two `Float`s,
|
||||
* the one with zero at least significant bit of mantissa is selected.
|
||||
*/
|
||||
@WasmInstruction(WasmInstruction.F32_DEMOTE_F64)
|
||||
public override fun toFloat(): Float =
|
||||
implementedAsIntrinsic
|
||||
wasm_f32_demote_f64(this)
|
||||
|
||||
/** Returns this value. */
|
||||
public override inline fun toDouble(): Double =
|
||||
@@ -1977,17 +2034,20 @@ public class Double private constructor() : Number(), Comparable<Double> {
|
||||
public inline fun equals(other: Double): Boolean =
|
||||
this.bits() == other.bits()
|
||||
|
||||
// TODO: Support Any? and type operators
|
||||
// public override fun equals(other: Any?): Boolean =
|
||||
// other is Double && this.bits() == other.bits()
|
||||
public override fun equals(other: Any?): Boolean =
|
||||
other is Double && this.bits() == other.bits()
|
||||
|
||||
// TODO: Implement Double.toString()
|
||||
// public override fun toString(): String
|
||||
public override fun toString(): String =
|
||||
doubleToStringImpl(this)
|
||||
|
||||
public override inline fun hashCode(): Int = bits().hashCode()
|
||||
|
||||
@PublishedApi
|
||||
@WasmInstruction(WasmInstruction.I64_REINTERPRET_F64)
|
||||
@WasmOp(WasmOp.I64_REINTERPRET_F64)
|
||||
internal fun bits(): Long =
|
||||
implementedAsIntrinsic
|
||||
}
|
||||
|
||||
@WasmImport("runtime", "coerceToString")
|
||||
private fun doubleToStringImpl(x: Double): String =
|
||||
implementedAsIntrinsic
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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 kotlin
|
||||
|
||||
import kotlin.wasm.internal.*
|
||||
|
||||
/**
|
||||
* The `String` class represents character strings. All string literals in Kotlin programs, such as `"abc"`, are
|
||||
* implemented as instances of this class.
|
||||
*/
|
||||
@WasmPrimitive
|
||||
public class String constructor(public val string: String) : Comparable<String>, CharSequence {
|
||||
public companion object;
|
||||
|
||||
/**
|
||||
* Returns a string obtained by concatenating this string with the string representation of the given [other] object.
|
||||
*/
|
||||
public operator fun plus(other: Any?): String =
|
||||
stringPlusImpl(this, other.toString())
|
||||
|
||||
public override val length: Int
|
||||
get() = stringLengthImpl(this)
|
||||
|
||||
/**
|
||||
* Returns the character of this string at the specified [index].
|
||||
*
|
||||
* If the [index] is out of bounds of this string, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public override fun get(index: Int): Char =
|
||||
stringGetCharImpl(this, index)
|
||||
|
||||
public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence =
|
||||
stringSubSequenceImpl(this, startIndex, endIndex)
|
||||
|
||||
public override fun compareTo(other: String): Int =
|
||||
stringCompareToImpl(this, other)
|
||||
|
||||
public override fun equals(other: Any?): Boolean {
|
||||
if (other is String)
|
||||
return this.compareTo(other) == 0
|
||||
return false
|
||||
}
|
||||
|
||||
public override fun toString(): String = this
|
||||
|
||||
// TODO: Implement
|
||||
public override fun hashCode(): Int = 10
|
||||
}
|
||||
|
||||
@WasmImport("runtime", "String_plus")
|
||||
private fun stringPlusImpl(it: String, other: String): String =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@WasmImport("runtime", "String_getLength")
|
||||
private fun stringLengthImpl(it: String): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@WasmImport("runtime", "String_getChar")
|
||||
private fun stringGetCharImpl(it: String, index: Int): Char =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@WasmImport("runtime", "String_compareTo")
|
||||
private fun stringCompareToImpl(it: String, other: String): Int =
|
||||
implementedAsIntrinsic
|
||||
|
||||
@WasmImport("runtime", "String_subsequence")
|
||||
private fun stringSubSequenceImpl(string: String, startIndex: Int, endIndex: Int): String =
|
||||
implementedAsIntrinsic
|
||||
@@ -1,13 +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 kotlin
|
||||
|
||||
/**
|
||||
* Base interface implicitly implemented by all annotation interfaces.
|
||||
* See [Kotlin language documentation](https://kotlinlang.org/docs/reference/annotations.html) for more information
|
||||
* on annotations.
|
||||
*/
|
||||
public interface Annotation
|
||||
@@ -1,313 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.
|
||||
*/
|
||||
|
||||
// Auto-generated file. DO NOT EDIT!
|
||||
|
||||
@file:Suppress(
|
||||
"NON_ABSTRACT_FUNCTION_WITH_NO_BODY",
|
||||
"MUST_BE_INITIALIZED_OR_BE_ABSTRACT",
|
||||
"EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE",
|
||||
"PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED",
|
||||
"WRONG_MODIFIER_TARGET"
|
||||
)
|
||||
|
||||
package kotlin
|
||||
|
||||
/**
|
||||
* An array of bytes. When targeting the JVM, instances of this class are represented as `byte[]`.
|
||||
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
|
||||
*/
|
||||
public class ByteArray(size: Int) {
|
||||
/**
|
||||
* Creates a new array of the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
*
|
||||
* The function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for an array element given its index.
|
||||
*/
|
||||
public inline constructor(size: Int, init: (Int) -> Byte)
|
||||
|
||||
/**
|
||||
* Returns the array element at the given [index]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun get(index: Int): Byte
|
||||
|
||||
/**
|
||||
* Sets the element at the given [index] to the given [value]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: Byte): Unit
|
||||
|
||||
/** Returns the number of elements in the array. */
|
||||
public val size: Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
public operator fun iterator(): ByteIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of chars. When targeting the JVM, instances of this class are represented as `char[]`.
|
||||
* @constructor Creates a new array of the specified [size], with all elements initialized to null char (`\u0000').
|
||||
*/
|
||||
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 function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for 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.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: Char): Unit
|
||||
|
||||
/** Returns the number of elements in the array. */
|
||||
public val size: Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
public operator fun iterator(): CharIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public class ShortArray(size: Int) {
|
||||
/**
|
||||
* Creates a new array of the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
*
|
||||
* The function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for an array element given its index.
|
||||
*/
|
||||
public inline constructor(size: Int, init: (Int) -> Short)
|
||||
|
||||
/**
|
||||
* Returns the array element at the given [index]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun get(index: Int): Short
|
||||
|
||||
/**
|
||||
* Sets the element at the given [index] to the given [value]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: Short): Unit
|
||||
|
||||
/** Returns the number of elements in the array. */
|
||||
public val size: Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
public operator fun iterator(): ShortIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of ints. When targeting the JVM, instances of this class are represented as `int[]`.
|
||||
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
|
||||
*/
|
||||
public class IntArray(size: Int) {
|
||||
/**
|
||||
* Creates a new array of the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
*
|
||||
* The function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for an array element given its index.
|
||||
*/
|
||||
public inline constructor(size: Int, init: (Int) -> Int)
|
||||
|
||||
/**
|
||||
* Returns the array element at the given [index]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun get(index: Int): Int
|
||||
|
||||
/**
|
||||
* Sets the element at the given [index] to the given [value]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: Int): Unit
|
||||
|
||||
/** Returns the number of elements in the array. */
|
||||
public val size: Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
public operator fun iterator(): IntIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of longs. When targeting the JVM, instances of this class are represented as `long[]`.
|
||||
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
|
||||
*/
|
||||
public class LongArray(size: Int) {
|
||||
/**
|
||||
* Creates a new array of the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
*
|
||||
* The function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for an array element given its index.
|
||||
*/
|
||||
public inline constructor(size: Int, init: (Int) -> Long)
|
||||
|
||||
/**
|
||||
* Returns the array element at the given [index]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun get(index: Int): Long
|
||||
|
||||
/**
|
||||
* Sets the element at the given [index] to the given [value]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: Long): Unit
|
||||
|
||||
/** Returns the number of elements in the array. */
|
||||
public val size: Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
public operator fun iterator(): LongIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of floats. When targeting the JVM, instances of this class are represented as `float[]`.
|
||||
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
|
||||
*/
|
||||
public class FloatArray(size: Int) {
|
||||
/**
|
||||
* Creates a new array of the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
*
|
||||
* The function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for an array element given its index.
|
||||
*/
|
||||
public inline constructor(size: Int, init: (Int) -> Float)
|
||||
|
||||
/**
|
||||
* Returns the array element at the given [index]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun get(index: Int): Float
|
||||
|
||||
/**
|
||||
* Sets the element at the given [index] to the given [value]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: Float): Unit
|
||||
|
||||
/** Returns the number of elements in the array. */
|
||||
public val size: Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
public operator fun iterator(): FloatIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of doubles. When targeting the JVM, instances of this class are represented as `double[]`.
|
||||
* @constructor Creates a new array of the specified [size], with all elements initialized to zero.
|
||||
*/
|
||||
public class DoubleArray(size: Int) {
|
||||
/**
|
||||
* Creates a new array of the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
*
|
||||
* The function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for an array element given its index.
|
||||
*/
|
||||
public inline constructor(size: Int, init: (Int) -> Double)
|
||||
|
||||
/**
|
||||
* Returns the array element at the given [index]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun get(index: Int): Double
|
||||
|
||||
/**
|
||||
* Sets the element at the given [index] to the given [value]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: Double): Unit
|
||||
|
||||
/** Returns the number of elements in the array. */
|
||||
public val size: Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
public operator fun iterator(): DoubleIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of booleans. When targeting the JVM, instances of this class are represented as `boolean[]`.
|
||||
* @constructor Creates a new array of the specified [size], with all elements initialized to `false`.
|
||||
*/
|
||||
public class BooleanArray(size: Int) {
|
||||
/**
|
||||
* Creates a new array of the specified [size], where each element is calculated by calling the specified
|
||||
* [init] function.
|
||||
*
|
||||
* The function [init] is called for each array element sequentially starting from the first one.
|
||||
* It should return the value for an array element given its index.
|
||||
*/
|
||||
public inline constructor(size: Int, init: (Int) -> Boolean)
|
||||
|
||||
/**
|
||||
* Returns the array element at the given [index]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun get(index: Int): Boolean
|
||||
|
||||
/**
|
||||
* Sets the element at the given [index] to the given [value]. This method can be called using the index operator.
|
||||
*
|
||||
* If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
|
||||
* where the behavior is unspecified.
|
||||
*/
|
||||
public operator fun set(index: Int, value: Boolean): Unit
|
||||
|
||||
/** Returns the number of elements in the array. */
|
||||
public val size: Int
|
||||
|
||||
/** Creates an iterator over the elements of the array. */
|
||||
public operator fun iterator(): BooleanIterator
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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 kotlin
|
||||
|
||||
/**
|
||||
* Represents a readable sequence of [Char] values.
|
||||
*/
|
||||
public interface CharSequence {
|
||||
/**
|
||||
* Returns the length of this character sequence.
|
||||
*/
|
||||
public val length: Int
|
||||
|
||||
/**
|
||||
* Returns the character at the specified [index] in this character sequence.
|
||||
*
|
||||
* @throws [IndexOutOfBoundsException] if the [index] is out of bounds of this character sequence.
|
||||
*
|
||||
* Note that the [String] implementation of this interface in Kotlin/JS has unspecified behavior
|
||||
* if the [index] is out of its bounds.
|
||||
*/
|
||||
public operator fun get(index: Int): Char
|
||||
|
||||
/**
|
||||
* Returns a new character sequence that is a subsequence of this character sequence,
|
||||
* starting at the specified [startIndex] and ending right before the specified [endIndex].
|
||||
*
|
||||
* @param startIndex the start index (inclusive).
|
||||
* @param endIndex the end index (exclusive).
|
||||
*/
|
||||
public fun subSequence(startIndex: Int, endIndex: Int): CharSequence
|
||||
}
|
||||
@@ -1,438 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 kotlin.collections
|
||||
|
||||
import kotlin.internal.PlatformDependent
|
||||
|
||||
/**
|
||||
* Classes that inherit from this interface can be represented as a sequence of elements that can
|
||||
* be iterated over.
|
||||
* @param T the type of element being iterated over. The iterator is covariant in its element type.
|
||||
*/
|
||||
public interface Iterable<out T> {
|
||||
/**
|
||||
* Returns an iterator over the elements of this object.
|
||||
*/
|
||||
public operator fun iterator(): Iterator<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Classes that inherit from this interface can be represented as a sequence of elements that can
|
||||
* be iterated over and that supports removing elements during iteration.
|
||||
* @param T the type of element being iterated over. The mutable iterator is invariant in its element type.
|
||||
*/
|
||||
public interface MutableIterable<out T> : Iterable<T> {
|
||||
/**
|
||||
* Returns an iterator over the elements of this sequence that supports removing elements during iteration.
|
||||
*/
|
||||
override fun iterator(): MutableIterator<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic collection of elements. Methods in this interface support only read-only access to the collection;
|
||||
* read/write access is supported through the [MutableCollection] interface.
|
||||
* @param E the type of elements contained in the collection. The collection is covariant in its element type.
|
||||
*/
|
||||
public interface Collection<out E> : Iterable<E> {
|
||||
// Query Operations
|
||||
/**
|
||||
* Returns the size of the collection.
|
||||
*/
|
||||
public val size: Int
|
||||
|
||||
/**
|
||||
* Returns `true` if the collection is empty (contains no elements), `false` otherwise.
|
||||
*/
|
||||
public fun isEmpty(): Boolean
|
||||
|
||||
/**
|
||||
* Checks if the specified element is contained in this collection.
|
||||
*/
|
||||
public operator fun contains(element: @UnsafeVariance E): Boolean
|
||||
|
||||
override fun iterator(): Iterator<E>
|
||||
|
||||
// Bulk Operations
|
||||
/**
|
||||
* Checks if all elements in the specified collection are contained in this collection.
|
||||
*/
|
||||
public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic collection of elements that supports adding and removing elements.
|
||||
*
|
||||
* @param E the type of elements contained in the collection. The mutable collection is invariant in its element type.
|
||||
*/
|
||||
public interface MutableCollection<E> : Collection<E>, MutableIterable<E> {
|
||||
// Query Operations
|
||||
override fun iterator(): MutableIterator<E>
|
||||
|
||||
// Modification Operations
|
||||
/**
|
||||
* Adds the specified element to the collection.
|
||||
*
|
||||
* @return `true` if the element has been added, `false` if the collection does not support duplicates
|
||||
* and the element is already contained in the collection.
|
||||
*/
|
||||
public fun add(element: E): Boolean
|
||||
|
||||
/**
|
||||
* Removes a single instance of the specified element from this
|
||||
* collection, if it is present.
|
||||
*
|
||||
* @return `true` if the element has been successfully removed; `false` if it was not present in the collection.
|
||||
*/
|
||||
public fun remove(element: E): Boolean
|
||||
|
||||
// Bulk Modification Operations
|
||||
/**
|
||||
* Adds all of the elements of the specified collection to this collection.
|
||||
*
|
||||
* @return `true` if any of the specified elements was added to the collection, `false` if the collection was not modified.
|
||||
*/
|
||||
public fun addAll(elements: Collection<E>): Boolean
|
||||
|
||||
/**
|
||||
* Removes all of this collection's elements that are also contained in the specified collection.
|
||||
*
|
||||
* @return `true` if any of the specified elements was removed from the collection, `false` if the collection was not modified.
|
||||
*/
|
||||
public fun removeAll(elements: Collection<E>): Boolean
|
||||
|
||||
/**
|
||||
* Retains only the elements in this collection that are contained in the specified collection.
|
||||
*
|
||||
* @return `true` if any element was removed from the collection, `false` if the collection was not modified.
|
||||
*/
|
||||
public fun retainAll(elements: Collection<E>): Boolean
|
||||
|
||||
/**
|
||||
* Removes all elements from this collection.
|
||||
*/
|
||||
public fun clear(): Unit
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic ordered collection of elements. Methods in this interface support only read-only access to the list;
|
||||
* read/write access is supported through the [MutableList] interface.
|
||||
* @param E the type of elements contained in the list. The list is covariant in its element type.
|
||||
*/
|
||||
public interface List<out E> : Collection<E> {
|
||||
// Query Operations
|
||||
|
||||
override val size: Int
|
||||
override fun isEmpty(): Boolean
|
||||
override fun contains(element: @UnsafeVariance E): Boolean
|
||||
override fun iterator(): Iterator<E>
|
||||
|
||||
// Bulk Operations
|
||||
override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
|
||||
|
||||
// Positional Access Operations
|
||||
/**
|
||||
* Returns the element at the specified index in the list.
|
||||
*/
|
||||
public operator fun get(index: Int): E
|
||||
|
||||
// Search Operations
|
||||
/**
|
||||
* Returns the index of the first occurrence of the specified element in the list, or -1 if the specified
|
||||
* element is not contained in the list.
|
||||
*/
|
||||
public fun indexOf(element: @UnsafeVariance E): Int
|
||||
|
||||
/**
|
||||
* Returns the index of the last occurrence of the specified element in the list, or -1 if the specified
|
||||
* element is not contained in the list.
|
||||
*/
|
||||
public fun lastIndexOf(element: @UnsafeVariance E): Int
|
||||
|
||||
// List Iterators
|
||||
/**
|
||||
* Returns a list iterator over the elements in this list (in proper sequence).
|
||||
*/
|
||||
public fun listIterator(): ListIterator<E>
|
||||
|
||||
/**
|
||||
* Returns a list iterator over the elements in this list (in proper sequence), starting at the specified [index].
|
||||
*/
|
||||
public fun listIterator(index: Int): ListIterator<E>
|
||||
|
||||
// View
|
||||
/**
|
||||
* Returns a view of the portion of this list between the specified [fromIndex] (inclusive) and [toIndex] (exclusive).
|
||||
* The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
|
||||
*
|
||||
* Structural changes in the base list make the behavior of the view undefined.
|
||||
*/
|
||||
public fun subList(fromIndex: Int, toIndex: Int): List<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic ordered collection of elements that supports adding and removing elements.
|
||||
* @param E the type of elements contained in the list. The mutable list is invariant in its element type.
|
||||
*/
|
||||
public interface MutableList<E> : List<E>, MutableCollection<E> {
|
||||
// Modification Operations
|
||||
/**
|
||||
* Adds the specified element to the end of this list.
|
||||
*
|
||||
* @return `true` because the list is always modified as the result of this operation.
|
||||
*/
|
||||
override fun add(element: E): Boolean
|
||||
|
||||
override fun remove(element: E): Boolean
|
||||
|
||||
// Bulk Modification Operations
|
||||
/**
|
||||
* Adds all of the elements of the specified collection to the end of this list.
|
||||
*
|
||||
* The elements are appended in the order they appear in the [elements] collection.
|
||||
*
|
||||
* @return `true` if the list was changed as the result of the operation.
|
||||
*/
|
||||
override fun addAll(elements: Collection<E>): Boolean
|
||||
|
||||
/**
|
||||
* Inserts all of the elements of the specified collection [elements] into this list at the specified [index].
|
||||
*
|
||||
* @return `true` if the list was changed as the result of the operation.
|
||||
*/
|
||||
public fun addAll(index: Int, elements: Collection<E>): Boolean
|
||||
|
||||
override fun removeAll(elements: Collection<E>): Boolean
|
||||
override fun retainAll(elements: Collection<E>): Boolean
|
||||
override fun clear(): Unit
|
||||
|
||||
// Positional Access Operations
|
||||
/**
|
||||
* Replaces the element at the specified position in this list with the specified element.
|
||||
*
|
||||
* @return the element previously at the specified position.
|
||||
*/
|
||||
public operator fun set(index: Int, element: E): E
|
||||
|
||||
/**
|
||||
* Inserts an element into the list at the specified [index].
|
||||
*/
|
||||
public fun add(index: Int, element: E): Unit
|
||||
|
||||
/**
|
||||
* Removes an element at the specified [index] from the list.
|
||||
*
|
||||
* @return the element that has been removed.
|
||||
*/
|
||||
public fun removeAt(index: Int): E
|
||||
|
||||
// List Iterators
|
||||
override fun listIterator(): MutableListIterator<E>
|
||||
|
||||
override fun listIterator(index: Int): MutableListIterator<E>
|
||||
|
||||
// View
|
||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic unordered collection of elements that does not support duplicate elements.
|
||||
* Methods in this interface support only read-only access to the set;
|
||||
* read/write access is supported through the [MutableSet] interface.
|
||||
* @param E the type of elements contained in the set. The set is covariant in its element type.
|
||||
*/
|
||||
public interface Set<out E> : Collection<E> {
|
||||
// Query Operations
|
||||
|
||||
override val size: Int
|
||||
override fun isEmpty(): Boolean
|
||||
override fun contains(element: @UnsafeVariance E): Boolean
|
||||
override fun iterator(): Iterator<E>
|
||||
|
||||
// Bulk Operations
|
||||
override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic unordered collection of elements that does not support duplicate elements, and supports
|
||||
* adding and removing elements.
|
||||
* @param E the type of elements contained in the set. The mutable set is invariant in its element type.
|
||||
*/
|
||||
public interface MutableSet<E> : Set<E>, MutableCollection<E> {
|
||||
// Query Operations
|
||||
override fun iterator(): MutableIterator<E>
|
||||
|
||||
// Modification Operations
|
||||
|
||||
/**
|
||||
* Adds the specified element to the set.
|
||||
*
|
||||
* @return `true` if the element has been added, `false` if the element is already contained in the set.
|
||||
*/
|
||||
override fun add(element: E): Boolean
|
||||
|
||||
override fun remove(element: E): Boolean
|
||||
|
||||
// Bulk Modification Operations
|
||||
|
||||
override fun addAll(elements: Collection<E>): Boolean
|
||||
override fun removeAll(elements: Collection<E>): Boolean
|
||||
override fun retainAll(elements: Collection<E>): Boolean
|
||||
override fun clear(): Unit
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection that holds pairs of objects (keys and values) and supports efficiently retrieving
|
||||
* the value corresponding to each key. Map keys are unique; the map holds only one value for each key.
|
||||
* Methods in this interface support only read-only access to the map; read-write access is supported through
|
||||
* the [MutableMap] interface.
|
||||
* @param K the type of map keys. The map is invariant in its key type, as it
|
||||
* can accept key as a parameter (of [containsKey] for example) and return it in [keys] set.
|
||||
* @param V the type of map values. The map is covariant in its value type.
|
||||
*/
|
||||
public interface Map<K, out V> {
|
||||
// Query Operations
|
||||
/**
|
||||
* Returns the number of key/value pairs in the map.
|
||||
*/
|
||||
public val size: Int
|
||||
|
||||
/**
|
||||
* Returns `true` if the map is empty (contains no elements), `false` otherwise.
|
||||
*/
|
||||
public fun isEmpty(): Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if the map contains the specified [key].
|
||||
*/
|
||||
public fun containsKey(key: K): Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if the map maps one or more keys to the specified [value].
|
||||
*/
|
||||
public fun containsValue(value: @UnsafeVariance V): Boolean
|
||||
|
||||
/**
|
||||
* Returns the value corresponding to the given [key], or `null` if such a key is not present in the map.
|
||||
*/
|
||||
public operator fun get(key: K): V?
|
||||
|
||||
/**
|
||||
* Returns the value corresponding to the given [key], or [defaultValue] if such a key is not present in the map.
|
||||
*
|
||||
* @since JDK 1.8
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@PlatformDependent
|
||||
public fun getOrDefault(key: K, defaultValue: @UnsafeVariance V): V {
|
||||
// See default implementation in JDK sources
|
||||
return null as V
|
||||
}
|
||||
|
||||
// Views
|
||||
/**
|
||||
* Returns a read-only [Set] of all keys in this map.
|
||||
*/
|
||||
public val keys: Set<K>
|
||||
|
||||
/**
|
||||
* Returns a read-only [Collection] of all values in this map. Note that this collection may contain duplicate values.
|
||||
*/
|
||||
public val values: Collection<V>
|
||||
|
||||
/**
|
||||
* Returns a read-only [Set] of all key/value pairs in this map.
|
||||
*/
|
||||
public val entries: Set<Map.Entry<K, V>>
|
||||
|
||||
/**
|
||||
* Represents a key/value pair held by a [Map].
|
||||
*/
|
||||
public interface Entry<out K, out V> {
|
||||
/**
|
||||
* Returns the key of this key/value pair.
|
||||
*/
|
||||
public val key: K
|
||||
|
||||
/**
|
||||
* Returns the value of this key/value pair.
|
||||
*/
|
||||
public val value: V
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A modifiable collection that holds pairs of objects (keys and values) and supports efficiently retrieving
|
||||
* the value corresponding to each key. Map keys are unique; the map holds only one value for each key.
|
||||
* @param K the type of map keys. The map is invariant in its key type.
|
||||
* @param V the type of map values. The mutable map is invariant in its value type.
|
||||
*/
|
||||
public interface MutableMap<K, V> : Map<K, V> {
|
||||
// Modification Operations
|
||||
/**
|
||||
* Associates the specified [value] with the specified [key] in the map.
|
||||
*
|
||||
* @return the previous value associated with the key, or `null` if the key was not present in the map.
|
||||
*/
|
||||
public fun put(key: K, value: V): V?
|
||||
|
||||
/**
|
||||
* Removes the specified key and its corresponding value from this map.
|
||||
*
|
||||
* @return the previous value associated with the key, or `null` if the key was not present in the map.
|
||||
*/
|
||||
public fun remove(key: K): V?
|
||||
|
||||
/**
|
||||
* Removes the entry for the specified key only if it is mapped to the specified value.
|
||||
*
|
||||
* @return true if entry was removed
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@PlatformDependent
|
||||
public fun remove(key: K, value: V): Boolean {
|
||||
// See default implementation in JDK sources
|
||||
return true
|
||||
}
|
||||
|
||||
// Bulk Modification Operations
|
||||
/**
|
||||
* Updates this map with key/value pairs from the specified map [from].
|
||||
*/
|
||||
public fun putAll(from: Map<out K, V>): Unit
|
||||
|
||||
/**
|
||||
* Removes all elements from this map.
|
||||
*/
|
||||
public fun clear(): Unit
|
||||
|
||||
// Views
|
||||
/**
|
||||
* Returns a [MutableSet] of all keys in this map.
|
||||
*/
|
||||
override val keys: MutableSet<K>
|
||||
|
||||
/**
|
||||
* Returns a [MutableCollection] of all values in this map. Note that this collection may contain duplicate values.
|
||||
*/
|
||||
override val values: MutableCollection<V>
|
||||
|
||||
/**
|
||||
* Returns a [MutableSet] of all key/value pairs in this map.
|
||||
*/
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
|
||||
/**
|
||||
* Represents a key/value pair held by a [MutableMap].
|
||||
*/
|
||||
public interface MutableEntry<K, V> : Map.Entry<K, V> {
|
||||
/**
|
||||
* Changes the value associated with the key of this entry.
|
||||
*
|
||||
* @return the previous value corresponding to the key.
|
||||
*/
|
||||
public fun setValue(newValue: V): V
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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 kotlin
|
||||
|
||||
/**
|
||||
* Classes which inherit from this interface have a defined total ordering between their instances.
|
||||
*/
|
||||
public interface Comparable<in T> {
|
||||
/**
|
||||
* Compares this object with the specified object for order. Returns zero if this object is equal
|
||||
* to the specified [other] object, a negative number if it's less than [other], or a positive number
|
||||
* if it's greater than [other].
|
||||
*/
|
||||
public operator fun compareTo(other: T): Int
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user