diff --git a/.idea/dictionaries/skuzmich.xml b/.idea/dictionaries/skuzmich.xml
new file mode 100644
index 00000000000..d373a954ec6
--- /dev/null
+++ b/.idea/dictionaries/skuzmich.xml
@@ -0,0 +1,9 @@
+
+
+
+ anyref
+ ushr
+ wasm
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 25c658bcd85..a859abdcb1d 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -23,28 +23,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build.gradle.kts b/build.gradle.kts
index 5a34db84f76..f0c578be408 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -3,7 +3,6 @@ import org.gradle.plugins.ide.idea.model.IdeaModel
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import proguard.gradle.ProGuardTask
-import org.gradle.kotlin.dsl.*
buildscript {
extra["defaultSnapshotVersion"] = "1.3-SNAPSHOT"
@@ -212,6 +211,7 @@ extra["compilerModules"] = arrayOf(
":compiler:ir.backend.common",
":compiler:backend.jvm",
":compiler:backend.js",
+ ":compiler:backend.wasm",
":compiler:ir.serialization.common",
":compiler:ir.serialization.js",
":kotlin-util-io",
@@ -506,6 +506,10 @@ tasks {
dependsOn(":js:js.tests:runMocha")
}
+ register("wasmCompilerTest") {
+ dependsOn(":js:js.tests:wasmTest")
+ }
+
register("firCompilerTest") {
dependsOn(":compiler:fir:psi2fir:test")
dependsOn(":compiler:fir:resolve:test")
@@ -527,6 +531,7 @@ tasks {
register("compilerTest") {
dependsOn("jvmCompilerTest")
dependsOn("jsCompilerTest")
+ dependsOn("wasmCompilerTest")
dependsOn("firCompilerTest")
dependsOn("scriptingTest")
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt
index 3324a7c158f..250632d5bd2 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.utils.DFS
-private fun sortDependencies(dependencies: Collection): Collection {
+fun sortDependencies(dependencies: Collection): Collection {
val mapping = dependencies.map { it.descriptor to it }.toMap()
return DFS.topologicalOrder(dependencies) { m ->
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt
index d37ab001f36..2724cf69565 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/AnnotationUtils.kt
@@ -23,7 +23,7 @@ object JsAnnotations {
}
@Suppress("UNCHECKED_CAST")
-private fun IrConstructorCall.getSingleConstStringArgument() =
+fun IrConstructorCall.getSingleConstStringArgument() =
(getValueArgument(0) as IrConst).value
fun IrAnnotationContainer.getJsModule(): String? =
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt
index 4f9169141c2..51a034a30d3 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
class NameTable(
val parent: NameTable? = null,
- private val reserved: MutableSet = mutableSetOf()
+ private val reserved: MutableSet = mutableSetOf(),
+ val sanitizer: (String) -> String = ::sanitizeName
) {
var finished = false
val names = mutableMapOf()
@@ -41,9 +42,10 @@ class NameTable(
reserved.add(name)
}
- fun declareFreshName(declaration: T, suggestedName: String) {
- val freshName = findFreshName(sanitizeName(suggestedName))
+ fun declareFreshName(declaration: T, suggestedName: String): String {
+ val freshName = findFreshName(sanitizer(suggestedName))
declareStableName(declaration, freshName)
+ return freshName
}
private fun findFreshName(suggestedName: String): String {
diff --git a/compiler/ir/backend.wasm/build.gradle.kts b/compiler/ir/backend.wasm/build.gradle.kts
new file mode 100644
index 00000000000..cc9386c3abc
--- /dev/null
+++ b/compiler/ir/backend.wasm/build.gradle.kts
@@ -0,0 +1,26 @@
+plugins {
+ kotlin("jvm")
+ id("jps-compatible")
+}
+
+dependencies {
+ compile(project(":compiler:util"))
+ compile(project(":compiler:frontend"))
+ compile(project(":compiler:backend-common"))
+ compile(project(":compiler:ir.tree"))
+ compile(project(":compiler:ir.psi2ir"))
+ compile(project(":compiler:ir.backend.common"))
+ compile(project(":compiler:ir.serialization.common"))
+ compile(project(":compiler:ir.serialization.js"))
+ compile(project(":js:js.ast"))
+ compile(project(":js:js.frontend"))
+ compile(project(":compiler:backend.js"))
+
+ compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
+}
+
+sourceSets {
+ "main" { projectDefault() }
+ "test" {}
+}
+
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt
new file mode 100644
index 00000000000..4375cd2e3f0
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt
@@ -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
+
+import org.jetbrains.kotlin.backend.common.CommonBackendContext
+import org.jetbrains.kotlin.backend.common.ir.Ir
+import org.jetbrains.kotlin.backend.common.ir.Symbols
+import org.jetbrains.kotlin.backend.js.JsDeclarationFactory
+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.IrElement
+import org.jetbrains.kotlin.ir.backend.js.JsSharedVariablesManager
+import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
+import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
+import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
+import org.jetbrains.kotlin.ir.symbols.IrExternalPackageFragmentSymbol
+import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
+import org.jetbrains.kotlin.ir.util.SymbolTable
+import org.jetbrains.kotlin.name.FqName
+
+class WasmBackendContext(
+ val module: ModuleDescriptor,
+ override val irBuiltIns: IrBuiltIns,
+ symbolTable: SymbolTable,
+ irModuleFragment: IrModuleFragment,
+ val additionalExportedDeclarations: Set,
+ override val configuration: CompilerConfiguration
+) : CommonBackendContext {
+ override val builtIns = module.builtIns
+ override var inVerbosePhase: Boolean = false
+
+ // Place to store declarations excluded from code generation
+ val excludedDeclarations: IrPackageFragment by lazy {
+ IrExternalPackageFragmentImpl(
+ DescriptorlessExternalPackageFragmentSymbol(),
+ FqName("kotlin")
+ )
+ }
+
+ override val declarationFactory = JsDeclarationFactory()
+
+ val objectToGetInstanceFunction = mutableMapOf()
+ override val internalPackageFqn = FqName("kotlin.wasm")
+
+ private val internalPackageFragment = IrExternalPackageFragmentImpl(
+ IrExternalPackageFragmentSymbolImpl(
+ EmptyPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.wasm.internal"))
+ )
+ )
+
+ override val sharedVariablesManager = JsSharedVariablesManager(irBuiltIns, internalPackageFragment)
+
+ val wasmSymbols: WasmSymbols = WasmSymbols(this@WasmBackendContext, symbolTable)
+ override val ir = object : Ir(this, irModuleFragment) {
+ override val symbols: Symbols = wasmSymbols
+ override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
+ }
+
+ override fun log(message: () -> String) {
+ /*TODO*/
+ if (inVerbosePhase) print(message())
+ }
+
+ override fun report(element: IrElement?, irFile: IrFile?, message: String, isError: Boolean) {
+ /*TODO*/
+ print(message)
+ }
+}
+
+class DescriptorlessExternalPackageFragmentSymbol : IrExternalPackageFragmentSymbol {
+ override val descriptor: PackageFragmentDescriptor
+ get() = error("Operation is unsupported")
+
+ private var _owner: IrExternalPackageFragment? = null
+ override val owner get() = _owner!!
+
+ override val isBound get() = _owner != null
+
+ override fun bind(owner: IrExternalPackageFragment) {
+ _owner = owner
+ }
+}
+
+
+
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt
new file mode 100644
index 00000000000..b1631a9cabb
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt
@@ -0,0 +1,414 @@
+/*
+ * 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
+
+import org.jetbrains.kotlin.backend.common.*
+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.wasm.lower.BuiltInsLowering
+import org.jetbrains.kotlin.backend.wasm.lower.WasmBlockDecomposerLowering
+import org.jetbrains.kotlin.backend.wasm.lower.excludeDeclarationsFromCodegen
+import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
+import org.jetbrains.kotlin.ir.backend.js.lower.*
+import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineFunctionsWithReifiedTypeParametersLowering
+import org.jetbrains.kotlin.ir.backend.js.lower.inline.ReturnableBlockLowering
+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 validationCallback(context: WasmBackendContext, module: IrModuleFragment) {
+ val validatorConfig = IrValidatorConfig(
+ abortOnError = true,
+ ensureAllNodesAreDifferent = true,
+ checkTypes = false,
+ checkDescriptors = false
+ )
+ module.accept(IrValidator(context, validatorConfig), null)
+ module.accept(CheckDeclarationParentsVisitor, null)
+}
+
+val validationAction = makeVerifyAction(::validationCallback)
+
+private fun makeWasmModulePhase(
+ lowering: (WasmBackendContext) -> FileLoweringPass,
+ name: String,
+ description: String,
+ prerequisite: Set = emptySet()
+) = makeIrModulePhase(lowering, name, description, prerequisite, actions = setOf(validationAction, defaultDumper))
+
+private fun makeCustomWasmModulePhase(
+ op: (WasmBackendContext, IrModuleFragment) -> Unit,
+ description: String,
+ name: String,
+ prerequisite: Set = emptySet()
+) = namedIrModulePhase(
+ name,
+ description,
+ prerequisite,
+ actions = setOf(defaultDumper, validationAction),
+ nlevels = 0,
+ lower = object : SameTypeCompilerPhase {
+ override fun invoke(
+ phaseConfig: PhaseConfig,
+ phaserState: PhaserState,
+ context: WasmBackendContext,
+ input: IrModuleFragment
+ ): IrModuleFragment {
+ op(context, input)
+ return input
+ }
+ }
+)
+
+private val validateIrBeforeLowering = makeCustomWasmModulePhase(
+ { context, module -> validationCallback(context, module) },
+ name = "ValidateIrBeforeLowering",
+ description = "Validate IR before lowering"
+)
+
+private val validateIrAfterLowering = makeCustomWasmModulePhase(
+ { context, module -> validationCallback(context, module) },
+ name = "ValidateIrAfterLowering",
+ description = "Validate IR after lowering"
+)
+
+private val expectDeclarationsRemovingPhase = makeWasmModulePhase(
+ ::ExpectDeclarationsRemoveLowering,
+ name = "ExpectDeclarationsRemoving",
+ description = "Remove expect declaration from module fragment"
+)
+
+private val lateinitLoweringPhase = makeWasmModulePhase(
+ ::LateinitLowering,
+ name = "LateinitLowering",
+ description = "Insert checks for lateinit field references"
+)
+
+// TODO make all lambda-related stuff work with IrFunctionExpression and drop this phase
+private val provisionalFunctionExpressionPhase = makeWasmModulePhase(
+ { ProvisionalFunctionExpressionLowering() },
+ name = "FunctionExpression",
+ 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)
+ module.patchDeclarationParents()
+ },
+ name = "FunctionInliningPhase",
+ description = "Perform function inlining",
+ prerequisite = setOf(expectDeclarationsRemovingPhase)
+)
+
+private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeWasmModulePhase(
+ { RemoveInlineFunctionsWithReifiedTypeParametersLowering() },
+ name = "RemoveInlineFunctionsWithReifiedTypeParametersLowering",
+ description = "Remove Inline functions with reified parameters from context",
+ prerequisite = setOf(functionInliningPhase)
+)
+
+private val tailrecLoweringPhase = makeWasmModulePhase(
+ ::TailrecLowering,
+ name = "TailrecLowering",
+ description = "Replace `tailrec` callsites with equivalent loop"
+)
+
+private val enumClassConstructorLoweringPhase = makeWasmModulePhase(
+ ::EnumClassConstructorLowering,
+ name = "EnumClassConstructorLowering",
+ description = "Transform Enum Class into regular Class"
+)
+
+
+private val sharedVariablesLoweringPhase = makeWasmModulePhase(
+ ::SharedVariablesLowering,
+ name = "SharedVariablesLowering",
+ description = "Box captured mutable variables"
+)
+
+private val localDelegatedPropertiesLoweringPhase = makeWasmModulePhase(
+ { LocalDelegatedPropertiesLowering() },
+ name = "LocalDelegatedPropertiesLowering",
+ description = "Transform Local Delegated properties"
+)
+
+private val localDeclarationsLoweringPhase = makeWasmModulePhase(
+ ::LocalDeclarationsLowering,
+ name = "LocalDeclarationsLowering",
+ description = "Move local declarations into nearest declaration container",
+ prerequisite = setOf(sharedVariablesLoweringPhase, localDelegatedPropertiesLoweringPhase)
+)
+
+private val localClassExtractionPhase = makeWasmModulePhase(
+ ::LocalClassPopupLowering,
+ name = "LocalClassExtractionPhase",
+ description = "Move local declarations into nearest declaration container",
+ prerequisite = setOf(localDeclarationsLoweringPhase)
+)
+
+private val innerClassesLoweringPhase = makeWasmModulePhase(
+ ::InnerClassesLowering,
+ name = "InnerClassesLowering",
+ description = "Capture outer this reference to inner class"
+)
+
+private val innerClassConstructorCallsLoweringPhase = makeWasmModulePhase(
+ ::InnerClassConstructorCallsLowering,
+ name = "InnerClassConstructorCallsLowering",
+ description = "Replace inner class constructor invocation"
+)
+
+private val defaultArgumentStubGeneratorPhase = makeWasmModulePhase(
+ ::DefaultArgumentStubGenerator,
+ name = "DefaultArgumentStubGenerator",
+ description = "Generate synthetic stubs for functions with default parameter values"
+)
+
+private val defaultParameterInjectorPhase = makeWasmModulePhase(
+ { context -> DefaultParameterInjector(context, skipExternalMethods = true) },
+ name = "DefaultParameterInjector",
+ description = "Replace callsite with default parameters with corresponding stub function",
+ prerequisite = setOf(innerClassesLoweringPhase)
+)
+
+private val defaultParameterCleanerPhase = makeWasmModulePhase(
+ ::DefaultParameterCleaner,
+ name = "DefaultParameterCleaner",
+ 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(
+ { context -> PropertiesLowering(context, skipExternalProperties = true, generateAnnotationFields = true) },
+ name = "PropertiesLowering",
+ description = "Move fields and accessors out from its property"
+)
+
+private val primaryConstructorLoweringPhase = makeWasmModulePhase(
+ ::PrimaryConstructorLowering,
+ name = "PrimaryConstructorLowering",
+ description = "Creates primary constructor if it doesn't exist"
+)
+
+private val initializersLoweringPhase = makeCustomWasmModulePhase(
+ { context, module -> InitializersLowering(context, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).lower(module) },
+ name = "InitializersLowering",
+ description = "Merge init block and field initializers into [primary] constructor",
+ prerequisite = setOf(primaryConstructorLoweringPhase)
+)
+
+private val excludeDeclarationsFromCodegenPhase = makeCustomWasmModulePhase(
+ { context, module ->
+ excludeDeclarationsFromCodegen(context, module)
+ },
+ name = "ExcludeDeclarationsFromCodegen",
+ description = "Move excluded declarations to separate place"
+)
+
+private val returnableBlockLoweringPhase = makeWasmModulePhase(
+ ::ReturnableBlockLowering,
+ name = "ReturnableBlockLowering",
+ description = "Replace returnable block with do-while loop",
+ prerequisite = setOf(functionInliningPhase)
+)
+
+private val bridgesConstructionPhase = makeWasmModulePhase(
+ ::BridgesConstruction,
+ name = "BridgesConstruction",
+ description = "Generate bridges"
+)
+
+private val inlineClassLoweringPhase = makeCustomWasmModulePhase(
+ { context, module ->
+ InlineClassLowering(context).run {
+ inlineClassDeclarationLowering.runOnFilesPostfix(module)
+ inlineClassUsageLowering.lower(module)
+ }
+ },
+ name = "InlineClassLowering",
+ description = "Handle inline classes"
+)
+
+//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 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"
+)
+
+private val objectDeclarationLoweringPhase = makeCustomWasmModulePhase(
+ { context, module -> ObjectUsageLowering(context, context.objectToGetInstanceFunction).lower(module) },
+ name = "ObjectDeclarationLowering",
+ description = "Create lazy object instance generator functions"
+)
+
+private val objectUsageLoweringPhase = makeCustomWasmModulePhase(
+ { context, module -> ObjectUsageLowering(context, context.objectToGetInstanceFunction).lower(module) },
+ name = "ObjectUsageLowering",
+ description = "Transform IrGetObjectValue into instance generator call"
+)
+
+val wasmPhases = namedIrModulePhase(
+ 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
+ lateinitLoweringPhase then
+ tailrecLoweringPhase then
+
+ enumClassConstructorLoweringPhase then
+
+ sharedVariablesLoweringPhase then
+ localDelegatedPropertiesLoweringPhase then
+ localDeclarationsLoweringPhase then
+ localClassExtractionPhase then
+ innerClassesLoweringPhase then
+ innerClassConstructorCallsLoweringPhase then
+ propertiesLoweringPhase then
+ primaryConstructorLoweringPhase then
+ initializersLoweringPhase then
+ // Common prefix ends
+
+ builtInsLoweringPhase then
+
+// TODO: Commonize enumEntryToGetInstanceFunction
+// Commonize array literal creation
+// Extract external enum lowering to JS part
+//
+// enumClassLoweringPhase then
+// enumUsageLoweringPhase then
+
+
+// TODO: Requires stdlib
+// suspendFunctionsLoweringPhase then
+
+ returnableBlockLoweringPhase then
+
+// TODO: Callable reference lowering is too JS specific.
+// Should we reuse JVM or Native lowering?
+// callableReferenceLoweringPhase then
+
+ defaultArgumentStubGeneratorPhase then
+ defaultParameterInjectorPhase then
+ defaultParameterCleanerPhase then
+
+// TODO: Investigate
+// jsDefaultCallbackGeneratorPhase then
+
+ removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then
+
+
+// TODO: Varargs are too platform-specific. Reimplement.
+// varargLoweringPhase then
+
+// TODO: Investigate exception proposal
+// multipleCatchesLoweringPhase then
+
+ bridgesConstructionPhase then
+
+// TODO: Reimplement
+// typeOperatorLoweringPhase then
+
+// TODO: Reimplement
+// secondaryConstructorLoweringPhase then
+// secondaryFactoryInjectorLoweringPhase then
+
+// TODO: Reimplement
+// classReferenceLoweringPhase then
+
+ inlineClassLoweringPhase then
+
+// TODO: Commonize box/unbox intrinsics
+// autoboxingTransformerPhase then
+
+ blockDecomposerLoweringPhase then
+
+// TODO: Reimplement
+// constLoweringPhase then
+
+ objectDeclarationLoweringPhase then
+ objectUsageLoweringPhase then
+ staticMembersLoweringPhase then
+
+ validateIrAfterLowering
+)
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt
new file mode 100644
index 00000000000..c404c207a77
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt
@@ -0,0 +1,121 @@
+/*
+ * 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
+
+import org.jetbrains.kotlin.backend.common.ir.Symbols
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+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.symbols.IrClassSymbol
+import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
+import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.resolve.scopes.MemberScope
+import org.jetbrains.kotlin.types.SimpleType
+
+class WasmSymbols(
+ context: WasmBackendContext,
+ private val symbolTable: ReferenceSymbolTable
+) : Symbols(context, symbolTable) {
+
+ override val ThrowNullPointerException
+ get() = TODO()
+ override val ThrowNoWhenBranchMatchedException
+ get() = TODO()
+ override val ThrowTypeCastException
+ get() = TODO()
+ override val ThrowUninitializedPropertyAccessException
+ get() = TODO()
+ override val defaultConstructorMarker
+ get() = TODO()
+ override val stringBuilder
+ get() = TODO()
+ override val copyRangeTo: Map
+ get() = TODO()
+ override val coroutineImpl
+ get() = TODO()
+ override val coroutineSuspendedGetter
+ get() = TODO()
+ override val getContinuation
+ get() = TODO()
+ override val coroutineContextGetter by lazy {
+ context.excludedDeclarations.addFunction {
+ name = Name.identifier("coroutineContextGetter\$Stub")
+ }.symbol
+ }
+
+ override val suspendCoroutineUninterceptedOrReturn
+ get() = TODO()
+ override val coroutineGetContext
+ get() = TODO()
+ override val returnIfSuspended
+ get() = TODO()
+
+ private val wasmInternalPackage = context.module.getPackage(FqName("kotlin.wasm.internal"))
+
+ val equalityFunctions = mapOf(
+ context.irBuiltIns.booleanType to getInternalFunction("wasm_i32_eq"),
+ context.irBuiltIns.byteType to getInternalFunction("wasm_i32_eq"),
+ context.irBuiltIns.shortType to getInternalFunction("wasm_i32_eq"),
+ 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.floatType to getInternalFunction("wasm_f32_eq"),
+ context.irBuiltIns.doubleType to getInternalFunction("wasm_f64_eq")
+ )
+
+ private fun wasmString(simpleType: SimpleType): String = with(context.irBuiltIns) {
+ when (simpleType) {
+ bool, byte, short, char, int -> "i32"
+ float -> "f32"
+ double -> "f64"
+ long -> "i64"
+ else -> error("Unkonow primitive type")
+ }
+ }
+
+ val irBuiltInsToWasmIntrinsics = context.irBuiltIns.run {
+ mapOf(
+ lessFunByOperandType to "lt",
+ lessOrEqualFunByOperandType to "le",
+ greaterOrEqualFunByOperandType to "ge",
+ greaterFunByOperandType to "gt"
+ ).map { (typeToBuiltIn, wasmOp) ->
+ typeToBuiltIn.map { (type, builtin) ->
+ val wasmType = wasmString(type)
+ val markSign = if (wasmType == "i32" || wasmType == "i64") "_s" else ""
+ builtin to getInternalFunction("wasm_${wasmType}_$wasmOp$markSign")
+ }
+ }.flatten().toMap()
+ }
+
+ val stringGetLiteral = getInternalFunction("stringLiteral")
+
+ private fun findClass(memberScope: MemberScope, name: Name): ClassDescriptor =
+ memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
+
+ private fun findFunctions(memberScope: MemberScope, name: Name): List =
+ memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
+
+ private fun findProperty(memberScope: MemberScope, name: Name): List =
+ memberScope.getContributedVariables(name, NoLookupLocation.FROM_BACKEND).toList()
+
+ internal fun getClass(fqName: FqName): ClassDescriptor =
+ findClass(context.module.getPackage(fqName.parent()).memberScope, fqName.shortName())
+
+ internal fun getProperty(fqName: FqName): PropertyDescriptor =
+ findProperty(context.module.getPackage(fqName.parent()).memberScope, fqName.shortName()).single()
+
+ internal fun getInternalFunction(name: String): IrSimpleFunctionSymbol {
+ val tmp = findFunctions(wasmInternalPackage.memberScope, Name.identifier(name)).single()
+ return symbolTable.referenceSimpleFunction(tmp)
+ }
+
+ private fun getIrClass(fqName: FqName): IrClassSymbol = symbolTable.referenceClass(getClass(fqName))
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmAstToWat.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmAstToWat.kt
new file mode 100644
index 00000000000..60b174504b8
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmAstToWat.kt
@@ -0,0 +1,64 @@
+/*
+ * 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
+
+// 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".toLowerCase()
+}
+
+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 + "\""
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmDeclarations.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmDeclarations.kt
new file mode 100644
index 00000000000..8d0cc6ec4a6
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmDeclarations.kt
@@ -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.ast
+
+import org.jetbrains.kotlin.backend.wasm.utils.WasmImportPair
+
+class WasmModule(
+ val fields: List
+)
+
+sealed class WasmModuleField
+
+class WasmModuleFieldList(
+ val fields: List
+) : WasmModuleField()
+
+class WasmFunction(
+ val name: String,
+ val parameters: List,
+ val returnType: WasmValueType?,
+ val locals: List,
+ val instructions: List,
+ 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")
+ }
+}
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmInstructions.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmInstructions.kt
new file mode 100644
index 00000000000..59c6f28c1e3
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmInstructions.kt
@@ -0,0 +1,65 @@
+/*
+ * 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(val value: T) : WasmImmediate()
+}
+
+sealed class WasmInstruction(
+ val mnemonic: String,
+ val immediate: WasmImmediate = WasmImmediate.None,
+ val operands: List = emptyList()
+)
+
+class WasmSimpleInstruction(mnemonic: String, operands: List) :
+ WasmInstruction(mnemonic, operands = operands)
+
+class WasmNop : WasmInstruction("nop")
+
+class WasmReturn(values: List) :
+ WasmInstruction("return", operands = values)
+
+class WasmDrop(instructions: List) :
+ WasmInstruction("drop", operands = instructions)
+
+class WasmCall(name: String, operands: List) :
+ 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("block", operands = instructions)
+
+sealed class WasmConst(value: KotlinType, type: WasmType) :
+ WasmInstruction(type.mnemonic + ".const", WasmImmediate.LiteralValue(value))
+
+class WasmI32Const(value: Int) : WasmConst(value, WasmI32)
+class WasmI64Const(value: Long) : WasmConst(value, WasmI64)
+class WasmF32Const(value: Float) : WasmConst(value, WasmF32)
+class WasmF64Const(value: Double) : WasmConst(value, WasmF64)
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmTypes.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmTypes.kt
new file mode 100644
index 00000000000..a31df5ef6de
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmTypes.kt
@@ -0,0 +1,15 @@
+/*
+ * 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")
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/BaseTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/BaseTransformer.kt
new file mode 100644
index 00000000000..8ea16a07b6d
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/BaseTransformer.kt
@@ -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.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 : IrElementVisitor {
+ override fun visitElement(element: IrElement, data: D): R {
+ TODO(element)
+ }
+}
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/DeclarationTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/DeclarationTransformer.kt
new file mode 100644
index 00000000000..d59251cf660
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/DeclarationTransformer.kt
@@ -0,0 +1,123 @@
+/*
+ * 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 {
+ 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()
+
+ 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()
+ 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)
+ }
+ )
+ }
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/ExpressionTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/ExpressionTransformer.kt
new file mode 100644
index 00000000000..54ba6905601
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/ExpressionTransformer.kt
@@ -0,0 +1,206 @@
+/*
+ * 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.IrSimpleFunction
+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 {
+ 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 visitConst(expression: IrConst, 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 visitSetVariable(expression: IrSetVariable, 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
+ require(function is IrSimpleFunction) { "Only IrSimpleFunction could be called via IrCall" }
+ 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)
+ when (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)
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/ModuleTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/ModuleTransformer.kt
new file mode 100644
index 00000000000..26dea06a614
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/ModuleTransformer.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.Visibilities
+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 {
+ return JsBlock(
+ jsAssignment(
+ JsNameRef("stringLiterals", "runtime"),
+ JsArrayLiteral(literals.map { JsStringLiteral(it) })
+ ).makeStmt()
+ ).toString()
+ }
+
+ private fun generateExports(module: IrModuleFragment, context: WasmCodegenContext): List {
+ val exports = mutableListOf()
+ 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 != Visibilities.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
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/NameTable.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/NameTable.kt
new file mode 100644
index 00000000000..8369181580d
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/NameTable.kt
@@ -0,0 +1,64 @@
+/*
+ * 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 wasmNameTable() = NameTable(sanitizer = ::sanitizeWatIdentifier)
+
+fun generateWatTopLevelNames(packages: List): Map {
+ val names = wasmNameTable()
+
+ 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 "$.@_"
+
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/StatementTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/StatementTransformer.kt
new file mode 100644
index 00000000000..13776fb2694
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/StatementTransformer.kt
@@ -0,0 +1,35 @@
+/*
+ * 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 {
+ 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 {
+ if (body is IrBlockBody) {
+ return body.statements.map { statementToWasmInstruction(it, context) }
+ } else TODO()
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/TypeTransformer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/TypeTransformer.kt
new file mode 100644
index 00000000000..26e8959961a
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/TypeTransformer.kt
@@ -0,0 +1,27 @@
+/*
+ * 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()}")
+ }
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/WasmCodegenContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/WasmCodegenContext.kt
new file mode 100644
index 00000000000..21218fc17be
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/WasmCodegenContext.kt
@@ -0,0 +1,29 @@
+/*
+ * 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,
+ val backendContext: WasmBackendContext
+) {
+ val imports = mutableListOf()
+ var localNames: Map = emptyMap()
+ val stringLiterals = mutableListOf()
+
+ 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}")
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt
new file mode 100644
index 00000000000..b0aa31bd7b4
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt
@@ -0,0 +1,65 @@
+/*
+ * 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
+
+import com.intellij.openapi.project.Project
+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.config.CompilerConfiguration
+import org.jetbrains.kotlin.ir.backend.js.loadIr
+import org.jetbrains.kotlin.ir.backend.js.sortDependencies
+import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
+import org.jetbrains.kotlin.ir.util.patchDeclarationParents
+import org.jetbrains.kotlin.library.KotlinLibrary
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.KtFile
+
+data class WasmCompilerResult(val wat: String, val js: String)
+
+fun compileWasm(
+ project: Project,
+ files: List,
+ configuration: CompilerConfiguration,
+ phaseConfig: PhaseConfig,
+ allDependencies: List,
+ friendDependencies: List,
+ exportedDeclarations: Set = emptySet()
+): WasmCompilerResult {
+ val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
+ loadIr(project, files, configuration, allDependencies, friendDependencies)
+
+ val moduleDescriptor = moduleFragment.descriptor
+ val context = WasmBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, exportedDeclarations, configuration)
+
+ // Load declarations referenced during `context` initialization
+ dependencyModules.forEach {
+ ExternalDependenciesGenerator(
+ it.descriptor,
+ symbolTable,
+ irBuiltIns,
+ deserializer = deserializer
+ ).generateUnboundSymbolsAsDependencies()
+ }
+
+ // Since modules should be initialized in the correct topological order we sort them
+ val irFiles = sortDependencies(dependencyModules).flatMap { it.files } + moduleFragment.files
+
+ moduleFragment.files.clear()
+ moduleFragment.files += irFiles
+
+ // Create stubs
+ ExternalDependenciesGenerator(
+ moduleDescriptor = moduleDescriptor,
+ symbolTable = symbolTable,
+ irBuiltIns = irBuiltIns
+ ).generateUnboundSymbolsAsDependencies()
+ moduleFragment.patchDeclarationParents()
+
+ wasmPhases.invokeToplevel(phaseConfig, context, moduleFragment)
+
+ return IrModuleToWasm(context).generateModule(moduleFragment)
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BlockDecomposerLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BlockDecomposerLowering.kt
new file mode 100644
index 00000000000..33e411a2e42
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BlockDecomposerLowering.kt
@@ -0,0 +1,14 @@
+/*
+ * 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()
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt
new file mode 100644
index 00000000000..b688091510e
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.wasm.WasmBackendContext
+import org.jetbrains.kotlin.ir.declarations.IrFile
+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.util.irCall
+import org.jetbrains.kotlin.ir.util.render
+import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
+
+class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass {
+ private val irBuiltins = context.irBuiltIns
+ private val symbols = context.wasmSymbols
+
+ fun transformCall(call: IrCall): IrExpression {
+ when (val symbol = call.symbol) {
+ irBuiltins.eqeqSymbol, irBuiltins.eqeqeqSymbol, in irBuiltins.ieee754equalsFunByOperandType.values -> {
+ val type = call.getValueArgument(0)!!.type
+ val newSymbol = symbols.equalityFunctions[type]
+ ?: error("Unsupported equality operator with type: ${type.render()}")
+ return irCall(call, newSymbol)
+ }
+ in symbols.irBuiltInsToWasmIntrinsics.keys -> {
+ val newSymbol = symbols.irBuiltInsToWasmIntrinsics[symbol]!!
+ return irCall(call, newSymbol)
+ }
+ }
+ return call
+ }
+
+ override fun lower(irFile: IrFile) {
+ irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
+ override fun visitCall(expression: IrCall): IrExpression {
+ val newExpression = transformCall(expression)
+ newExpression.transformChildrenVoid(this)
+ return newExpression
+ }
+ })
+ }
+}
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ExcludeDeclarationsFromCodegen.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ExcludeDeclarationsFromCodegen.kt
new file mode 100644
index 00000000000..d61c2dc2ee3
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ExcludeDeclarationsFromCodegen.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.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()
+
+fun excludeDeclarationsFromCodegen(context: WasmBackendContext, module: IrModuleFragment) {
+
+ fun isExcluded(declaration: IrDeclaration): Boolean {
+ if (declaration is IrDeclarationWithName && declaration.fqNameWhenAvailable in BODILESS_BUILTIN_CLASSES)
+ return true
+
+ if (declaration.hasExcludedFromCodegenAnnotation())
+ return true
+
+ val parentFile = declaration.parent as? IrFile
+ if (parentFile?.hasExcludedFromCodegenAnnotation() == true)
+ return true
+
+ return false
+ }
+
+ for (file in module.files) {
+ val it = file.declarations.iterator()
+ while (it.hasNext()) {
+ val d = it.next() as? IrDeclarationWithName ?: continue
+ if (isExcluded(d)) {
+ it.remove()
+ context.excludedDeclarations.addChild(d)
+ }
+ }
+ }
+}
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Annotations.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Annotations.kt
new file mode 100644
index 00000000000..e5765b0bf96
--- /dev/null
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Annotations.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.utils
+
+import org.jetbrains.kotlin.ir.backend.js.utils.getSingleConstStringArgument
+import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
+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
+
+fun IrAnnotationContainer.hasExcludedFromCodegenAnnotation(): Boolean =
+ hasAnnotation(FqName("kotlin.wasm.internal.ExcludedFromCodegen"))
+
+fun IrAnnotationContainer.getWasmInstructionAnnotation(): String? =
+ getAnnotation(FqName("kotlin.wasm.internal.WasmInstruction"))?.getSingleConstStringArgument()
+
+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).value,
+ (it.getValueArgument(1) as IrConst).value
+ )
+ }
diff --git a/compiler/ir/serialization.js/build.gradle.kts b/compiler/ir/serialization.js/build.gradle.kts
index 07db5ca2e64..b0ef55d02c1 100644
--- a/compiler/ir/serialization.js/build.gradle.kts
+++ b/compiler/ir/serialization.js/build.gradle.kts
@@ -189,9 +189,7 @@ val generateReducedRuntimeKLib by eagerTask {
)
}
-val generateWasmRuntimeKLib by task {
- dependsOn(reducedRuntimeSources)
-
+val generateWasmRuntimeKLib by eagerTask {
buildKLib(sources = listOf("$rootDir/libraries/stdlib/wasm"),
dependencies = emptyList(),
outPath = "$buildDir/wasmRuntime/klib",
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/TargetBackend.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/test/TargetBackend.kt
index 62121f817af..404f87093b2 100644
--- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/TargetBackend.kt
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/TargetBackend.kt
@@ -12,7 +12,8 @@ enum class TargetBackend(
JVM,
JVM_IR(JVM),
JS,
- JS_IR(JS);
+ JS_IR(JS),
+ WASM;
val compatibleWith get() = compatibleWithTargetBackend ?: ANY
}
diff --git a/js/js.tests/build.gradle.kts b/js/js.tests/build.gradle.kts
index cf62c8b9705..eddc439e12a 100644
--- a/js/js.tests/build.gradle.kts
+++ b/js/js.tests/build.gradle.kts
@@ -1,15 +1,18 @@
import com.moowork.gradle.node.NodeExtension
import com.moowork.gradle.node.npm.NpmTask
+import de.undercouch.gradle.tasks.download.Download
import org.gradle.internal.os.OperatingSystem
plugins {
kotlin("jvm")
id("jps-compatible")
id("com.moowork.node").version("1.2.0")
+ id("de.undercouch.download")
}
node {
download = true
+ version = "10.16.2"
}
val antLauncherJar by configurations.creating
@@ -27,6 +30,7 @@ dependencies {
testCompileOnly(intellijCoreDep()) { includeJars("intellij-core") }
testCompileOnly(intellijDep()) { includeJars("openapi", "idea", "idea_rt", "util") }
testCompile(project(":compiler:backend.js"))
+ testCompile(project(":compiler:backend.wasm"))
testCompile(projectTests(":compiler:ir.serialization.js"))
testCompile(project(":js:js.translator"))
testCompile(project(":js:js.serializer"))
@@ -65,7 +69,7 @@ sourceSets {
}
-fun Test.setUpBoxTests(jsEnabled: Boolean, jsIrEnabled: Boolean) {
+fun Test.setUpJsBoxTests(jsEnabled: Boolean, jsIrEnabled: Boolean) {
dependsOn(":dist")
if (jsEnabled) dependsOn(testJsRuntime)
if (jsIrEnabled) {
@@ -74,14 +78,20 @@ fun Test.setUpBoxTests(jsEnabled: Boolean, jsIrEnabled: Boolean) {
dependsOn(":compiler:ir.serialization.js:generateKotlinTestKLib")
}
+ exclude("org/jetbrains/kotlin/js/test/wasm/semantics/*")
+
if (jsEnabled && !jsIrEnabled) exclude("org/jetbrains/kotlin/js/test/ir/semantics/*")
if (!jsEnabled && jsIrEnabled) include("org/jetbrains/kotlin/js/test/ir/semantics/*")
jvmArgs("-da:jdk.nashorn.internal.runtime.RecompilableScriptFunctionData") // Disable assertion which fails due to a bug in nashorn (KT-23637)
- workingDir = rootDir
if (findProperty("kotlin.compiler.js.ir.tests.skip")?.toString()?.toBoolean() == true) {
exclude("org/jetbrains/kotlin/js/test/ir/semantics/*")
}
+ setUpBoxTests()
+}
+
+fun Test.setUpBoxTests() {
+ workingDir = rootDir
doFirst {
systemProperty("kotlin.ant.classpath", antLauncherJar.asPath)
systemProperty("kotlin.ant.launcher.class", "org.apache.tools.ant.Main")
@@ -96,19 +106,19 @@ fun Test.setUpBoxTests(jsEnabled: Boolean, jsIrEnabled: Boolean) {
}
projectTest(parallel = true) {
- setUpBoxTests(jsEnabled = true, jsIrEnabled = true)
+ setUpJsBoxTests(jsEnabled = true, jsIrEnabled = true)
}
projectTest("jsTest", true) {
- setUpBoxTests(jsEnabled = true, jsIrEnabled = false)
+ setUpJsBoxTests(jsEnabled = true, jsIrEnabled = false)
}
projectTest("jsIrTest", true) {
- setUpBoxTests(jsEnabled = false, jsIrEnabled = true)
+ setUpJsBoxTests(jsEnabled = false, jsIrEnabled = true)
}
projectTest("quickTest", true) {
- setUpBoxTests(jsEnabled = true, jsIrEnabled = false)
+ setUpJsBoxTests(jsEnabled = true, jsIrEnabled = false)
systemProperty("kotlin.js.skipMinificationTest", "true")
}
@@ -136,3 +146,58 @@ val runMocha by task {
val check by tasks
check.dependsOn(this)
}
+
+enum class OsName { WINDOWS, MAC, LINUX, UNKNOWN }
+enum class OsArch { X86_32, X86_64, UNKNOWN }
+data class OsType(val name: OsName, val arch: OsArch)
+val currentOsType = run {
+ val gradleOs = OperatingSystem.current()
+ val osName = when {
+ gradleOs.isMacOsX -> OsName.MAC
+ gradleOs.isWindows -> OsName.WINDOWS
+ gradleOs.isLinux -> OsName.LINUX
+ else -> OsName.UNKNOWN
+ }
+
+ val osArch = when (System.getProperty("sun.arch.data.model")) {
+ "32" -> OsArch.X86_32
+ "64" -> OsArch.X86_64
+ else -> OsArch.UNKNOWN
+ }
+
+ OsType(osName, osArch)
+}
+
+val jsShellDirectory = "https://archive.mozilla.org/pub/firefox/nightly/2019/08/2019-08-11-09-56-40-mozilla-central"
+val jsShellSuffix = when (currentOsType) {
+ OsType(OsName.LINUX, OsArch.X86_32) -> "linux-i686"
+ OsType(OsName.LINUX, OsArch.X86_64) -> "linux-x86_64"
+ OsType(OsName.MAC, OsArch.X86_64) -> "mac"
+ OsType(OsName.WINDOWS, OsArch.X86_32) -> "win32"
+ OsType(OsName.WINDOWS, OsArch.X86_64) -> "win64"
+ else -> error("unsupported os type $currentOsType")
+}
+val jsShellLocation = "$jsShellDirectory/jsshell-$jsShellSuffix.zip"
+
+val downloadedTools = File(buildDir, "tools")
+
+val downloadJsShell by task {
+ src(jsShellLocation)
+ dest(File(downloadedTools, "jsshell-$jsShellSuffix.zip"))
+}
+
+val unzipJsShell by task {
+ dependsOn(downloadJsShell)
+ from(zipTree(downloadJsShell.get().dest))
+ val unpackedDir = File(downloadedTools, "jsshell-$jsShellSuffix")
+ into(unpackedDir)
+}
+
+projectTest("wasmTest", true) {
+ dependsOn(unzipJsShell)
+ dependsOn(":compiler:ir.serialization.js:generateWasmRuntimeKLib")
+ include("org/jetbrains/kotlin/js/test/wasm/semantics/*")
+ val jsShellExecutablePath = File(unzipJsShell.get().destinationDir, "js").absolutePath
+ systemProperty("javascript.engine.path.SpiderMonkey", jsShellExecutablePath)
+ setUpBoxTests()
+}
diff --git a/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt b/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt
index db3206d0ce6..f5ab018acdd 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt
+++ b/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.js.test.AbstractDceTest
import org.jetbrains.kotlin.js.test.AbstractJsLineNumberTest
import org.jetbrains.kotlin.js.test.ir.semantics.*
import org.jetbrains.kotlin.js.test.semantics.*
+import org.jetbrains.kotlin.js.test.wasm.semantics.AbstractIrWasmBoxWasmTest
import org.jetbrains.kotlin.test.TargetBackend
fun main(args: Array) {
@@ -42,6 +43,14 @@ fun main(args: Array) {
testClass {
model("lineNumbers/", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS)
}
+
+ testClass {
+ model("wasmBox", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.WASM)
+ }
+
+ testClass {
+ model("wasmBox", pattern = "^([^_](.+))\\.kt$", targetBackend = TargetBackend.JS_IR)
+ }
}
testGroup("js/js.tests/test", "compiler/testData", testRunnerMethodName = "runTest0") {
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicWasmBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicWasmBoxTest.kt
new file mode 100644
index 00000000000..24c89fcb0cd
--- /dev/null
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicWasmBoxTest.kt
@@ -0,0 +1,194 @@
+/*
+ * 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.js.test
+
+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 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.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.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.SpiderMonkeyEngine
+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.KotlinTestUtils
+import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
+import java.io.Closeable
+import java.io.File
+
+private val wasmRuntimeKlib =
+ loadKlib("compiler/ir/serialization.js/build/wasmRuntime/klib")
+
+abstract class BasicWasmBoxTest(
+ private val pathToTestDir: String,
+ testGroupOutputDirPrefix: String,
+ pathToRootOutputDir: String = TEST_DATA_DIR_PATH
+) : KotlinTestWithEnvironment() {
+ private val testGroupOutputDirForCompilation = File(pathToRootOutputDir + "out/" + testGroupOutputDirPrefix)
+
+ private val spiderMonkey by lazy { SpiderMonkeyEngine() }
+
+ fun doTest(filePath: String) {
+ val file = File(filePath)
+ val outputDir = getOutputDir(file)
+ val fileContent = KotlinTestUtils.doLoadFile(file)
+
+ TestFileFactoryImpl().use { testFactory ->
+ val inputFiles: MutableList = KotlinTestUtils.createTestFiles(file.name, fileContent, testFactory, true, "")
+ val testPackage = testFactory.testPackage
+ val outputFileBase = outputDir.absolutePath + "/" + getTestName(true)
+ val outputWatFile = outputFileBase + ".wat"
+ val outputJsFile = outputFileBase + ".js"
+
+ val kotlinFiles = inputFiles.filter { it.fileName.endsWith(".kt") }
+ val psiFiles = createPsiFiles(kotlinFiles.map { File(it.fileName).canonicalPath }.sorted())
+ val config = createConfig()
+ translateFiles(
+ psiFiles.map(TranslationUnit::SourceFile),
+ File(outputWatFile),
+ File(outputJsFile),
+ config,
+ testPackage,
+ TEST_FUNCTION
+ )
+
+ spiderMonkey.runFile(outputJsFile)
+ }
+ }
+
+ private fun getOutputDir(file: File, testGroupOutputDir: File = testGroupOutputDirForCompilation): File {
+ val stopFile = File(pathToTestDir)
+ return generateSequence(file.parentFile) { it.parentFile }
+ .takeWhile { it != stopFile }
+ .map { it.name }
+ .toList().asReversed()
+ .fold(testGroupOutputDir, ::File)
+ }
+
+ private fun translateFiles(
+ units: List,
+ outputWatFile: File,
+ outputJsFile: File,
+ config: JsConfig,
+ testPackage: String?,
+ testFunction: String
+ ) {
+ val filesToCompile = units.map { (it as TranslationUnit.SourceFile).file }
+ val debugMode = false
+
+ 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")
+ PhaseConfig(
+ wasmPhases,
+ dumpToDirectory = dumpOutputDir.path,
+ toDumpStateAfter = allPhasesSet,
+ toValidateStateAfter = allPhasesSet,
+ dumpOnlyFqName = null
+ )
+ } else {
+ PhaseConfig(wasmPhases)
+ }
+
+ val compilerResult = compileWasm(
+ project = config.project,
+ files = filesToCompile,
+ configuration = config.configuration,
+ phaseConfig = phaseConfig,
+ allDependencies = listOf(wasmRuntimeKlib),
+ friendDependencies = emptyList(),
+ exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, testFunction)))
+ )
+
+ outputWatFile.write(compilerResult.wat)
+
+ val runtime = File("libraries/stdlib/wasm/runtime/runtime.js").readText()
+
+ val testRunner = """
+ const wat = read(String.raw`${outputWatFile.absoluteFile}`);
+ const wasmBinary = wasmTextToBinary(wat);
+ const wasmModule = new WebAssembly.Module(wasmBinary);
+ const wasmInstance = new WebAssembly.Instance(wasmModule, { runtime });
+
+ const actualResult = wasmInstance.exports.$testFunction();
+ if (actualResult !== "OK")
+ throw `Wrong box result '${'$'}{actualResult}'; Expected "OK"`;
+ """.trimIndent()
+
+ 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): List = fileNames.map(this::createPsiFile)
+
+ private fun createConfig(): JsConfig {
+ val configuration = environment.configuration.copy()
+ configuration.put(CommonConfigurationKeys.MODULE_NAME, TEST_MODULE)
+ return JsConfig(project, configuration, null, null)
+ }
+
+ private inner class TestFileFactoryImpl : KotlinTestUtils.TestFileFactoryNoModules(), Closeable {
+ override fun create(fileName: String, text: String, directives: MutableMap): TestFile {
+ val ktFile = KtPsiFactory(project).createFile(text)
+ val boxFunction = ktFile.declarations.find { it is KtNamedFunction && it.name == TEST_FUNCTION }
+ if (boxFunction != null) {
+ testPackage = ktFile.packageFqName.asString()
+ if (testPackage?.isEmpty() == true) {
+ testPackage = null
+ }
+ }
+
+ val temporaryFile = File(tmpDir, "WASM_TEST/$fileName")
+ KotlinTestUtils.mkdirs(temporaryFile.parentFile)
+ temporaryFile.writeText(text, Charsets.UTF_8)
+
+ return TestFile(temporaryFile.absolutePath)
+ }
+
+ var testPackage: String? = null
+ val tmpDir = KotlinTestUtils.tmpDir("wasm-tests")
+
+ override fun close() {
+ FileUtil.delete(tmpDir)
+ }
+ }
+
+ private class TestFile(val fileName: String)
+
+ override fun createEnvironment() =
+ KotlinCoreEnvironment.createForTests(testRootDisposable, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
+
+ companion object {
+ const val TEST_DATA_DIR_PATH = "js/js.translator/testData/"
+ const val TEST_MODULE = "WASM_TESTS"
+ private const val TEST_FUNCTION = "box"
+ }
+}
+
+private fun File.write(text: String) {
+ parentFile.mkdirs()
+ writeText(text)
+}
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/engines/SpiderMonkey.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/engines/SpiderMonkey.kt
new file mode 100644
index 00000000000..76fc2836e14
--- /dev/null
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/engines/SpiderMonkey.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.js.test.engines
+
+import java.io.BufferedReader
+import java.io.InputStreamReader
+import kotlin.test.fail
+
+class ExternalTool(val path: String) {
+ fun run(vararg arguments: String) {
+ val command = arrayOf(path, *arguments)
+ val process = ProcessBuilder(*command)
+ .redirectErrorStream(true)
+ .start()
+
+ val commandString = command.joinToString(" ") { escapeShellArgument(it) }
+ println(commandString)
+
+ // Print process output
+ val input = BufferedReader(InputStreamReader(process.inputStream))
+ while (true) println(input.readLine() ?: break)
+
+ val exitValue = process.waitFor()
+ if (exitValue != 0) {
+ fail("Command \"$commandString\" terminated with exit code $exitValue")
+ }
+ }
+}
+
+private fun escapeShellArgument(arg: String): String =
+ "'${arg.replace("'", "'\\''")}'"
+
+class SpiderMonkeyEngine(
+ jsShellPath: String = System.getProperty("javascript.engine.path.SpiderMonkey")
+) {
+ private val jsShell = ExternalTool(jsShellPath)
+
+ fun runFile(file: String) {
+ jsShell.run(file)
+ }
+}
\ No newline at end of file
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrWasmBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrWasmBoxJsTestGenerated.java
new file mode 100644
index 00000000000..6c6b5a9e676
--- /dev/null
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrWasmBoxJsTestGenerated.java
@@ -0,0 +1,548 @@
+/*
+ * 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.js.test.ir.semantics;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
+import org.jetbrains.kotlin.test.KotlinTestUtils;
+import org.jetbrains.kotlin.test.TargetBackend;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
+@SuppressWarnings("all")
+@TestMetadata("js/js.translator/testData/wasmBox")
+@TestDataPath("$PROJECT_ROOT")
+@RunWith(JUnit3RunnerWithInners.class)
+public class IrWasmBoxJsTestGenerated extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInWasmBox() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("basicTypes.kt")
+ public void testBasicTypes() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/basicTypes.kt");
+ }
+
+ @TestMetadata("primitivesOperatos.kt")
+ public void testPrimitivesOperatos() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/primitivesOperatos.kt");
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/number")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Number extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInNumber() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/number"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("assignmentIntOverflow.kt")
+ public void testAssignmentIntOverflow() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/assignmentIntOverflow.kt");
+ }
+
+ @TestMetadata("byteAndShortConversions.kt")
+ public void testByteAndShortConversions() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/byteAndShortConversions.kt");
+ }
+
+ @TestMetadata("conversionsWithTruncation.kt")
+ public void testConversionsWithTruncation() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/conversionsWithTruncation.kt");
+ }
+
+ @TestMetadata("conversionsWithoutTruncation.kt")
+ public void testConversionsWithoutTruncation() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/conversionsWithoutTruncation.kt");
+ }
+
+ @TestMetadata("division.kt")
+ public void testDivision() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/division.kt");
+ }
+
+ @TestMetadata("doubleConversions.kt")
+ public void testDoubleConversions() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/doubleConversions.kt");
+ }
+
+ @TestMetadata("hexadecimalConstant.kt")
+ public void testHexadecimalConstant() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/hexadecimalConstant.kt");
+ }
+
+ @TestMetadata("incDecOptimization.kt")
+ public void testIncDecOptimization() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/incDecOptimization.kt");
+ }
+
+ @TestMetadata("intConversions.kt")
+ public void testIntConversions() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/intConversions.kt");
+ }
+
+ @TestMetadata("intDivFloat.kt")
+ public void testIntDivFloat() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/intDivFloat.kt");
+ }
+
+ @TestMetadata("intIncDecOverflow.kt")
+ public void testIntIncDecOverflow() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/intIncDecOverflow.kt");
+ }
+
+ @TestMetadata("intOverflow.kt")
+ public void testIntOverflow() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/intOverflow.kt");
+ }
+
+ @TestMetadata("kt2342.kt")
+ public void testKt2342() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/kt2342.kt");
+ }
+
+ @TestMetadata("longBinaryOperations.kt")
+ public void testLongBinaryOperations() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longBinaryOperations.kt");
+ }
+
+ @TestMetadata("longBitOperations.kt")
+ public void testLongBitOperations() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longBitOperations.kt");
+ }
+
+ @TestMetadata("longCompareToIntrinsic.kt")
+ public void testLongCompareToIntrinsic() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longCompareToIntrinsic.kt");
+ }
+
+ @TestMetadata("longEqualsIntrinsic.kt")
+ public void testLongEqualsIntrinsic() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longEqualsIntrinsic.kt");
+ }
+
+ @TestMetadata("longHashCode.kt")
+ public void testLongHashCode() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longHashCode.kt");
+ }
+
+ @TestMetadata("longUnaryOperations.kt")
+ public void testLongUnaryOperations() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longUnaryOperations.kt");
+ }
+
+ @TestMetadata("mixedTypesOverflow.kt")
+ public void testMixedTypesOverflow() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/mixedTypesOverflow.kt");
+ }
+
+ @TestMetadata("numberCompareTo.kt")
+ public void testNumberCompareTo() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/numberCompareTo.kt");
+ }
+
+ @TestMetadata("numberConversions.kt")
+ public void testNumberConversions() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/numberConversions.kt");
+ }
+
+ @TestMetadata("numberEquals.kt")
+ public void testNumberEquals() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/numberEquals.kt");
+ }
+
+ @TestMetadata("numberIncDec.kt")
+ public void testNumberIncDec() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/numberIncDec.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class PassedCommonTests extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInPassedCommonTests() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class BoxingOptimization extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInBoxingOptimization() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("explicitEqualsOnDouble.kt")
+ public void testExplicitEqualsOnDouble() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization/explicitEqualsOnDouble.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/classes")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Classes extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInClasses() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/classes"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("kt2482.kt")
+ public void testKt2482() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/classes/kt2482.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/constants")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Constants extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInConstants() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/constants"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("float.kt")
+ public void testFloat() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/constants/float.kt");
+ }
+
+ @TestMetadata("long.kt")
+ public void testLong() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/constants/long.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ControlStructures extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInControlStructures() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("ifConst1.kt")
+ public void testIfConst1() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst1.kt");
+ }
+
+ @TestMetadata("ifConst2.kt")
+ public void testIfConst2() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst2.kt");
+ }
+
+ @TestMetadata("kt1899.kt")
+ public void testKt1899() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/kt1899.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ExtensionProperties extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInExtensionProperties() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("topLevel.kt")
+ public void testTopLevel() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties/topLevel.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/functions")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Functions extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInFunctions() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/functions"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("kt2280.kt")
+ public void testKt2280() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/functions/kt2280.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/ieee754")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Ieee754 extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInIeee754() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/ieee754"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("lessDouble_properIeeeAndNewInference.kt")
+ public void testLessDouble_properIeeeAndNewInference() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/ieee754/lessDouble_properIeeeAndNewInference.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/ir")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Ir extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInIr() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/ir"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ClosureConversion extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInClosureConversion() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("closureConversion1.kt")
+ public void testClosureConversion1() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion1.kt");
+ }
+
+ @TestMetadata("closureConversion3.kt")
+ public void testClosureConversion3() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion3.kt");
+ }
+
+ @TestMetadata("closureConversion4.kt")
+ public void testClosureConversion4() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion4.kt");
+ }
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/labels")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Labels extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInLabels() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/labels"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("propertyAccessor.kt")
+ public void testPropertyAccessor() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/labels/propertyAccessor.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class LazyCodegen extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInLazyCodegen() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Optimizations extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInOptimizations() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("negateConstantCompare.kt")
+ public void testNegateConstantCompare() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations/negateConstantCompare.kt");
+ }
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class OperatorConventions extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInOperatorConventions() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("annotatedAssignment.kt")
+ public void testAnnotatedAssignment() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/annotatedAssignment.kt");
+ }
+
+ @TestMetadata("infixFunctionOverBuiltinMember.kt")
+ public void testInfixFunctionOverBuiltinMember() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/infixFunctionOverBuiltinMember.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class PrimitiveTypes extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInPrimitiveTypes() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("ea35963.kt")
+ public void testEa35963() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/ea35963.kt");
+ }
+
+ @TestMetadata("incrementByteCharShort.kt")
+ public void testIncrementByteCharShort() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/incrementByteCharShort.kt");
+ }
+
+ @TestMetadata("kt1634.kt")
+ public void testKt1634() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt1634.kt");
+ }
+
+ @TestMetadata("kt3078.kt")
+ public void testKt3078() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt3078.kt");
+ }
+
+ @TestMetadata("kt6590_identityEquals.kt")
+ public void testKt6590_identityEquals() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt6590_identityEquals.kt");
+ }
+
+ @TestMetadata("kt737.kt")
+ public void testKt737() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt737.kt");
+ }
+
+ @TestMetadata("kt828.kt")
+ public void testKt828() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt828.kt");
+ }
+
+ @TestMetadata("kt877.kt")
+ public void testKt877() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt877.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/publishedApi")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class PublishedApi extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInPublishedApi() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/publishedApi"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("topLevel.kt")
+ public void testTopLevel() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/publishedApi/topLevel.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/unaryOp")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class UnaryOp extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInUnaryOp() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/unaryOp"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("intrinsic.kt")
+ public void testIntrinsic() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/unaryOp/intrinsic.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/when")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class When extends AbstractIrWasmBoxJsTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInWhen() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/when"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS_IR, true);
+ }
+
+ @TestMetadata("noElseNoMatch.kt")
+ public void testNoElseNoMatch() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/when/noElseNoMatch.kt");
+ }
+ }
+ }
+}
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/abstractClassesForGeneratedIrTests.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/abstractClassesForGeneratedIrTests.kt
index 1f69a207fb1..288e97e159d 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/abstractClassesForGeneratedIrTests.kt
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/abstractClassesForGeneratedIrTests.kt
@@ -15,6 +15,11 @@ abstract class AbstractIrJsCodegenBoxTest : BasicIrBoxTest(
"codegen/irBox/"
)
+abstract class AbstractIrWasmBoxJsTest : BasicIrBoxTest(
+ BasicBoxTest.TEST_DATA_DIR_PATH + "wasmBox/",
+ "irWasmBox/"
+)
+
abstract class BorrowedIrInlineTest(relativePath: String) : BasicIrBoxTest(
"compiler/testData/codegen/boxInline/$relativePath",
"codegen/irBoxInline/$relativePath"
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/wasm/semantics/IrWasmBoxWasmTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/wasm/semantics/IrWasmBoxWasmTestGenerated.java
new file mode 100644
index 00000000000..02eabce5809
--- /dev/null
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/wasm/semantics/IrWasmBoxWasmTestGenerated.java
@@ -0,0 +1,553 @@
+/*
+ * 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.js.test.wasm.semantics;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
+import org.jetbrains.kotlin.test.KotlinTestUtils;
+import org.jetbrains.kotlin.test.TargetBackend;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
+@SuppressWarnings("all")
+@TestMetadata("js/js.translator/testData/wasmBox")
+@TestDataPath("$PROJECT_ROOT")
+@RunWith(JUnit3RunnerWithInners.class)
+public class IrWasmBoxWasmTestGenerated extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInWasmBox() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("basicTypes.kt")
+ public void testBasicTypes() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/basicTypes.kt");
+ }
+
+ @TestMetadata("primitivesOperatos.kt")
+ public void testPrimitivesOperatos() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/primitivesOperatos.kt");
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/number")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Number extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInNumber() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/number"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("assignmentIntOverflow.kt")
+ public void testAssignmentIntOverflow() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/assignmentIntOverflow.kt");
+ }
+
+ @TestMetadata("byteAndShortConversions.kt")
+ public void testByteAndShortConversions() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/byteAndShortConversions.kt");
+ }
+
+ @TestMetadata("conversionsWithTruncation.kt")
+ public void testConversionsWithTruncation() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/conversionsWithTruncation.kt");
+ }
+
+ @TestMetadata("conversionsWithoutTruncation.kt")
+ public void testConversionsWithoutTruncation() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/conversionsWithoutTruncation.kt");
+ }
+
+ @TestMetadata("division.kt")
+ public void testDivision() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/division.kt");
+ }
+
+ @TestMetadata("doubleConversions.kt")
+ public void testDoubleConversions() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/doubleConversions.kt");
+ }
+
+ @TestMetadata("hashCode.kt")
+ public void testHashCode() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/hashCode.kt");
+ }
+
+ @TestMetadata("hexadecimalConstant.kt")
+ public void testHexadecimalConstant() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/hexadecimalConstant.kt");
+ }
+
+ @TestMetadata("incDecOptimization.kt")
+ public void testIncDecOptimization() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/incDecOptimization.kt");
+ }
+
+ @TestMetadata("intConversions.kt")
+ public void testIntConversions() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/intConversions.kt");
+ }
+
+ @TestMetadata("intDivFloat.kt")
+ public void testIntDivFloat() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/intDivFloat.kt");
+ }
+
+ @TestMetadata("intIncDecOverflow.kt")
+ public void testIntIncDecOverflow() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/intIncDecOverflow.kt");
+ }
+
+ @TestMetadata("intOverflow.kt")
+ public void testIntOverflow() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/intOverflow.kt");
+ }
+
+ @TestMetadata("kt2342.kt")
+ public void testKt2342() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/kt2342.kt");
+ }
+
+ @TestMetadata("longBinaryOperations.kt")
+ public void testLongBinaryOperations() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longBinaryOperations.kt");
+ }
+
+ @TestMetadata("longBitOperations.kt")
+ public void testLongBitOperations() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longBitOperations.kt");
+ }
+
+ @TestMetadata("longCompareToIntrinsic.kt")
+ public void testLongCompareToIntrinsic() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longCompareToIntrinsic.kt");
+ }
+
+ @TestMetadata("longEqualsIntrinsic.kt")
+ public void testLongEqualsIntrinsic() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longEqualsIntrinsic.kt");
+ }
+
+ @TestMetadata("longHashCode.kt")
+ public void testLongHashCode() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longHashCode.kt");
+ }
+
+ @TestMetadata("longUnaryOperations.kt")
+ public void testLongUnaryOperations() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/longUnaryOperations.kt");
+ }
+
+ @TestMetadata("mixedTypesOverflow.kt")
+ public void testMixedTypesOverflow() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/mixedTypesOverflow.kt");
+ }
+
+ @TestMetadata("numberCompareTo.kt")
+ public void testNumberCompareTo() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/numberCompareTo.kt");
+ }
+
+ @TestMetadata("numberConversions.kt")
+ public void testNumberConversions() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/numberConversions.kt");
+ }
+
+ @TestMetadata("numberEquals.kt")
+ public void testNumberEquals() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/numberEquals.kt");
+ }
+
+ @TestMetadata("numberIncDec.kt")
+ public void testNumberIncDec() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/number/numberIncDec.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class PassedCommonTests extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInPassedCommonTests() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class BoxingOptimization extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInBoxingOptimization() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("explicitEqualsOnDouble.kt")
+ public void testExplicitEqualsOnDouble() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization/explicitEqualsOnDouble.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/classes")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Classes extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInClasses() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/classes"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("kt2482.kt")
+ public void testKt2482() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/classes/kt2482.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/constants")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Constants extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInConstants() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/constants"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("float.kt")
+ public void testFloat() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/constants/float.kt");
+ }
+
+ @TestMetadata("long.kt")
+ public void testLong() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/constants/long.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ControlStructures extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInControlStructures() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("ifConst1.kt")
+ public void testIfConst1() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst1.kt");
+ }
+
+ @TestMetadata("ifConst2.kt")
+ public void testIfConst2() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst2.kt");
+ }
+
+ @TestMetadata("kt1899.kt")
+ public void testKt1899() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/kt1899.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ExtensionProperties extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInExtensionProperties() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("topLevel.kt")
+ public void testTopLevel() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties/topLevel.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/functions")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Functions extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInFunctions() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/functions"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("kt2280.kt")
+ public void testKt2280() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/functions/kt2280.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/ieee754")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Ieee754 extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInIeee754() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/ieee754"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("lessDouble_properIeeeAndNewInference.kt")
+ public void testLessDouble_properIeeeAndNewInference() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/ieee754/lessDouble_properIeeeAndNewInference.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/ir")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Ir extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInIr() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/ir"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ClosureConversion extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInClosureConversion() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("closureConversion1.kt")
+ public void testClosureConversion1() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion1.kt");
+ }
+
+ @TestMetadata("closureConversion3.kt")
+ public void testClosureConversion3() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion3.kt");
+ }
+
+ @TestMetadata("closureConversion4.kt")
+ public void testClosureConversion4() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion4.kt");
+ }
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/labels")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Labels extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInLabels() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/labels"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("propertyAccessor.kt")
+ public void testPropertyAccessor() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/labels/propertyAccessor.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class LazyCodegen extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInLazyCodegen() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class Optimizations extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInOptimizations() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("negateConstantCompare.kt")
+ public void testNegateConstantCompare() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations/negateConstantCompare.kt");
+ }
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class OperatorConventions extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInOperatorConventions() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("annotatedAssignment.kt")
+ public void testAnnotatedAssignment() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/annotatedAssignment.kt");
+ }
+
+ @TestMetadata("infixFunctionOverBuiltinMember.kt")
+ public void testInfixFunctionOverBuiltinMember() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/infixFunctionOverBuiltinMember.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class PrimitiveTypes extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInPrimitiveTypes() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("ea35963.kt")
+ public void testEa35963() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/ea35963.kt");
+ }
+
+ @TestMetadata("incrementByteCharShort.kt")
+ public void testIncrementByteCharShort() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/incrementByteCharShort.kt");
+ }
+
+ @TestMetadata("kt1634.kt")
+ public void testKt1634() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt1634.kt");
+ }
+
+ @TestMetadata("kt3078.kt")
+ public void testKt3078() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt3078.kt");
+ }
+
+ @TestMetadata("kt6590_identityEquals.kt")
+ public void testKt6590_identityEquals() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt6590_identityEquals.kt");
+ }
+
+ @TestMetadata("kt737.kt")
+ public void testKt737() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt737.kt");
+ }
+
+ @TestMetadata("kt828.kt")
+ public void testKt828() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt828.kt");
+ }
+
+ @TestMetadata("kt877.kt")
+ public void testKt877() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt877.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/publishedApi")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class PublishedApi extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInPublishedApi() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/publishedApi"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("topLevel.kt")
+ public void testTopLevel() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/publishedApi/topLevel.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/unaryOp")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class UnaryOp extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInUnaryOp() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/unaryOp"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("intrinsic.kt")
+ public void testIntrinsic() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/unaryOp/intrinsic.kt");
+ }
+ }
+
+ @TestMetadata("js/js.translator/testData/wasmBox/passedCommonTests/when")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class When extends AbstractIrWasmBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInWhen() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/wasmBox/passedCommonTests/when"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.WASM, true);
+ }
+
+ @TestMetadata("noElseNoMatch.kt")
+ public void testNoElseNoMatch() throws Exception {
+ runTest("js/js.translator/testData/wasmBox/passedCommonTests/when/noElseNoMatch.kt");
+ }
+ }
+ }
+}
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/wasm/semantics/abstractClassesForGeneratedWasmTests.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/wasm/semantics/abstractClassesForGeneratedWasmTests.kt
new file mode 100644
index 00000000000..a4535642435
--- /dev/null
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/wasm/semantics/abstractClassesForGeneratedWasmTests.kt
@@ -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.js.test.wasm.semantics
+
+import org.jetbrains.kotlin.js.test.BasicBoxTest
+import org.jetbrains.kotlin.js.test.BasicWasmBoxTest
+
+abstract class AbstractIrWasmBoxWasmTest : BasicWasmBoxTest(BasicBoxTest.TEST_DATA_DIR_PATH + "wasmBox", "wasmBox/")
+
+abstract class AbstractIrCodegenBoxWasmTest : BasicWasmBoxTest(
+ "compiler/testData/codegen/box/",
+ "codegen/wasmBox/"
+)
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/basicTypes.kt b/js/js.translator/testData/wasmBox/basicTypes.kt
new file mode 100644
index 00000000000..53fe93c582d
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/basicTypes.kt
@@ -0,0 +1,44 @@
+
+fun foo(
+ x1: Int,
+ x2: Long,
+ x3: Float,
+ x4: Double
+): Int {
+ var mtmp1: Int = 0
+ var mtmp2: Long = 0L
+ var mtmp3: Float = 0f
+ var mtmp4: Double = 0.0
+ val tmp1 = x1
+ val tmp2 = x2
+ val tmp3 = x3
+ val tmp4 = x4
+ mtmp1 = x1
+ mtmp2 = x2
+ mtmp3 = x3
+ mtmp4 = x4
+ return mtmp1
+}
+
+var g1: Int = 0
+var g2: Long = 0L
+var g3: Float = 0f
+var g4: Double = 0.0
+fun fooUnit() {
+ g1 = 10
+ g2 = 10L
+ g3 = 10f
+ g4 = 10.0
+ g1 = g1
+ g2 = g2
+ g3 = g3
+ g4 = g4
+}
+
+fun box(): String {
+ fooUnit()
+ val res = foo(42, 100L, 100f, 100.0)
+ if (res == 42)
+ return "OK"
+ return "Fail"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/assignmentIntOverflow.kt b/js/js.translator/testData/wasmBox/number/assignmentIntOverflow.kt
new file mode 100644
index 00000000000..caeb9c2b2c8
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/assignmentIntOverflow.kt
@@ -0,0 +1,26 @@
+// EXPECTED_REACHABLE_NODES: 1282
+package foo
+
+fun bigValue() = 0x7FFFFFFC
+
+fun mediumValue() = 0x12345
+
+fun box(): String {
+ var v = bigValue()
+ v += 1
+ if (v != 0x7FFFFFFD) return "fail1"
+
+ v = bigValue()
+ v += 8
+ if (v != -0x7FFFFFFC) return "fail2"
+
+ v = mediumValue()
+ v *= 0x23456
+ if (v != -2112496338) return "fail3"
+
+ v = bigValue()
+ v *= bigValue()
+ if (v != 16) return "fail4"
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/byteAndShortConversions.kt b/js/js.translator/testData/wasmBox/number/byteAndShortConversions.kt
new file mode 100644
index 00000000000..1e5d7d6dcb0
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/byteAndShortConversions.kt
@@ -0,0 +1,46 @@
+// EXPECTED_REACHABLE_NODES: 1284
+package foo
+
+fun testShortConversions(c: Short): Boolean {
+ if (c.toDouble() != 3.0) {
+ return false
+ }
+ if (c.toFloat() != 3.toFloat()) {
+ return false
+ }
+ if (c.toByte() != 3.toByte()) {
+ return false
+ }
+ if (c.toInt() != 3) {
+ return false
+ }
+ if (c.toShort() != 3.toShort()) {
+ return false
+ }
+ return true
+}
+
+fun testByteConversions(c: Byte): Boolean {
+ if (c.toDouble() != 3.0) {
+ return false
+ }
+ if (c.toFloat() != 3.toFloat()) {
+ return false
+ }
+ if (c.toByte() != 3.toByte()) {
+ return false
+ }
+ if (c.toInt() != 3) {
+ return false
+ }
+ if (c.toShort() != 3.toShort()) {
+ return false
+ }
+ return true
+}
+
+fun box(): String {
+ if (!testShortConversions(3)) return "fail: testShortConversions"
+ if (!testByteConversions(3)) return "fail: testByteConversions"
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/conversionsWithTruncation.kt b/js/js.translator/testData/wasmBox/number/conversionsWithTruncation.kt
new file mode 100644
index 00000000000..9561aedda9e
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/conversionsWithTruncation.kt
@@ -0,0 +1,51 @@
+// EXPECTED_REACHABLE_NODES: 1227
+package foo
+
+// TODO: Floats to ints
+
+fun box(): String {
+
+// assertEquals(65, 321.0.toByte())
+// assertEquals(-56, 200.0.toByte())
+//
+// assertEquals(65, 321.0f.toByte())
+// assertEquals(-56, 200.0f.toByte())
+
+ assertEquals(65, 321L.toByte())
+ assertEquals(-56, 200L.toByte())
+
+ assertEquals(65, 321.toByte())
+ assertEquals(-56, 200.toByte())
+
+ assertEquals(65, (321.toShort()).toByte())
+ assertEquals(-56, (200.toShort()).toByte())
+
+// assertEquals(-1, 65535.0.toShort())
+// assertEquals(-1, 65535.0f.toShort())
+ assertEquals(-1, 65535L.toShort())
+ assertEquals(-1, 65535.toShort())
+
+// assertEquals(65535, 65535.2.toInt())
+// assertEquals(23, 23.6f.toInt())
+// assertEquals(-12, -12.4.toShort())
+// assertEquals(-12, -12.4.toByte())
+
+ assertEquals('\u0419', (-654311).toChar())
+// assertEquals('\u0419', (-654311.0).toChar())
+// assertEquals('\u0419', (-654311.0f).toChar())
+
+ // TODO: Long.toString
+ val longX: Long = 9223372034707292481L
+ // assertEquals("9223372034707292481", longX.toString())
+
+ assertEquals(-2147483327, longX.toInt())
+ assertEquals(321, longX.toShort())
+ assertEquals(65, longX.toByte())
+ assertEquals('\u0141', longX.toChar())
+
+ val intX: Int = longX.toInt()
+ assertEquals(321, intX.toShort())
+ assertEquals(65, intX.toByte())
+
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/number/conversionsWithoutTruncation.kt b/js/js.translator/testData/wasmBox/number/conversionsWithoutTruncation.kt
new file mode 100644
index 00000000000..ab8c2836e65
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/conversionsWithoutTruncation.kt
@@ -0,0 +1,81 @@
+// EXPECTED_REACHABLE_NODES: 1293
+package foo
+
+//fun testForNumber(numberX: Number) {
+// assertEquals(true, 65.0 == numberX.toDouble())
+// assertEquals(true, 65.0f == numberX.toFloat())
+// assertEquals(true, 65L == numberX.toLong())
+// assertEquals(true, 65 == numberX.toInt())
+// assertEquals(true, 65.toShort() == numberX.toShort())
+// assertEquals(true, 65.toByte() == numberX.toByte())
+// assertEquals(true, 'A' == numberX.toChar())
+//}
+
+fun box(): String {
+
+// TODO: Number is not supported yet
+// testForNumber(65.0)
+// testForNumber(65.0f)
+// testForNumber(65L)
+// testForNumber(65)
+// testForNumber(65.toShort())
+// testForNumber(65.toByte())
+
+ var doubleX: Double = 65.0
+ assertEquals(true, 65.0 == doubleX.toDouble())
+ assertEquals(true, 65.0f == doubleX.toFloat())
+ // TODO: Float to integer convertions are not supported yet
+ // assertEquals(true, 65L == doubleX.toLong())
+ // assertEquals(true, 65 == doubleX.toInt())
+ // assertEquals(true, 65.toShort() == doubleX.toShort())
+ // assertEquals(true, 65.toByte() == doubleX.toByte())
+ // assertEquals(true, 'A' == doubleX.toChar())
+
+ var floatX: Float = 65.0f
+ assertEquals(true, 65.0 == floatX.toDouble())
+ assertEquals(true, 65.0f == floatX.toFloat())
+ // TODO: Float to integer convertions are not supported yet
+// assertEquals(true, 65L == floatX.toLong())
+// assertEquals(true, 65 == floatX.toInt())
+// assertEquals(true, 65.toShort() == floatX.toShort())
+// assertEquals(true, 65.toByte() == floatX.toByte())
+// assertEquals(true, 'A' == floatX.toChar())
+
+ val longX: Long = 65L
+ assertEquals(true, 65.0 == longX.toDouble())
+ assertEquals(true, 65.0f == longX.toFloat())
+ assertEquals(true, 65L == longX.toLong())
+ assertEquals(true, 65 == longX.toInt())
+ assertEquals(true, 65.toShort() == longX.toShort())
+ assertEquals(true, 65.toByte() == longX.toByte())
+ assertEquals(true, 'A' == longX.toChar())
+
+ val intX: Int = 65
+ assertEquals(true, 65.0 == intX.toDouble())
+ assertEquals(true, 65.0f == intX.toFloat())
+ assertEquals(true, 65L == intX.toLong())
+ assertEquals(true, 65 == intX.toInt())
+ assertEquals(true, 65.toShort() == intX.toShort())
+ assertEquals(true, 65.toByte() == intX.toByte())
+ assertEquals(true, 'A' == intX.toChar())
+
+ val shortX: Short = 65.toShort()
+ assertEquals(true, 65.0 == shortX.toDouble())
+ assertEquals(true, 65.0f == shortX.toFloat())
+ assertEquals(true, 65L == shortX.toLong())
+ assertEquals(true, 65 == shortX.toInt())
+ assertEquals(true, 65.toShort() == shortX.toShort())
+ assertEquals(true, 65.toByte() == shortX.toByte())
+ assertEquals(true, 'A' == shortX.toChar())
+
+ val byteX: Byte = 65.toByte()
+ assertEquals(true, 65.0 == byteX.toDouble())
+ assertEquals(true, 65.0f == byteX.toFloat())
+ assertEquals(true, 65L == byteX.toLong())
+ assertEquals(true, 65 == byteX.toInt())
+ assertEquals(true, 65.toShort() == byteX.toShort())
+ assertEquals(true, 65.toByte() == byteX.toByte())
+ assertEquals(true, 'A' == byteX.toChar())
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/division.kt b/js/js.translator/testData/wasmBox/number/division.kt
new file mode 100644
index 00000000000..0073e310517
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/division.kt
@@ -0,0 +1,45 @@
+// EXPECTED_REACHABLE_NODES: 1280
+package foo
+
+fun box(): String {
+ if (3 / 4 != 0) {
+ return "fail11"
+ }
+ if (-5 / 4 != -1) {
+ return "fail2"
+ }
+ if ((3.0 / 4.0 - 0.75) > 0.01) {
+ return "fail3"
+ }
+ if ((-10.0 / 4.0 + 2.5) > 0.01) {
+ return "fail44"
+ }
+ val i1: Int = 5
+ val i2: Int = 2
+ if (i1 / i2 != 2) {
+ return "fail55"
+ }
+ val i3: Short = 5
+ val i4: Short = 2
+ if (i3 / i4 != 2) {
+ return "fail6"
+ }
+ val i5: Byte = 5
+ val i6: Byte = 2
+ if (i5 / i6 != 2) {
+ return "fail7"
+ }
+
+ val f1: Double = 5.0
+ val f2: Double = 2.0
+ if ((f1 / f2 - 2.5) > 0.01) {
+ return "fail8"
+ }
+
+ val f3: Float = 5.0.toFloat()
+ val f4: Float = 2.0.toFloat()
+ if ((f3 / f4 - 2.5.toFloat()) > 0.01) {
+ return "fail9"
+ }
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/number/doubleConversions.kt b/js/js.translator/testData/wasmBox/number/doubleConversions.kt
new file mode 100644
index 00000000000..8adf7baa07b
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/doubleConversions.kt
@@ -0,0 +1,77 @@
+// EXPECTED_REACHABLE_NODES: 1222
+
+// IGNORE_BACKEND: WASM
+// TODO: Support floating-point to integer conversions
+package foo
+
+fun box(): String {
+ val c: Double = 3.6
+ if (c.toDouble() != 3.6) {
+ return "fail1"
+ }
+ if (c.toFloat() != 3.6.toFloat()) {
+ return "fail2"
+ }
+ if (c.toByte() != 3.toByte()) {
+ return "fail3"
+ }
+ if (c.toInt() != 3) {
+ return "fail4"
+ }
+ if (c.toShort() != 3.toShort()) {
+ return "fail5"
+ }
+
+ val cn: Double = -3.6
+ if (cn.toDouble() != -3.6) {
+ return "fail6"
+ }
+ if (cn.toFloat() != -3.6.toFloat()) {
+ return "fail7"
+ }
+ if (cn.toByte() != (-3).toByte()) {
+ return "fail8"
+ }
+ if (cn.toInt() != -3) {
+ return "fail9"
+ }
+ if (cn.toShort() != (-3).toShort()) {
+ return "fail10"
+ }
+
+ val f: Float = 3.6.toFloat()
+ if (f.toDouble() != 3.6) {
+ return "fail11"
+ }
+ if (f.toFloat() != 3.6.toFloat()) {
+ return "fail12"
+ }
+ if (f.toByte() != 3.toByte()) {
+ return "fail13"
+ }
+ if (f.toInt() != 3) {
+ return "fail14"
+ }
+ if (f.toShort() != 3.toShort()) {
+ return "fail15"
+ }
+
+ val fn: Float = -3.6.toFloat()
+ if (fn.toDouble() != -3.6) {
+ return "fail16"
+ }
+ if (fn.toFloat() != -3.6.toFloat()) {
+ return "fail17"
+ }
+ if (fn.toByte() != (-3).toByte()) {
+ return "fail18"
+ }
+ if (fn.toInt() != -3) {
+ return "fail19"
+ }
+ if (fn.toShort() != (-3).toShort()) {
+ return "fail20"
+ }
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/hashCode.kt b/js/js.translator/testData/wasmBox/number/hashCode.kt
new file mode 100644
index 00000000000..dc1024ff7d6
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/hashCode.kt
@@ -0,0 +1,23 @@
+// TARGET_BACKEND: WASM
+// EXPECTED_REACHABLE_NODES: 1280
+
+// NOTE: Hash codes are the same as in Native and JVM
+
+fun box(): String {
+ var value = (3).hashCode()
+ if (value != 3) return "fail1"
+
+ value = (3.14).hashCode()
+ if (value != 300063655) return "fail2"
+
+ value = (3.14159).hashCode()
+ if (value != -1340954729) return "fail3"
+
+ value = (1e80).hashCode()
+ if (value != 24774576) return "fail4"
+
+ value = (1e81).hashCode()
+ if (value != -1007271154) return "fail5"
+
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/number/hexadecimalConstant.kt b/js/js.translator/testData/wasmBox/number/hexadecimalConstant.kt
new file mode 100644
index 00000000000..ab5058adc4c
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/hexadecimalConstant.kt
@@ -0,0 +1,7 @@
+// EXPECTED_REACHABLE_NODES: 1219
+package foo
+
+fun box(): String {
+ val i = 0x80000000 + 0x8000000
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/number/incDecOptimization.kt b/js/js.translator/testData/wasmBox/number/incDecOptimization.kt
new file mode 100644
index 00000000000..408fba61b4d
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/incDecOptimization.kt
@@ -0,0 +1,21 @@
+// EXPECTED_REACHABLE_NODES: 1283
+// CHECK_VARS_COUNT: function=test count=1
+
+// TODO: Support classes
+
+fun test(): String {
+
+ var i = 23
+
+ var x = ++i
+ if (x != 24) return "fail1:"
+
+ i++
+ if (i != 25) return "fail2:"
+
+ // a.i++, used as expression, requires temporary variable
+
+ return "OK"
+}
+
+fun box(): String = test()
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/intConversions.kt b/js/js.translator/testData/wasmBox/number/intConversions.kt
new file mode 100644
index 00000000000..462d400a40b
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/intConversions.kt
@@ -0,0 +1,29 @@
+// EXPECTED_REACHABLE_NODES: 1282
+package foo
+
+fun box(): String {
+ val c: Int = 3
+ if (c.toDouble() != 3.0) {
+ return "fail1"
+ }
+ if (c.toFloat() != 3.toFloat()) {
+ return "fail2"
+ }
+ if (c.toByte() != 3.toByte()) {
+ return "fail3"
+ }
+ if (c.toInt() != 3) {
+ return "fail4"
+ }
+ if (c.toShort() != 3.toShort()) {
+ return "fail5"
+ }
+ val c2: Int = -5
+ if (c2.toShort() != (-5).toShort()) {
+ return "fail6"
+ }
+ if (c2.toFloat() != -5.toFloat()) {
+ return "fail7"
+ }
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/intDivFloat.kt b/js/js.translator/testData/wasmBox/number/intDivFloat.kt
new file mode 100644
index 00000000000..43ed02dc6a6
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/intDivFloat.kt
@@ -0,0 +1,20 @@
+// EXPECTED_REACHABLE_NODES: 1284
+// http://youtrack.jetbrains.com/issue/KT-5345
+// KT-5345 (Javascript) Type mismatch on Int / Float division
+// If any of Number operands is floating-point, the result should be float too.
+
+package foo
+
+fun box(): String {
+ assertEquals(0.5f, 1 / 2.0f, "Int / Float")
+
+ assertEquals(0.5, 1 / 2.0, "Int / Double")
+
+ assertEquals(0.5f, 1.toShort() / 2.0f, "Short / Float")
+ assertEquals(0.5, 1.toShort() / 2.0, "Short / Double")
+
+ assertEquals(0.5f, 1.toByte() / 2.0f, "Byte / Float")
+ assertEquals(0.5, 1.toByte() / 2.0, "Byte / Double")
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/intIncDecOverflow.kt b/js/js.translator/testData/wasmBox/number/intIncDecOverflow.kt
new file mode 100644
index 00000000000..2d5d9c45cf8
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/intIncDecOverflow.kt
@@ -0,0 +1,25 @@
+// EXPECTED_REACHABLE_NODES: 1282
+package foo
+
+
+fun box(): String {
+ var b: Byte = 0x7F
+ b++
+ if (b.toInt() != -0x80) return "fail1a"
+ b--
+ if (b.toInt() != 0x7F) return "fail1b"
+
+ var s: Short = 0x7FFF
+ s++
+ if (s.toInt() != -0x8000) return "fail2a"
+ s--
+ if (s.toInt() != 0x7FFF) return "fail2b"
+
+ var i: Int = 0x7FFFFFFF
+ i++
+ if (i != -0x80000000) return "fail3a"
+ i--
+ if (i != 0x7FFFFFFF) return "fail3b"
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/intOverflow.kt b/js/js.translator/testData/wasmBox/number/intOverflow.kt
new file mode 100644
index 00000000000..b2a46b414ae
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/intOverflow.kt
@@ -0,0 +1,35 @@
+// EXPECTED_REACHABLE_NODES: 1284
+package foo
+
+fun bigValue() = 0x7FFFFFFC
+
+fun mediumValue() = 0x12345
+
+fun four() = 4
+
+fun box(): String {
+ var v = bigValue() + 1
+ if (v != 0x7FFFFFFD) return "fail1"
+
+ v = bigValue() + 8
+ if (v != -0x7FFFFFFC) return "fail2"
+
+ v = bigValue() + four() + 4
+ if (v != -0x7FFFFFFC) return "fail3"
+
+ v = (bigValue() + four() - 4) shr 1
+ if (v != 0x3FFFFFFE) return "fail3"
+
+ v = mediumValue() * 0x23456
+ if (v != -2112496338) return "fail5"
+
+ v = bigValue() * bigValue()
+ if (v != 16) return "fail6"
+
+ v = -minInt()
+ if (v != -2147483648) return "fail7"
+
+ return "OK"
+}
+
+fun minInt() = -2147483648
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/kt2342.kt b/js/js.translator/testData/wasmBox/number/kt2342.kt
new file mode 100644
index 00000000000..a2d28963be9
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/kt2342.kt
@@ -0,0 +1,20 @@
+// EXPECTED_REACHABLE_NODES: 1281
+package foo
+
+fun test(a: Int, b: Int, expected: Int): Int {
+ val result = a / b
+ if (expected == result) return 100
+ return 25
+}
+
+fun box(): String {
+ var r = test(10, 3, 3)
+ if (r != 100) return "Fail1"
+
+ r = test(49, 6, 8)
+ if (r != 100) return "Fail 2"
+
+ if (2133 / 3 / 7 / (91 / 5) != 5) return "2133 / 3 / 7 / (91 / 5) != 5"
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/longBinaryOperations.kt b/js/js.translator/testData/wasmBox/number/longBinaryOperations.kt
new file mode 100644
index 00000000000..f29865078f7
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/longBinaryOperations.kt
@@ -0,0 +1,57 @@
+// EXPECTED_REACHABLE_NODES: 1230
+package foo
+
+fun fact(n: Int): Long = if (n == 1) 1L else n * fact(n - 1)
+
+// TODO: Support loops
+//fun fib(n: Int): Long {
+// var a = 0L
+// var b = 1L
+// for (i in 2..n) {
+// var tmp = a
+// a = b
+// b = b + tmp
+// }
+// return b
+//}
+
+fun box(): String {
+
+ assertEquals(30.0, 10L + 20.0)
+ assertEquals(30.0f, 10L + 20.0f)
+ assertEquals(30L, 10L + 20L)
+ assertEquals(30L, 10L + 20)
+ assertEquals(30L, 10L + 20.toShort())
+ assertEquals(30L, 10L + 20.toByte())
+
+ assertEquals(30.0, 20.0 + 10L)
+ assertEquals(30.0f, 20.0f + 10L)
+ assertEquals(20L, 10 + 10L)
+ assertEquals(20L, 10.toShort() + 10L)
+ assertEquals(20L, 10.toByte() + 10L)
+
+ assertEquals(20L, 30 - 10L)
+
+ assertEquals(100L, 10 * 10L)
+ assertEquals(100.0, 10.0 * 10L)
+
+ assertEquals(100L, 10L * 10)
+ assertEquals(100.0, 10L * 10.0)
+
+ assertEquals(100L, 1000L / 10)
+ assertEquals(100L, 1000 / 10L)
+
+ assertEquals(100.0, 1000L / 10.0)
+ assertEquals(100.0, 1000.0 / 10L)
+
+ assertEquals(2L, 100L % 7)
+ assertEquals(2L, 100 % 7L)
+
+ assertEquals(2432902008176640000L, fact(20))
+
+// TODO: Support loops
+// assertEquals(12586269025L, fib(50))
+// assertEquals(7540113804746346429L, fib(92))
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/longBitOperations.kt b/js/js.translator/testData/wasmBox/number/longBitOperations.kt
new file mode 100644
index 00000000000..b32b77bbea5
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/longBitOperations.kt
@@ -0,0 +1,24 @@
+// EXPECTED_REACHABLE_NODES: 1228
+package foo
+
+fun box(): String {
+
+ assertEquals(65536L, 1L shl 16)
+ assertEquals(1L, 65536L shr 16)
+
+ assertEquals(-1L, -1L shr 48)
+ assertEquals(65535L, -1L ushr 48)
+
+ assertEquals(-1L, 0L.inv())
+
+ assertEquals(0b1000L, 0b1100L and 0b1010L)
+ assertEquals(0b1110L, 0b1100L or 0b1010L)
+ assertEquals(0b0110L, 0b1100L xor 0b1010L)
+
+ assertEquals(0xab88ac0021L, 0xabcdef0123L and 0xefaabcdef1L)
+ assertEquals(0xefefffdff3L, 0xabcdef0123L or 0xefaabcdef1L)
+ assertEquals(0x446753dfd2L, 0xabcdef0123L xor 0xefaabcdef1L)
+ assertEquals(-737894400292, 0xabcdef0123L.inv())
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/longCompareToIntrinsic.kt b/js/js.translator/testData/wasmBox/number/longCompareToIntrinsic.kt
new file mode 100644
index 00000000000..3e228384021
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/longCompareToIntrinsic.kt
@@ -0,0 +1,41 @@
+// EXPECTED_REACHABLE_NODES: 1226
+package foo
+
+fun box(): String {
+
+ assertEquals(true, 10.0 < 20L, "Double.compareTo(Long)")
+ assertEquals(true, 10.0 < 7540113804746346429L, "Double.compareTo(Long)")
+
+ assertEquals(true, 10.0f < 20L, "Float.compareTo(Long)")
+ assertEquals(true, 10.0f < 7540113804746346429L, "Float.compareTo(Long)")
+
+ assertEquals(true, 10L < 20L, "Long.compareTo(Long)")
+ assertEquals(true, 10 < 20L, "Int.compareTo(Long)")
+ assertEquals(true, 10 < 7540113804746346429L, "Int.compareTo(Long)")
+
+ assertEquals(true, 10.toShort() < 20L, "Short.compareTo(Long)")
+ assertEquals(true, 10.toShort() < 7540113804746346429L, "Short.compareTo(Long)")
+ assertEquals(true, 10.toByte() < 20L, "Byte.compareTo(Long)")
+ assertEquals(true, 10.toByte() < 7540113804746346429L, "Byte.compareTo(Long)")
+
+ assertEquals(true, 10L < 20.0, "Long.compareTo(Double)")
+ assertEquals(false, 7540113804746346429L < 20.0, "Long.compareTo(Double)")
+
+ assertEquals(true, 10L < 20.0f, "Long.compareTo(Float)")
+ assertEquals(true, 7540113804746346429L > 20.0f, "Long.compareTo(Float)")
+ assertEquals(false, 7540113804746346429L < 20.0f, "Long.compareTo(Float)")
+
+ assertEquals(true, 10L < 20, "Long.compareTo(Int)")
+ assertEquals(true, 7540113804746346429L > 20, "Long.compareTo(Int)")
+ assertEquals(false, 7540113804746346429L < 20, "Long.compareTo(Int)")
+
+ assertEquals(true, 10L < 20.toShort(), "Long.compareTo(Short)")
+ assertEquals(true, 7540113804746346429L > 20.toShort(), "Long.compareTo(Short)")
+ assertEquals(false, 7540113804746346429L < 20.toShort(), "Long.compareTo(Short)")
+
+ assertEquals(true, 10L < 20.toByte(), "Long.compareTo(Byte)")
+ assertEquals(true, 7540113804746346429L > 20.toByte(), "Long.compareTo(Byte)")
+ assertEquals(false, 7540113804746346429L < 20.toByte(), "Long.compareTo(Byte)")
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/longEqualsIntrinsic.kt b/js/js.translator/testData/wasmBox/number/longEqualsIntrinsic.kt
new file mode 100644
index 00000000000..7f826aa2688
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/longEqualsIntrinsic.kt
@@ -0,0 +1,45 @@
+// EXPECTED_REACHABLE_NODES: 1284
+package foo
+
+// WASM: TODO: Nullable types, Number, Any
+
+fun box(): String {
+ assertEquals(true, 10L == 10L, "Long == Long")
+ assertEquals(true, 10L != 11L, "Long != Long")
+
+// val x1: Long? = 10L
+// val x2: Long? = 10L
+// assertEquals(false, x1 == null, "Long? == null")
+// assertEquals(false, null == x1, "null == Long?")
+// assertEquals(true, x1 == 10L, "Long? == Long")
+// assertEquals(true, 10L == x1, "Long == Long?")
+// assertEquals(true, x1 == x2, "Long? == Long?")
+
+// val x3: Long? = null
+// val x4: Long? = null
+// assertEquals(true, x3 == null, "Long?(null) == null")
+// assertEquals(true, null == x3, "null == Long?(null)")
+// assertEquals(false, x3 == 10L, "Long?(null) == Long")
+// assertEquals(false, 10L == x3, "Long == Long?(null)")
+// assertEquals(false, x3 == x1, "Long?(null) == Long?")
+// assertEquals(true, x3 == x4, "Long?(null) == Long?(null)")
+
+// val number1: Number = 10L
+// val number2: Number = 10L
+// assertEquals(true, number1 == number2, "Number == Number")
+// assertEquals(true, number1 == 10L, "Number == Long")
+// assertEquals(true, number1 != 11L, "Number != Long")
+// assertEquals(true, 10L == number1, "Long == Number")
+// assertEquals(true, 11L != number1, "Long != Number")
+//
+// val y1: Any = 10L
+// var y2: Any = 10
+// var y3: Any? = null
+// assertEquals(true, y1 == 10L, "Any == Long")
+// assertEquals(true, 10L == y1, "Long == Any 1")
+// assertEquals(false, 10L == y2, "Long == Any 2")
+// assertEquals(false, 10L == y3, "Long == Any?(null)")
+// assertEquals(true, x3 == y3, "Long?(null) == Any?(null)")
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/longHashCode.kt b/js/js.translator/testData/wasmBox/number/longHashCode.kt
new file mode 100644
index 00000000000..149fa885d70
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/longHashCode.kt
@@ -0,0 +1,18 @@
+// EXPECTED_REACHABLE_NODES: 1284
+package foo
+
+fun box(): String {
+ var l1: Long = 0x12344478935690
+ var l2: Long = 0x12344478935698
+ var diff: Long = l2 - l1
+ l1 += (diff / 2)
+ l2 -= (diff / 2)
+
+ assertEquals(l1, l2, "When L1 == L2")
+ assertEquals(l1.hashCode(), l2.hashCode(), "L1.hashCode() == L2.hashCode()")
+
+// var l3: Any = l2
+// assertEquals(l1.hashCode(), l3.hashCode(), "Any(Long).hashCode()")
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/longUnaryOperations.kt b/js/js.translator/testData/wasmBox/number/longUnaryOperations.kt
new file mode 100644
index 00000000000..daaa14cbec0
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/longUnaryOperations.kt
@@ -0,0 +1,32 @@
+// EXPECTED_REACHABLE_NODES: 1225
+package foo
+
+fun box(): String {
+
+ var x: Long = 2L
+ x++
+ assertEquals(3L, x)
+ ++x
+ assertEquals(4L, x)
+
+ var y = x++
+ assertEquals(4L, y)
+ assertEquals(5L, x)
+
+ y = ++x
+ assertEquals(6L, y)
+ assertEquals(6L, x)
+
+ x--
+ assertEquals(5L, x)
+ --x
+ assertEquals(4L, x)
+
+ y = +x
+ assertEquals(4L, y)
+
+ y = -x
+ assertEquals(-4L, y)
+
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/number/mixedTypesOverflow.kt b/js/js.translator/testData/wasmBox/number/mixedTypesOverflow.kt
new file mode 100644
index 00000000000..157ca0c5896
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/mixedTypesOverflow.kt
@@ -0,0 +1,34 @@
+// EXPECTED_REACHABLE_NODES: 1284
+// IGNORE_BACKEND: JS
+package foo
+
+// TODO(WASM) Companions are not supported yet
+
+fun box(): String {
+ val byteOne = 1.toByte()
+ val shortOne = 1.toShort()
+ var v: Int
+
+ v = maxInt() + byteOne
+ if (v != minInt()) return "fail1"
+
+ v = minInt() - byteOne
+ if (v != maxInt()) return "fail2"
+
+ v = maxInt() + shortOne
+ if (v != minInt()) return "fail3"
+
+ v = minInt() - shortOne
+ if (v != maxInt()) return "fail4"
+
+ v = maxInt() * 127 // Byte.MAX_VALUE
+ if (v != 2147483521) return "fail5"
+
+ v = maxInt() * 32767 // Short.MAX_VALUE
+ if (v != 2147450881) return "fail6"
+
+ return "OK"
+}
+
+fun minInt() = -2147483648 // Int.MIN_VALUE
+fun maxInt() = 2147483647 // Int.MAX_VALUE
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/numberCompareTo.kt b/js/js.translator/testData/wasmBox/number/numberCompareTo.kt
new file mode 100644
index 00000000000..6dbf88e40ee
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/numberCompareTo.kt
@@ -0,0 +1,127 @@
+// EXPECTED_REACHABLE_NODES: 1289
+package foo
+
+// TODO: Wasm global initialization is not supported
+//var global: String = ""
+//
+//fun id(s: String, value: Int): Int {
+// global += s
+// return value
+//}
+
+fun box(): String {
+
+ assertEquals(-1, 1.compareTo(2))
+ // assertEquals(-1, (1 as Comparable).compareTo(2))
+
+ assertEquals(-1, 1.compareTo(2L))
+ assertEquals(-1, 1.compareTo(2L))
+ assertEquals(-1, 1.compareTo(7540113804746346429L))
+ assertEquals(-1, 1.compareTo(2.toShort()))
+ assertEquals(-1, 1.compareTo(2.toByte()))
+ assertEquals(-1, 1.compareTo(2.0))
+ assertEquals(-1, 1.compareTo(2.0f))
+
+ assertEquals(1, 10.compareTo(2L))
+ assertEquals(1, 10.compareTo(2))
+ assertEquals(1, 10.compareTo(2.toShort()))
+ assertEquals(1, 10.compareTo(2.toByte()))
+ assertEquals(1, 10.compareTo(2.0))
+ assertEquals(1, 10.compareTo(2.0f))
+
+ assertEquals(0, 2.compareTo(2L))
+ assertEquals(0, 2.compareTo(2))
+ assertEquals(0, 2.compareTo(2.toShort()))
+ assertEquals(0, 2.compareTo(2.toByte()))
+ assertEquals(0, 2.compareTo(2.0))
+ assertEquals(0, 2.compareTo(2.0f))
+
+ assertEquals(-1, 1.toShort().compareTo(2L))
+ assertEquals(-1, 1.toShort().compareTo(7540113804746346429L))
+ assertEquals(-1, 1.toShort().compareTo(2))
+ assertEquals(-1, 1.toShort().compareTo(2.toShort()))
+ // assertEquals(-1, (1.toShort() as Comparable).compareTo(2.toShort()))
+ assertEquals(-1, 1.toShort().compareTo(2.toByte()))
+ assertEquals(-1, 1.toShort().compareTo(2.0))
+ assertEquals(-1, 1.toShort().compareTo(2.0f))
+
+ assertEquals(1, 10.toByte().compareTo(2L))
+ assertEquals(-1, 10.toByte().compareTo(7540113804746346429L))
+ assertEquals(1, 10.toByte().compareTo(2))
+ assertEquals(1, 10.toByte().compareTo(2.toShort()))
+ assertEquals(1, 10.toByte().compareTo(2.toByte()))
+ // assertEquals(1, (10.toByte() as Comparable).compareTo(2.toByte()))
+ assertEquals(1, 10.toByte().compareTo(2.0))
+ assertEquals(1, 10.toByte().compareTo(2.0f))
+
+ assertEquals(0, 2.0.compareTo(2L))
+ assertEquals(-1, 2.0.compareTo(7540113804746346429L))
+ assertEquals(0, 2.0.compareTo(2))
+ assertEquals(0, 2.0.compareTo(2.toShort()))
+ assertEquals(0, 2.0.compareTo(2.toByte()))
+ assertEquals(0, 2.0.compareTo(2.0))
+ // assertEquals(0, (2.0 as Comparable).compareTo(2.0))
+ assertEquals(0, 2.0.compareTo(2.0f))
+
+ assertEquals(1, 3.0f.compareTo(2L))
+ assertEquals(-1, 3.0f.compareTo(7540113804746346429L))
+ assertEquals(1, 3.0f.compareTo(2))
+ assertEquals(1, 3.0f.compareTo(2.toShort()))
+ assertEquals(1, 3.0f.compareTo(2.toByte()))
+ assertEquals(1, 3.0f.compareTo(2.0))
+ assertEquals(1, 3.0f.compareTo(2.0f))
+ // assertEquals(1, (3.0f as Comparable).compareTo(2.0f))
+
+ assertEquals(1, 10L.compareTo(2L))
+ assertEquals(-1, 10L.compareTo(7540113804746346429L))
+ // assertEquals(1, (10L as Comparable).compareTo(2L))
+ assertEquals(1, 10L.compareTo(2))
+ assertEquals(1, 10L.compareTo(2.toShort()))
+ assertEquals(1, 10L.compareTo(2.toByte()))
+ assertEquals(1, 10L.compareTo(2.0))
+ assertEquals(1, 10L.compareTo(2.0f))
+
+ assertEquals(0, 'A'.compareTo('A'))
+
+ assertEquals(-1, 1L.compareTo(2L))
+ assertEquals(-1, 1L.compareTo(2))
+ assertEquals(-1, 1L.compareTo(2.toShort()))
+ assertEquals(-1, 1L.compareTo(2.toByte()))
+ assertEquals(-1, 1L.compareTo(2.0))
+ assertEquals(-1, 1L.compareTo(2.0f))
+
+ assertEquals(0, 7540113804746346429L.compareTo(7540113804746346429L))
+ assertEquals(1, 7540113804746346429L.compareTo(2L))
+ assertEquals(0, 2L.compareTo(2L))
+ assertEquals(0, 2L.compareTo(2))
+ assertEquals(0, 2L.compareTo(2.toShort()))
+ assertEquals(0, 2L.compareTo(2.toByte()))
+ assertEquals(0, 2L.compareTo(2.0))
+ assertEquals(0, 2L.compareTo(2.0f))
+
+ assertEquals(1, 10L.compareTo(2L))
+ assertEquals(1, 10L.compareTo(2))
+ assertEquals(1, 10L.compareTo(2.toShort()))
+ assertEquals(1, 10L.compareTo(2.toByte()))
+ assertEquals(1, 10L.compareTo(2.0))
+ assertEquals(1, 10L.compareTo(2.0f))
+
+ assertEquals(-1, 1L.compareTo(2L))
+ assertEquals(-1, 1L.compareTo(2))
+ assertEquals(-1, 1L.compareTo(2.toShort()))
+ assertEquals(-1, 1L.compareTo(2.toByte()))
+ assertEquals(-1, 1L.compareTo(2.0))
+ assertEquals(-1, 1L.compareTo(2.0f))
+
+ assertEquals(0, 2L.compareTo(2L))
+ assertEquals(0, 2L.compareTo(2))
+ assertEquals(0, 2L.compareTo(2.toShort()))
+ assertEquals(0, 2L.compareTo(2.toByte()))
+ assertEquals(0, 2L.compareTo(2.0))
+ assertEquals(0, 2L.compareTo(2.0f))
+
+// assertEquals(1, id("A", 10).compareTo(id("B", 5)))
+// assertEquals("AB", global)
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/numberConversions.kt b/js/js.translator/testData/wasmBox/number/numberConversions.kt
new file mode 100644
index 00000000000..1e893912cc4
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/numberConversions.kt
@@ -0,0 +1,91 @@
+// EXPECTED_REACHABLE_NODES: 1289
+package foo
+
+fun testIntegerConversions(c: Byte): Boolean {
+ if (c.toDouble() != 3.0) {
+ return false
+ }
+ if (c.toFloat() != 3.toFloat()) {
+ return false
+ }
+ if (c.toByte() != 3.toByte()) {
+ return false
+ }
+ if (c.toInt() != 3) {
+ return false
+ }
+ if (c.toShort() != 3.toShort()) {
+ return false
+ }
+ return true
+}
+
+fun testIntegerConversions(c: Short): Boolean {
+ if (c.toDouble() != 3.0) {
+ return false
+ }
+ if (c.toFloat() != 3.toFloat()) {
+ return false
+ }
+ if (c.toByte() != 3.toByte()) {
+ return false
+ }
+ if (c.toInt() != 3) {
+ return false
+ }
+ if (c.toShort() != 3.toShort()) {
+ return false
+ }
+ return true
+}
+
+fun testIntegerConversions(c: Int): Boolean {
+ if (c.toDouble() != 3.0) {
+ return false
+ }
+ if (c.toFloat() != 3.toFloat()) {
+ return false
+ }
+ if (c.toByte() != 3.toByte()) {
+ return false
+ }
+ if (c.toInt() != 3) {
+ return false
+ }
+ if (c.toShort() != 3.toShort()) {
+ return false
+ }
+ return true
+}
+
+
+fun testFloatingPointConversions(c: Float): Boolean {
+// This is FALSE on JVM
+// if (c.toDouble() != 3.6) {
+// return false
+// }
+ if (c.toFloat() != 3.6.toFloat()) {
+ return false
+ }
+ return true
+}
+
+fun testFloatingPointConversions(c: Double): Boolean {
+ if (c.toDouble() != 3.6) {
+ return false
+ }
+ if (c.toFloat() != 3.6.toFloat()) {
+ return false
+ }
+ return true
+}
+
+
+fun box(): String {
+ if (!testIntegerConversions(3)) return "fail: testIntegerConversions1"
+ if (!testFloatingPointConversions(3.6)) return "fail: testFloatingPointConversions1"
+ if (!testFloatingPointConversions(3.6.toFloat())) return "fail: testFloaintPointConversions2"
+ if (!testIntegerConversions(3.toByte())) return "fail: testIntegerConversions2"
+ if (!testIntegerConversions(3.toShort())) return "fail: testIntegerConversions3"
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/number/numberEquals.kt b/js/js.translator/testData/wasmBox/number/numberEquals.kt
new file mode 100644
index 00000000000..704a14034e3
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/numberEquals.kt
@@ -0,0 +1,55 @@
+// !LANGUAGE: +ProperIeee754Comparisons
+package foo
+
+
+//fun testNullable(): String {
+// val undefined: Double? = js("undefined")
+// val doubleNull: Double? = null
+//
+// val plusZero: Double? = +0.0
+// val minusZero: Double? = -0.0
+//
+// if ((+0.0).equals(minusZero)) return "Total order fail"
+// if (plusZero != minusZero) return "IEEE 754 equals fail"
+//
+// if (plusZero == doubleNull) return "+0.0 != null fail"
+// if (plusZero == undefined) return "+0.0 != undefined fail"
+//
+// if (undefined != doubleNull) return "undefined == null fail"
+// if (undefined != undefined) return "undefined = undefined fail"
+// if (doubleNull != doubleNull) return "doubleNull = doubleNull fail"
+//
+// // Double == Float
+// val plusZeroAny: Any? = +0.0
+// val minusZeroAny: Any? = -0.0f
+//
+// if (plusZeroAny is Double && minusZeroAny is Float) {
+// if (plusZeroAny != minusZeroAny) return "IEEE 754 quals fail 2"
+// }
+//
+// return "OK"
+//}
+
+fun box(): String {
+ val plusZero: Double = +0.0
+ val minusZero: Double = -0.0
+
+ if (plusZero.equals(minusZero)) return "Total order fail"
+ if (plusZero != minusZero) return "IEEE 754 equals fail"
+
+ val plusZeroFloat: Float = +0.0f
+ val minusZeroFloat: Float = -0.0f
+
+ if (plusZeroFloat.equals(minusZeroFloat)) return "Total order fail 2"
+ if (plusZeroFloat != minusZeroFloat) return "IEEE 754 equals fail 2"
+
+// if ((plusZero as Any) == (minusZero as Any)) return "Total order fail 4"
+// if ((plusZeroFloat as Any) == (minusZeroFloat as Any)) return "Total order fail 5"
+// if (plusZero == (minusZero as Any)) return "Total order fail 6"
+
+// val nullableRes = testNullable()
+// if (nullableRes != "OK")
+// return "Nullable" + nullableRes
+
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/number/numberIncDec.kt b/js/js.translator/testData/wasmBox/number/numberIncDec.kt
new file mode 100644
index 00000000000..e0e7043bafc
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/number/numberIncDec.kt
@@ -0,0 +1,17 @@
+// EXPECTED_REACHABLE_NODES: 1282
+package foo
+
+fun box(): String {
+
+ assertEquals(100.inc(), 101)
+ assertEquals(100.dec(), 99)
+
+ var x = 100
+ assertEquals(x.inc(), 101)
+ assertEquals(x, 100)
+
+ assertEquals(x.dec(), 99)
+ assertEquals(x, 100)
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization/explicitEqualsOnDouble.kt b/js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization/explicitEqualsOnDouble.kt
new file mode 100644
index 00000000000..8bd7cf0a228
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization/explicitEqualsOnDouble.kt
@@ -0,0 +1,7 @@
+
+fun equals1(a: Double, b: Double) = a.equals(b)
+
+fun box(): String {
+ if ((-0.0).equals(0.0)) return "fail 0"
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/classes/kt2482.kt b/js/js.translator/testData/wasmBox/passedCommonTests/classes/kt2482.kt
new file mode 100644
index 00000000000..6a614198741
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/classes/kt2482.kt
@@ -0,0 +1,9 @@
+public fun box() : String {
+ if ( 0 == 0 ) { // Does not crash if either this...
+ if ( 0 == 0 ) { // ...or this is changed to if ( true )
+ // Does not crash if the following is uncommented.
+ //println("foo")
+ }
+ }
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/constants/float.kt b/js/js.translator/testData/wasmBox/passedCommonTests/constants/float.kt
new file mode 100644
index 00000000000..5c60d382df1
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/constants/float.kt
@@ -0,0 +1,18 @@
+fun box(): String {
+ if (1F != 1.toFloat()) return "fail 1"
+ if (1.0F != 1.0.toFloat()) return "fail 2"
+ if (1e1F != 1e1.toFloat()) return "fail 3"
+ if (1.0e1F != 1.0e1.toFloat()) return "fail 4"
+ if (1e-1F != 1e-1.toFloat()) return "fail 5"
+ if (1.0e-1F != 1.0e-1.toFloat()) return "fail 6"
+
+ if (1f != 1.toFloat()) return "fail 7"
+ if (1.0f != 1.0.toFloat()) return "fail 8"
+ if (1e1f != 1e1.toFloat()) return "fail 9"
+ if (1.0e1f != 1.0e1.toFloat()) return "fail 10"
+ if (1e-1f != 1e-1.toFloat()) return "fail 11"
+ if (1.0e-1f != 1.0e-1.toFloat()) return "fail 12"
+
+ return "OK"
+}
+
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/constants/long.kt b/js/js.translator/testData/wasmBox/passedCommonTests/constants/long.kt
new file mode 100644
index 00000000000..7fa2eaf4f50
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/constants/long.kt
@@ -0,0 +1,10 @@
+fun box(): String {
+ if (1L != 1.toLong()) return "fail 1"
+ if (0x1L != 0x1.toLong()) return "fail 2"
+ if (0X1L != 0X1.toLong()) return "fail 3"
+ if (0b1L != 0b1.toLong()) return "fail 4"
+ if (0B1L != 0B1.toLong()) return "fail 5"
+
+ return "OK"
+}
+
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst1.kt b/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst1.kt
new file mode 100644
index 00000000000..dc74e46b215
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst1.kt
@@ -0,0 +1,19 @@
+fun foo(b: Boolean): String {
+ return if (b) {
+ "OK"
+ } else if (false) {
+ "fail: reached unreachable code at line 5"
+ } else if (true) {
+ "fail: reached unexpected code at line 7"
+ } else if (true) {
+ "fail: reached unreachable code at line 9"
+ } else if (b) {
+ "fail: reached unreachable code at line 11"
+ } else {
+ "fail: reached unreachable code at line 13"
+ }
+}
+
+fun box(): String {
+ return foo(true)
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst2.kt b/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst2.kt
new file mode 100644
index 00000000000..bdf1dbc57d2
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst2.kt
@@ -0,0 +1,19 @@
+fun foo(b: Boolean): String {
+ return if (b) {
+ "fail: reached unexpected code at line 3"
+ } else if (false) {
+ "fail: reached unreachable code at line 5"
+ } else if (true) {
+ "OK"
+ } else if (true) {
+ "fail: reached unreachable code at line 9"
+ } else if (b) {
+ "fail: reached unreachable code at line 11"
+ } else {
+ "fail: reached unreachable code at line 13"
+ }
+}
+
+fun box(): String {
+ return foo(false)
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/kt1899.kt b/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/kt1899.kt
new file mode 100644
index 00000000000..92a38e1bd89
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/kt1899.kt
@@ -0,0 +1,5 @@
+fun box(): String {
+ if (1 != 0) {
+ }
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties/topLevel.kt b/js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties/topLevel.kt
new file mode 100644
index 00000000000..df0abcea24e
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties/topLevel.kt
@@ -0,0 +1,6 @@
+val Int.foo: String
+ get() = "OK"
+
+fun box(): String {
+ return 1.foo
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/functions/kt2280.kt b/js/js.translator/testData/wasmBox/passedCommonTests/functions/kt2280.kt
new file mode 100644
index 00000000000..79debb72bdf
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/functions/kt2280.kt
@@ -0,0 +1,7 @@
+fun box(): String {
+ fun rmrf(i: Int) {
+ if (i > 0) rmrf(i - 1)
+ }
+ rmrf(5)
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/ieee754/lessDouble_properIeeeAndNewInference.kt b/js/js.translator/testData/wasmBox/passedCommonTests/ieee754/lessDouble_properIeeeAndNewInference.kt
new file mode 100644
index 00000000000..d5f0f13e4ba
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/ieee754/lessDouble_properIeeeAndNewInference.kt
@@ -0,0 +1,8 @@
+// !LANGUAGE: +ProperIeee754Comparisons +NewInference
+
+fun box(): String {
+ if (-0.0 < 0.0) return "Fail 1"
+ if (-0.0 < 0) return "Fail 2"
+
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion1.kt b/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion1.kt
new file mode 100644
index 00000000000..486df9872db
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion1.kt
@@ -0,0 +1,6 @@
+fun foo(x: String): String {
+ fun bar(y: String) = x + y
+ return bar("K")
+}
+
+fun box() = foo("O")
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion3.kt b/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion3.kt
new file mode 100644
index 00000000000..7f0e7d4647b
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion3.kt
@@ -0,0 +1,11 @@
+fun foo(x: String): String {
+ fun bar(y: String): String {
+ fun qux(z: String): String =
+ x + y + z
+ return qux("")
+ }
+ return bar("K")
+}
+
+fun box(): String =
+ foo("O")
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion4.kt b/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion4.kt
new file mode 100644
index 00000000000..aa59458d534
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion4.kt
@@ -0,0 +1,6 @@
+fun String.foo(): String {
+ fun bar(y: String) = this + y
+ return bar("K")
+}
+
+fun box() = "O".foo()
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/labels/propertyAccessor.kt b/js/js.translator/testData/wasmBox/passedCommonTests/labels/propertyAccessor.kt
new file mode 100644
index 00000000000..b9973e82ddc
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/labels/propertyAccessor.kt
@@ -0,0 +1,11 @@
+val Int.getter: Int
+ get() {
+ return this@getter
+ }
+
+fun box(): String {
+ val i = 1
+ if (i.getter != 1) return "getter failed"
+
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations/negateConstantCompare.kt b/js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations/negateConstantCompare.kt
new file mode 100644
index 00000000000..f68757d7588
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations/negateConstantCompare.kt
@@ -0,0 +1,7 @@
+fun box(): String {
+ if (!(1 < 2)) {
+ return "fail"
+ }
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/annotatedAssignment.kt b/js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/annotatedAssignment.kt
new file mode 100644
index 00000000000..2a2bc1b115b
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/annotatedAssignment.kt
@@ -0,0 +1,14 @@
+@Target(AnnotationTarget.EXPRESSION)
+@Retention(AnnotationRetention.SOURCE)
+annotation class Annotation
+
+fun box(): String {
+ var v = 0
+ @Annotation v += 1 + 2
+ if (v != 3) return "fail1"
+
+ @Annotation v = 4
+ if (v != 4) return "fail2"
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/infixFunctionOverBuiltinMember.kt b/js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/infixFunctionOverBuiltinMember.kt
new file mode 100644
index 00000000000..d4ec1d41d6a
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/infixFunctionOverBuiltinMember.kt
@@ -0,0 +1,18 @@
+infix fun Int.rem(other: Int) = 10
+infix operator fun Int.minus(other: Int): Int = 20
+
+fun box(): String {
+ val a = 5 rem 2
+ if (a != 10) return "fail 1"
+
+ val b = 5 minus 3
+ if (b != 20) return "fail 2"
+
+ val a1 = 5.rem(2)
+ if (a1 != 1) return "fail 3"
+
+ val b2 = 5.minus(3)
+ if (b2 != 2) return "fail 4"
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/ea35963.kt b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/ea35963.kt
new file mode 100644
index 00000000000..6d58f3f2de4
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/ea35963.kt
@@ -0,0 +1,6 @@
+fun box(): String {
+ if (1 != 0) {
+ 1
+ }
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/incrementByteCharShort.kt b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/incrementByteCharShort.kt
new file mode 100644
index 00000000000..59b3f12b2ef
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/incrementByteCharShort.kt
@@ -0,0 +1,22 @@
+fun byteArg(b: Byte) {}
+fun charArg(c: Char) {}
+fun shortArg(s: Short) {}
+
+fun box(): String {
+ var b = 42.toByte()
+ b++
+ ++b
+ byteArg(b)
+
+ var c = 'x'
+ c++
+ ++c
+ charArg(c)
+
+ var s = 239.toShort()
+ s++
+ ++s
+ shortArg(s)
+
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt1634.kt b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt1634.kt
new file mode 100644
index 00000000000..8cdc1a36907
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt1634.kt
@@ -0,0 +1,4 @@
+fun box(): String {
+ !true
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt3078.kt b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt3078.kt
new file mode 100644
index 00000000000..cd834c89b2f
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt3078.kt
@@ -0,0 +1,7 @@
+fun box(): String {
+ if (1 >= 1.9) return "Fail #1"
+ if (1.compareTo(1.1) >= 0) return "Fail #2"
+ if (1.9 <= 1) return "Fail #3"
+ if (1.1.compareTo(1) <= 0) return "Fail #4"
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt6590_identityEquals.kt b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt6590_identityEquals.kt
new file mode 100644
index 00000000000..f21a8f1f6a7
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt6590_identityEquals.kt
@@ -0,0 +1,15 @@
+fun box(): String {
+ val i: Int = 10000
+ if (!(i === i)) return "Fail int ==="
+ if (i !== i) return "Fail int !=="
+
+ val j: Long = 123L
+ if (!(j === j)) return "Fail long ==="
+ if (j !== j) return "Fail long !=="
+
+ val d: Double = 3.14
+ if (!(d === d)) return "Fail double ==="
+ if (d !== d) return "Fail double !=="
+
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt737.kt b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt737.kt
new file mode 100644
index 00000000000..bdf9a4f5af7
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt737.kt
@@ -0,0 +1,5 @@
+fun box(): String {
+ if (3.compareTo(2) != 1) return "Fail #1"
+ if (5.toByte().compareTo(10.toLong()) >= 0) return "Fail #2"
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt828.kt b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt828.kt
new file mode 100644
index 00000000000..06e63bec23c
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt828.kt
@@ -0,0 +1,15 @@
+package demo
+
+fun box() : String {
+ var res : Boolean = true
+ res = (res and false)
+ res = (res or false)
+ res = (res xor false)
+ res = (true and false)
+ res = (true or false)
+ res = (true xor false)
+ res = (!true)
+ res = (true && false)
+ res = (true || false)
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt877.kt b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt877.kt
new file mode 100644
index 00000000000..094c5f88fae
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt877.kt
@@ -0,0 +1,9 @@
+fun box() : String {
+ var a : Int = -1
+ if((+a) != -1) return "fail 1"
+ a = 1
+ if((+a) != 1) return "fail 2"
+ if((+-1) != -1) return "fail 3"
+ if((-+a) != -1) return "fail 4"
+ return "OK"
+}
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/publishedApi/topLevel.kt b/js/js.translator/testData/wasmBox/passedCommonTests/publishedApi/topLevel.kt
new file mode 100644
index 00000000000..e2a33400e7d
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/publishedApi/topLevel.kt
@@ -0,0 +1,10 @@
+// MODULE: lib
+// FILE: lib.kt
+@PublishedApi
+internal fun published() = "OK"
+
+inline fun test() = published()
+
+// MODULE: main(lib)
+// FILE: main.kt
+fun box() = test()
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/unaryOp/intrinsic.kt b/js/js.translator/testData/wasmBox/passedCommonTests/unaryOp/intrinsic.kt
new file mode 100644
index 00000000000..30bd7d9d8f0
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/unaryOp/intrinsic.kt
@@ -0,0 +1,17 @@
+fun box(): String {
+ val a1: Byte = -1
+ val a2: Short = -1
+ val a3: Int = -1
+ val a4: Long = -1
+ val a5: Double = -1.0
+ val a6: Float = -1f
+
+ if (a1 != (-1).toByte()) return "fail 1"
+ if (a2 != (-1).toShort()) return "fail 2"
+ if (a3 != -1) return "fail 3"
+ if (a4 != -1L) return "fail 4"
+ if (a5 != -1.0) return "fail 5"
+ if (a6 != -1f) return "fail 6"
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/passedCommonTests/when/noElseNoMatch.kt b/js/js.translator/testData/wasmBox/passedCommonTests/when/noElseNoMatch.kt
new file mode 100644
index 00000000000..2c4e803b07b
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/passedCommonTests/when/noElseNoMatch.kt
@@ -0,0 +1,8 @@
+fun box(): String {
+ val x = 3
+ when (x) {
+ 1 -> {}
+ 2 -> {}
+ }
+ return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/wasmBox/primitivesOperatos.kt b/js/js.translator/testData/wasmBox/primitivesOperatos.kt
new file mode 100644
index 00000000000..b1bfdbda1f6
--- /dev/null
+++ b/js/js.translator/testData/wasmBox/primitivesOperatos.kt
@@ -0,0 +1,4 @@
+
+fun box(): String {
+ return "O" + "K"
+}
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/annotations.kt b/libraries/stdlib/wasm/annotations.kt
deleted file mode 100644
index 9e49963dcbe..00000000000
--- a/libraries/stdlib/wasm/annotations.kt
+++ /dev/null
@@ -1,12 +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 kotlin
-
-import kotlin.annotation.AnnotationTarget.*
-
-// Exclude declaration or file from lowerings and code generation
-@Target(FILE, CLASS, FUNCTION, PROPERTY)
-internal annotation class ExcludedFromCodegen
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/builtins/native/kotlin/Boolean.kt b/libraries/stdlib/wasm/builtins/native/kotlin/Boolean.kt
index f036a16b3c4..adb106c4cc6 100644
--- a/libraries/stdlib/wasm/builtins/native/kotlin/Boolean.kt
+++ b/libraries/stdlib/wasm/builtins/native/kotlin/Boolean.kt
@@ -13,6 +13,9 @@
package kotlin
+import kotlin.wasm.internal.WasmInstruction
+import kotlin.wasm.internal.wasm_i32_compareTo
+
/**
* 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`.
@@ -21,26 +24,34 @@ public class Boolean private constructor() : Comparable {
/**
* Returns the inverse of this boolean.
*/
+ @WasmInstruction(WasmInstruction.I32_EQZ)
public operator fun not(): Boolean
/**
* 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
/**
* 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
/**
* Performs a logical `xor` operation between this Boolean and the [other] one.
*/
+ @WasmInstruction(WasmInstruction.I32_XOR)
public infix fun xor(other: Boolean): Boolean
- public override fun compareTo(other: Boolean): Int
+ public override fun compareTo(other: Boolean): Int =
+ wasm_i32_compareTo(this.asInt(), other.asInt())
+
+ @WasmInstruction(WasmInstruction.NOP)
+ internal fun asInt(): Int
@SinceKotlin("1.3")
companion object {}
diff --git a/libraries/stdlib/wasm/builtins/native/kotlin/Char.kt b/libraries/stdlib/wasm/builtins/native/kotlin/Char.kt
index 740b512cfe6..7f5dec7b135 100644
--- a/libraries/stdlib/wasm/builtins/native/kotlin/Char.kt
+++ b/libraries/stdlib/wasm/builtins/native/kotlin/Char.kt
@@ -3,16 +3,15 @@
* 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"
-)
+@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
+
/**
* Represents a 16-bit Unicode character.
*
@@ -25,39 +24,56 @@ public class Char private constructor() : Comparable {
* 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 fun compareTo(other: Char): Int
+ public override inline fun compareTo(other: Char): Int =
+ wasm_i32_compareTo(this.toInt(), other.toInt())
/** Adds the other Int value to this value resulting a Char. */
- public operator fun plus(other: Int): Char
+ public inline operator fun plus(other: Int): Char =
+ (this.toInt() + other).toChar()
/** Subtracts the other Char value from this value resulting an Int. */
- public operator fun minus(other: Char): Int
+ public inline operator fun minus(other: Char): Int =
+ (this.toInt() - other.toInt())
+
/** Subtracts the other Int value from this value resulting a Char. */
- public operator fun minus(other: Int): Char
+ public inline operator fun minus(other: Int): Char =
+ (this.toInt() - other).toChar()
/** Increments this value. */
- public operator fun inc(): Char
+ public inline operator fun inc(): Char =
+ (this.toInt() + 1).toChar()
+
/** Decrements this value. */
- public operator fun dec(): 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
/** Returns the value of this character as a `Byte`. */
- public fun toByte(): Byte
+ public inline fun toByte(): Byte =
+ this.toInt().toByte()
/** Returns the value of this character as a `Char`. */
- public fun toChar(): Char
+ public inline fun toChar(): Char =
+ this
/** Returns the value of this character as a `Short`. */
- public fun toShort(): Short
+ public inline fun toShort(): Short =
+ this.toInt().toShort()
/** Returns the value of this character as a `Int`. */
- public fun toInt(): Int
+ @WasmInstruction(WasmInstruction.NOP)
+ public fun toInt(): Int =
+ implementedAsIntrinsic
/** Returns the value of this character as a `Long`. */
- public fun toLong(): Long
+ public inline fun toLong(): Long =
+ this.toInt().toLong()
/** Returns the value of this character as a `Float`. */
- public fun toFloat(): Float
+ public inline fun toFloat(): Float =
+ this.toInt().toFloat()
/** Returns the value of this character as a `Double`. */
- public fun toDouble(): Double
+ public inline fun toDouble(): Double =
+ this.toInt().toDouble()
+ @ExcludedFromCodegen
companion object {
/**
* The minimum value of a character code unit.
diff --git a/libraries/stdlib/wasm/builtins/native/kotlin/Library.kt b/libraries/stdlib/wasm/builtins/native/kotlin/Library.kt
index f19a04a58b6..19dce79c26a 100644
--- a/libraries/stdlib/wasm/builtins/native/kotlin/Library.kt
+++ b/libraries/stdlib/wasm/builtins/native/kotlin/Library.kt
@@ -6,7 +6,7 @@
"NON_MEMBER_FUNCTION_NO_BODY",
"REIFIED_TYPE_PARAMETER_NO_INLINE"
)
-@file:ExcludedFromCodegen
+@file:kotlin.wasm.internal.ExcludedFromCodegen
package kotlin
diff --git a/libraries/stdlib/wasm/builtins/native/kotlin/Primitives.kt b/libraries/stdlib/wasm/builtins/native/kotlin/Primitives.kt
index 9999d0dcaea..2d7b6883a15 100644
--- a/libraries/stdlib/wasm/builtins/native/kotlin/Primitives.kt
+++ b/libraries/stdlib/wasm/builtins/native/kotlin/Primitives.kt
@@ -2,24 +2,17 @@
* 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"
-)
+@file:Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
package kotlin
+import kotlin.wasm.internal.*
+
/**
* Represents a 8-bit signed integer.
- * On the JVM, non-nullable values of this type are represented as values of the primitive type `byte`.
*/
public class Byte private constructor() : Number(), Comparable {
+ @ExcludedFromCodegen
companion object {
/**
* A constant holding the minimum value an instance of Byte can have.
@@ -49,153 +42,189 @@ public class Byte private constructor() : Number(), Comparable {
* 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 operator fun compareTo(other: Byte): Int
+ public override inline operator fun compareTo(other: Byte): Int =
+ wasm_i32_compareTo(this.toInt(), other.toInt())
/**
* 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 operator fun compareTo(other: Short): Int
+ public inline operator fun compareTo(other: Short): Int =
+ this.toShort().compareTo(other)
/**
* 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 operator fun compareTo(other: Int): Int
+ public inline operator fun compareTo(other: Int): Int =
+ this.toInt().compareTo(other)
/**
* 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 operator fun compareTo(other: Long): Int
+ public inline operator fun compareTo(other: Long): Int =
+ this.toLong().compareTo(other)
/**
* 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 operator fun compareTo(other: Float): Int
+ public inline operator fun compareTo(other: Float): Int =
+ this.toFloat().compareTo(other)
/**
* 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 operator fun compareTo(other: Double): Int
+ public inline operator fun compareTo(other: Double): Int =
+ this.toDouble().compareTo(other)
/** Adds the other value to this value. */
- public operator fun plus(other: Byte): Int
+ public inline operator fun plus(other: Byte): Int =
+ this.toInt() + other.toInt()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Short): Int
+ public inline operator fun plus(other: Short): Int =
+ this.toInt() + other.toInt()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Int): Int
+ public inline operator fun plus(other: Int): Int =
+ this.toInt() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Long): Long
+ public inline operator fun plus(other: Long): Long =
+ this.toLong() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Float): Float
+ public inline operator fun plus(other: Float): Float =
+ this.toFloat() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Double): Double
+ public inline operator fun plus(other: Double): Double =
+ this.toDouble() + other
/** Subtracts the other value from this value. */
- public operator fun minus(other: Byte): Int
+ public inline operator fun minus(other: Byte): Int =
+ this.toInt() - other.toInt()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Short): Int
+ public inline operator fun minus(other: Short): Int =
+ this.toInt() - other.toInt()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Int): Int
+ public inline operator fun minus(other: Int): Int =
+ this.toInt() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Long): Long
+ public inline operator fun minus(other: Long): Long =
+ this.toLong() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Float): Float
+ public inline operator fun minus(other: Float): Float =
+ this.toFloat() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Double): Double
+ public inline operator fun minus(other: Double): Double =
+ this.toDouble() - other
/** Multiplies this value by the other value. */
- public operator fun times(other: Byte): Int
+ public inline operator fun times(other: Byte): Int =
+ this.toInt() * other.toInt()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Short): Int
+ public inline operator fun times(other: Short): Int =
+ this.toInt() * other.toInt()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Int): Int
+ public inline operator fun times(other: Int): Int =
+ this.toInt() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Long): Long
+ public inline operator fun times(other: Long): Long =
+ this.toLong() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Float): Float
+ public inline operator fun times(other: Float): Float =
+ this.toFloat() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Double): Double
+ public inline operator fun times(other: Double): Double =
+ this.toDouble() * other
/** Divides this value by the other value. */
- public operator fun div(other: Byte): Int
+ public inline operator fun div(other: Byte): Int =
+ this.toInt() / other.toInt()
+
/** Divides this value by the other value. */
- public operator fun div(other: Short): Int
+ public inline operator fun div(other: Short): Int =
+ this.toInt() / other.toInt()
+
/** Divides this value by the other value. */
- public operator fun div(other: Int): Int
+ public inline operator fun div(other: Int): Int =
+ this.toInt() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Long): Long
+ public inline operator fun div(other: Long): Long =
+ this.toLong() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Float): Float
+ public inline operator fun div(other: Float): Float =
+ this.toFloat() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Double): Double
+ public inline operator fun div(other: Double): Double =
+ this.toDouble() / other
/** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Byte): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Short): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Int): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Long): Long
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Double): Double
+ public inline operator fun rem(other: Byte): Int =
+ this.toInt() % other.toInt()
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Byte): Int
+ public inline operator fun rem(other: Short): Int =
+ this.toInt() % other.toInt()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Short): Int
+ public inline operator fun rem(other: Int): Int =
+ this.toInt() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Int): Int
+ public inline operator fun rem(other: Long): Long =
+ this.toLong() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Long): Long
+ public inline operator fun rem(other: Float): Float =
+ this.toFloat() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Double): Double
+ public inline operator fun rem(other: Double): Double =
+ this.toDouble() % other
/** Increments this value. */
- public operator fun inc(): Byte
+ public inline operator fun inc(): Byte =
+ (this + 1).toByte()
+
/** Decrements this value. */
- public operator fun dec(): Byte
+ public inline operator fun dec(): Byte =
+ (this - 1).toByte()
+
/** Returns this value. */
- public operator fun unaryPlus(): Int
+ public inline operator fun unaryPlus(): Int =
+ this.toInt()
+
/** Returns the negative of this value. */
- public operator fun unaryMinus(): Int
-
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Byte): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Short): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Int): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Long): LongRange
+ public inline operator fun unaryMinus(): Int =
+ -this.toInt()
/** Returns this value. */
- public override fun toByte(): Byte
+ public override inline fun toByte(): Byte =
+ this
+
/**
* Converts this [Byte] value to [Char].
*
@@ -204,7 +233,9 @@ public class Byte private constructor() : Number(), Comparable {
* 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.
*/
- public override fun toChar(): Char
+ @WasmInstruction(WasmInstruction.NOP)
+ public override fun toChar(): Char = implementedAsIntrinsic
+
/**
* Converts this [Byte] value to [Short].
*
@@ -213,7 +244,9 @@ public class Byte private constructor() : Number(), Comparable {
* 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.
*/
- public override fun toShort(): Short
+ @WasmInstruction(WasmInstruction.NOP)
+ public override fun toShort(): Short = implementedAsIntrinsic
+
/**
* Converts this [Byte] value to [Int].
*
@@ -222,7 +255,9 @@ public class Byte private constructor() : Number(), Comparable {
* 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.
*/
- public override fun toInt(): Int
+ @WasmInstruction(WasmInstruction.NOP)
+ public override fun toInt(): Int = implementedAsIntrinsic
+
/**
* Converts this [Byte] value to [Long].
*
@@ -231,26 +266,61 @@ public class Byte private constructor() : Number(), Comparable {
* 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.
*/
- public override fun toLong(): Long
+ @WasmInstruction(WasmInstruction.I64_EXTEND_I32_S)
+ public override fun toLong(): Long = implementedAsIntrinsic
+
/**
* Converts this [Byte] value to [Float].
*
* The resulting `Float` value represents the same numerical value as this `Byte`.
*/
- public override fun toFloat(): Float
+ @WasmInstruction(WasmInstruction.F32_CONVERT_I32_S)
+ public override fun toFloat(): Float = implementedAsIntrinsic
+
/**
* Converts this [Byte] value to [Double].
*
* The resulting `Double` value represents the same numerical value as this `Byte`.
*/
- public override fun toDouble(): Double
+ @WasmInstruction(WasmInstruction.F64_CONVERT_I32_S)
+ public override fun toDouble(): Double = implementedAsIntrinsic
+
+// /** 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())
+// }
+
+ // TODO: Support Any? and type operators
+// public override fun equals(other: Any?): Boolean =
+// other is Byte && wasm_i32_eq(this.toInt(), other.toInt()).reinterpretAsBoolean()
+
+ public inline fun equals(other: Byte): Boolean =
+ wasm_i32_eq(this.toInt(), other.toInt()).reinterpretAsBoolean()
+
+ // TODO: Implement Byte.toString()
+ // public override fun toString(): String
+
+ public override inline fun hashCode(): Int =
+ this.toInt()
}
/**
* Represents a 16-bit signed integer.
- * On the JVM, non-nullable values of this type are represented as values of the primitive type `short`.
*/
public class Short private constructor() : Number(), Comparable {
+ @ExcludedFromCodegen
companion object {
/**
* A constant holding the minimum value an instance of Short can have.
@@ -280,150 +350,201 @@ public class Short private constructor() : Number(), Comparable {
* 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 operator fun compareTo(other: Byte): Int
+ public inline operator fun compareTo(other: Byte): Int =
+ this.compareTo(other.toShort())
/**
* 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 operator fun compareTo(other: Short): Int
+ public override inline operator fun compareTo(other: Short): Int =
+ this.toInt().compareTo(other.toInt())
/**
* 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 operator fun compareTo(other: Int): Int
+ public inline operator fun compareTo(other: Int): Int =
+ this.toInt().compareTo(other)
/**
* 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 operator fun compareTo(other: Long): Int
+ public inline operator fun compareTo(other: Long): Int =
+ this.toLong().compareTo(other)
/**
* 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 operator fun compareTo(other: Float): Int
+ public inline operator fun compareTo(other: Float): Int =
+ this.toFloat().compareTo(other)
/**
* 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 operator fun compareTo(other: Double): Int
+ public inline operator fun compareTo(other: Double): Int =
+ this.toDouble().compareTo(other)
/** Adds the other value to this value. */
- public operator fun plus(other: Byte): Int
+ public inline operator fun plus(other: Byte): Int =
+ this.toInt() + other.toInt()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Short): Int
+ public inline operator fun plus(other: Short): Int =
+ this.toInt() + other.toInt()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Int): Int
+ public inline operator fun plus(other: Int): Int =
+ this.toInt() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Long): Long
+ public inline operator fun plus(other: Long): Long =
+ this.toLong() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Float): Float
+ public inline operator fun plus(other: Float): Float =
+ this.toFloat() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Double): Double
+ public inline operator fun plus(other: Double): Double =
+ this.toDouble() + other
/** Subtracts the other value from this value. */
- public operator fun minus(other: Byte): Int
+ public inline operator fun minus(other: Byte): Int =
+ this.toInt() - other.toInt()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Short): Int
+ public inline operator fun minus(other: Short): Int =
+ this.toInt() - other.toInt()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Int): Int
+ public inline operator fun minus(other: Int): Int =
+ this.toInt() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Long): Long
+ public inline operator fun minus(other: Long): Long =
+ this.toLong() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Float): Float
+ public inline operator fun minus(other: Float): Float =
+ this.toFloat() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Double): Double
+ public inline operator fun minus(other: Double): Double =
+ this.toDouble() - other
/** Multiplies this value by the other value. */
- public operator fun times(other: Byte): Int
+ public inline operator fun times(other: Byte): Int =
+ this.toInt() * other.toInt()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Short): Int
+ public inline operator fun times(other: Short): Int =
+ this.toInt() * other.toInt()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Int): Int
+ public inline operator fun times(other: Int): Int =
+ this.toInt() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Long): Long
+ public inline operator fun times(other: Long): Long =
+ this.toLong() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Float): Float
+ public inline operator fun times(other: Float): Float =
+ this.toFloat() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Double): Double
+ public inline operator fun times(other: Double): Double =
+ this.toDouble() * other
/** Divides this value by the other value. */
- public operator fun div(other: Byte): Int
+ public inline operator fun div(other: Byte): Int =
+ this.toInt() / other.toInt()
+
/** Divides this value by the other value. */
- public operator fun div(other: Short): Int
+ public inline operator fun div(other: Short): Int =
+ this.toInt() / other.toInt()
+
/** Divides this value by the other value. */
- public operator fun div(other: Int): Int
+ public inline operator fun div(other: Int): Int =
+ this.toInt() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Long): Long
+ public inline operator fun div(other: Long): Long =
+ this.toLong() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Float): Float
+ public inline operator fun div(other: Float): Float =
+ this.toFloat() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Double): Double
+ public inline operator fun div(other: Double): Double =
+ this.toDouble() / other
/** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Byte): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Short): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Int): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Long): Long
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Double): Double
+ public inline operator fun rem(other: Byte): Int =
+ this.toInt() % other.toInt()
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Byte): Int
+ public inline operator fun rem(other: Short): Int =
+ this.toInt() % other.toInt()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Short): Int
+ public inline operator fun rem(other: Int): Int =
+ this.toInt() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Int): Int
+ public inline operator fun rem(other: Long): Long =
+ this.toLong() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Long): Long
+ public inline operator fun rem(other: Float): Float =
+ this.toFloat() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Double): Double
+ public inline operator fun rem(other: Double): Double =
+ this.toDouble() % other
/** Increments this value. */
- public operator fun inc(): Short
- /** Decrements this value. */
- public operator fun dec(): Short
- /** Returns this value. */
- public operator fun unaryPlus(): Int
- /** Returns the negative of this value. */
- public operator fun unaryMinus(): Int
+ public inline operator fun inc(): Short =
+ (this + 1).toShort()
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Byte): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Short): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Int): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Long): LongRange
+ /** Decrements this value. */
+ public inline operator fun dec(): Short =
+ (this - 1).toShort()
+
+ /** Returns this value. */
+ public inline operator fun unaryPlus(): Int =
+ this.toInt()
+
+ /** Returns the negative of this value. */
+ 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())
+// }
/**
* Converts this [Short] value to [Byte].
@@ -433,16 +554,23 @@ public class Short private constructor() : Number(), Comparable {
*
* The resulting `Byte` value is represented by the least significant 8 bits of this `Short` value.
*/
- public override fun toByte(): Byte
+ public override inline fun toByte(): Byte =
+ this.toInt().toByte()
+
/**
* Converts this [Short] value to [Char].
*
* 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`.
*/
- public override fun toChar(): Char
+ @WasmInstruction(WasmInstruction.NOP)
+ public override fun toChar(): Char =
+ implementedAsIntrinsic
+
/** Returns this value. */
- public override fun toShort(): Short
+ public override inline fun toShort(): Short =
+ this
+
/**
* Converts this [Short] value to [Int].
*
@@ -451,7 +579,10 @@ public class Short private constructor() : Number(), Comparable {
* 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.
*/
- public override fun toInt(): Int
+ @WasmInstruction(WasmInstruction.NOP)
+ public override fun toInt(): Int =
+ implementedAsIntrinsic
+
/**
* Converts this [Short] value to [Long].
*
@@ -460,26 +591,48 @@ public class Short private constructor() : Number(), Comparable {
* 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.
*/
- public override fun toLong(): Long
+ @WasmInstruction(WasmInstruction.I64_EXTEND_I32_S)
+ public override fun toLong(): Long =
+ implementedAsIntrinsic
+
/**
* Converts this [Short] value to [Float].
*
* The resulting `Float` value represents the same numerical value as this `Short`.
*/
- public override fun toFloat(): Float
+ @WasmInstruction(WasmInstruction.F32_CONVERT_I32_S)
+ public override fun toFloat(): Float =
+ implementedAsIntrinsic
+
/**
* Converts this [Short] value to [Double].
*
* The resulting `Double` value represents the same numerical value as this `Short`.
*/
- public override fun toDouble(): Double
+ @WasmInstruction(WasmInstruction.F64_CONVERT_I32_S)
+ public override fun toDouble(): Double =
+ implementedAsIntrinsic
+
+ public inline fun equals(other: Short): Boolean =
+ wasm_i32_eq(this.toInt(), other.toInt()).reinterpretAsBoolean()
+
+ // TODO: Support Any? and type operators
+// public override fun equals(other: Any?): Boolean =
+// other is Short && wasm_i32_eq(this.toInt(), other.toInt()).reinterpretAsBoolean()
+
+ // TODO: Implement Short.toString()
+ // public override fun toString(): String
+
+ public override inline fun hashCode(): Int =
+ this.toInt()
}
/**
* Represents a 32-bit signed integer.
- * On the JVM, non-nullable values of this type are represented as values of the primitive type `int`.
*/
public class Int private constructor() : Number(), Comparable {
+
+ @ExcludedFromCodegen
companion object {
/**
* A constant holding the minimum value an instance of Int can have.
@@ -509,165 +662,238 @@ public class Int private constructor() : Number(), Comparable {
* 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 operator fun compareTo(other: Byte): Int
+ public inline operator fun compareTo(other: Byte): Int =
+ this.compareTo(other.toInt())
/**
* 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 operator fun compareTo(other: Short): Int
+ public inline operator fun compareTo(other: Short): Int =
+ this.compareTo(other.toInt())
/**
* 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 operator fun compareTo(other: Int): Int
+ public override inline operator fun compareTo(other: Int): Int =
+ wasm_i32_compareTo(this, other)
/**
* 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 operator fun compareTo(other: Long): Int
+ public inline operator fun compareTo(other: Long): Int =
+ this.toLong().compareTo(other)
/**
* 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 operator fun compareTo(other: Float): Int
+ public inline operator fun compareTo(other: Float): Int =
+ this.toFloat().compareTo(other)
/**
* 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 operator fun compareTo(other: Double): Int
+ public inline operator fun compareTo(other: Double): Int =
+ this.toDouble().compareTo(other)
/** Adds the other value to this value. */
- public operator fun plus(other: Byte): Int
+ public inline operator fun plus(other: Byte): Int =
+ this + other.toInt()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Short): Int
+ public inline operator fun plus(other: Short): Int =
+ this + other.toInt()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Int): Int
+ @WasmInstruction(WasmInstruction.I32_ADD)
+ public operator fun plus(other: Int): Int =
+ implementedAsIntrinsic
+
/** Adds the other value to this value. */
- public operator fun plus(other: Long): Long
+ public inline operator fun plus(other: Long): Long =
+ this.toLong() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Float): Float
+ public inline operator fun plus(other: Float): Float =
+ this.toFloat() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Double): Double
+ public inline operator fun plus(other: Double): Double =
+ this.toDouble() + other
/** Subtracts the other value from this value. */
- public operator fun minus(other: Byte): Int
+ public inline operator fun minus(other: Byte): Int =
+ this - other.toInt()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Short): Int
+ public inline operator fun minus(other: Short): Int =
+ this - other.toInt()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Int): Int
+ @WasmInstruction(WasmInstruction.I32_SUB)
+ public operator fun minus(other: Int): Int =
+ implementedAsIntrinsic
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Long): Long
+ public inline operator fun minus(other: Long): Long =
+ this.toLong() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Float): Float
+ public inline operator fun minus(other: Float): Float =
+ this.toFloat() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Double): Double
+ public inline operator fun minus(other: Double): Double =
+ this.toDouble() - other
/** Multiplies this value by the other value. */
- public operator fun times(other: Byte): Int
+ public inline operator fun times(other: Byte): Int =
+ this * other.toInt()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Short): Int
+ public inline operator fun times(other: Short): Int =
+ this * other.toInt()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Int): Int
+ @WasmInstruction(WasmInstruction.I32_MUL)
+ public operator fun times(other: Int): Int =
+ implementedAsIntrinsic
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Long): Long
+ public inline operator fun times(other: Long): Long =
+ this.toLong() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Float): Float
+ public inline operator fun times(other: Float): Float =
+ this.toFloat() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Double): Double
+ public inline operator fun times(other: Double): Double =
+ this.toDouble() * other
/** Divides this value by the other value. */
- public operator fun div(other: Byte): Int
+ public inline operator fun div(other: Byte): Int =
+ this / other.toInt()
+
/** Divides this value by the other value. */
- public operator fun div(other: Short): Int
+ public inline operator fun div(other: Short): Int =
+ this / other.toInt()
+
/** Divides this value by the other value. */
- public operator fun div(other: Int): Int
+ @WasmInstruction(WasmInstruction.I32_DIV_S)
+ public operator fun div(other: Int): Int =
+ implementedAsIntrinsic
+
/** Divides this value by the other value. */
- public operator fun div(other: Long): Long
+ public inline operator fun div(other: Long): Long =
+ this.toLong() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Float): Float
+ public inline operator fun div(other: Float): Float =
+ this.toFloat() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Double): Double
+ public inline operator fun div(other: Double): Double =
+ this.toDouble() / other
/** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Byte): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Short): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Int): Int
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Long): Long
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Double): Double
+ public inline operator fun rem(other: Byte): Int =
+ this % other.toInt()
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Byte): Int
+ public inline operator fun rem(other: Short): Int =
+ this % other.toInt()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Short): Int
+ @WasmInstruction(WasmInstruction.I32_REM_S)
+ public operator fun rem(other: Int): Int =
+ implementedAsIntrinsic
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Int): Int
+ public inline operator fun rem(other: Long): Long =
+ this.toLong() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Long): Long
+ public inline operator fun rem(other: Float): Float =
+ this.toFloat() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Double): Double
+ public inline operator fun rem(other: Double): Double =
+ this.toDouble() % other
/** Increments this value. */
- public operator fun inc(): Int
- /** Decrements this value. */
- public operator fun dec(): Int
- /** Returns this value. */
- public operator fun unaryPlus(): Int
- /** Returns the negative of this value. */
- public operator fun unaryMinus(): Int
+ public inline operator fun inc(): Int =
+ this + 1
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Byte): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Short): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Int): IntRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Long): LongRange
+ /** Decrements this value. */
+ public inline operator fun dec(): Int =
+ this - 1
+
+ /** Returns this value. */
+ public inline operator fun unaryPlus(): Int = this
+
+ /** Returns the negative of this value. */
+ public inline operator fun unaryMinus(): Int = 0 - this
/** Shifts this value left by the [bitCount] number of bits. */
- public infix fun shl(bitCount: Int): Int
+ @WasmInstruction(WasmInstruction.I32_SHL)
+ public infix fun shl(bitCount: Int): Int =
+ implementedAsIntrinsic
+
/** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with copies of the sign bit. */
- public infix fun shr(bitCount: Int): Int
+ @WasmInstruction(WasmInstruction.I32_SHR_S)
+ public infix fun shr(bitCount: Int): Int =
+ implementedAsIntrinsic
+
/** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with zeros. */
- public infix fun ushr(bitCount: Int): Int
+ @WasmInstruction(WasmInstruction.I32_SHR_U)
+ public infix fun ushr(bitCount: Int): Int =
+ implementedAsIntrinsic
+
/** Performs a bitwise AND operation between the two values. */
- public infix fun and(other: Int): Int
+ @WasmInstruction(WasmInstruction.I32_AND)
+ public infix fun and(other: Int): Int =
+ implementedAsIntrinsic
+
/** Performs a bitwise OR operation between the two values. */
- public infix fun or(other: Int): Int
+ @WasmInstruction(WasmInstruction.I32_OR)
+ public infix fun or(other: Int): Int =
+ implementedAsIntrinsic
+
/** Performs a bitwise XOR operation between the two values. */
- public infix fun xor(other: Int): Int
+ @WasmInstruction(WasmInstruction.I32_XOR)
+ public infix fun xor(other: Int): Int =
+ implementedAsIntrinsic
+
/** Inverts the bits in this value. */
- public fun inv(): 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())
+// }
/**
* Converts this [Int] value to [Byte].
@@ -677,7 +903,9 @@ public class Int private constructor() : Number(), Comparable {
*
* The resulting `Byte` value is represented by the least significant 8 bits of this `Int` value.
*/
- public override fun toByte(): Byte
+ public override fun toByte(): Byte =
+ ((this shl 24) shr 24).reinterpretAsByte()
+
/**
* Converts this [Int] value to [Char].
*
@@ -686,7 +914,9 @@ public class Int private constructor() : Number(), Comparable {
*
* The resulting `Char` code is represented by the least significant 16 bits of this `Int` value.
*/
- public override fun toChar(): Char
+ public override fun toChar(): Char =
+ (this and 0xFFFF).reinterpretAsChar()
+
/**
* Converts this [Int] value to [Short].
*
@@ -695,9 +925,13 @@ public class Int private constructor() : Number(), Comparable {
*
* The resulting `Short` value is represented by the least significant 16 bits of this `Int` value.
*/
- public override fun toShort(): Short
+ public override fun toShort(): Short =
+ ((this shl 16) shr 16).reinterpretAsShort()
+
/** Returns this value. */
- public override fun toInt(): Int
+ public override inline fun toInt(): Int =
+ this
+
/**
* Converts this [Int] value to [Long].
*
@@ -706,7 +940,10 @@ public class Int private constructor() : Number(), Comparable {
* 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.
*/
- public override fun toLong(): Long
+ @WasmInstruction(WasmInstruction.I64_EXTEND_I32_S)
+ public override fun toLong(): Long =
+ implementedAsIntrinsic
+
/**
* Converts this [Int] value to [Float].
*
@@ -714,20 +951,59 @@ public class Int private constructor() : Number(), Comparable {
* In case when this `Int` value is exactly between two `Float`s,
* the one with zero at least significant bit of mantissa is selected.
*/
- public override fun toFloat(): Float
+ @WasmInstruction(WasmInstruction.F32_CONVERT_I32_S)
+ public override fun toFloat(): Float =
+ implementedAsIntrinsic
+
/**
* Converts this [Int] value to [Double].
*
* The resulting `Double` value represents the same numerical value as this `Int`.
*/
- public override fun toDouble(): Double
+ @WasmInstruction(WasmInstruction.F64_CONVERT_I32_S)
+ public override fun toDouble(): Double =
+ implementedAsIntrinsic
+
+ public inline fun equals(other: Int): Boolean =
+ wasm_i32_eq(this, other).reinterpretAsBoolean()
+
+ // TODO: Support Any? and type operators
+// public override fun equals(other: Any?): Boolean =
+// other is Int && wasm_i32_eq(this, other).reinterpretAsBoolean()
+
+ // TODO: Implement Int.toString()
+ // public override fun toString(): String
+
+ public override inline fun hashCode(): Int =
+ this
+
+ @WasmInstruction(WasmInstruction.NOP)
+ @PublishedApi
+ internal fun reinterpretAsBoolean(): Boolean =
+ implementedAsIntrinsic
+
+ @PublishedApi
+ @WasmInstruction(WasmInstruction.NOP)
+ internal fun reinterpretAsByte(): Byte =
+ implementedAsIntrinsic
+
+ @PublishedApi
+ @WasmInstruction(WasmInstruction.NOP)
+ internal fun reinterpretAsShort(): Short =
+ implementedAsIntrinsic
+
+ @PublishedApi
+ @WasmInstruction(WasmInstruction.NOP)
+ internal fun reinterpretAsChar(): Char =
+ implementedAsIntrinsic
}
/**
* Represents a 64-bit signed integer.
- * On the JVM, non-nullable values of this type are represented as values of the primitive type `long`.
*/
public class Long private constructor() : Number(), Comparable {
+
+ @ExcludedFromCodegen
companion object {
/**
* A constant holding the minimum value an instance of Long can have.
@@ -757,165 +1033,236 @@ public class Long private constructor() : Number(), Comparable {
* 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 operator fun compareTo(other: Byte): Int
+ public inline operator fun compareTo(other: Byte): Int =
+ this.compareTo(other.toLong())
/**
* 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 operator fun compareTo(other: Short): Int
+ public inline operator fun compareTo(other: Short): Int =
+ this.compareTo(other.toLong())
/**
* 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 operator fun compareTo(other: Int): Int
+ public inline operator fun compareTo(other: Int): Int =
+ this.compareTo(other.toLong())
/**
* 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 operator fun compareTo(other: Long): Int
+ public override inline operator fun compareTo(other: Long): Int =
+ wasm_i64_compareTo(this, other)
/**
* 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 operator fun compareTo(other: Float): Int
+ public inline operator fun compareTo(other: Float): Int =
+ this.toFloat().compareTo(other)
/**
* 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 operator fun compareTo(other: Double): Int
+ public inline operator fun compareTo(other: Double): Int =
+ this.toDouble().compareTo(other)
/** Adds the other value to this value. */
- public operator fun plus(other: Byte): Long
+ public inline operator fun plus(other: Byte): Long =
+ this + other.toLong()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Short): Long
+ public inline operator fun plus(other: Short): Long =
+ this + other.toLong()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Int): Long
+ public inline operator fun plus(other: Int): Long =
+ this + other.toLong()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Long): Long
+ @WasmInstruction(WasmInstruction.I64_ADD)
+ public operator fun plus(other: Long): Long =
+ implementedAsIntrinsic
+
/** Adds the other value to this value. */
- public operator fun plus(other: Float): Float
+ public inline operator fun plus(other: Float): Float =
+ this.toFloat() + other
+
/** Adds the other value to this value. */
- public operator fun plus(other: Double): Double
+ public inline operator fun plus(other: Double): Double =
+ this.toDouble() + other
/** Subtracts the other value from this value. */
- public operator fun minus(other: Byte): Long
+ public inline operator fun minus(other: Byte): Long =
+ this - other.toLong()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Short): Long
+ public inline operator fun minus(other: Short): Long =
+ this - other.toLong()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Int): Long
+ public inline operator fun minus(other: Int): Long =
+ this - other.toLong()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Long): Long
+ @WasmInstruction(WasmInstruction.I64_SUB)
+ public operator fun minus(other: Long): Long =
+ implementedAsIntrinsic
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Float): Float
+ public inline operator fun minus(other: Float): Float =
+ this.toFloat() - other
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Double): Double
+ public inline operator fun minus(other: Double): Double =
+ this.toDouble() - other
/** Multiplies this value by the other value. */
- public operator fun times(other: Byte): Long
+ public inline operator fun times(other: Byte): Long =
+ this * other.toLong()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Short): Long
+ public inline operator fun times(other: Short): Long =
+ this * other.toLong()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Int): Long
+ public inline operator fun times(other: Int): Long =
+ this * other.toLong()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Long): Long
+ @WasmInstruction(WasmInstruction.I64_MUL)
+ public operator fun times(other: Long): Long =
+ implementedAsIntrinsic
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Float): Float
+ public inline operator fun times(other: Float): Float =
+ this.toFloat() * other
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Double): Double
+ public inline operator fun times(other: Double): Double =
+ this.toDouble() * other
/** Divides this value by the other value. */
- public operator fun div(other: Byte): Long
+ public inline operator fun div(other: Byte): Long =
+ this / other.toLong()
+
/** Divides this value by the other value. */
- public operator fun div(other: Short): Long
+ public inline operator fun div(other: Short): Long =
+ this / other.toLong()
+
/** Divides this value by the other value. */
- public operator fun div(other: Int): Long
+ public inline operator fun div(other: Int): Long =
+ this / other.toLong()
+
/** Divides this value by the other value. */
- public operator fun div(other: Long): Long
+ @WasmInstruction(WasmInstruction.I64_DIV_S)
+ public operator fun div(other: Long): Long =
+ implementedAsIntrinsic
+
/** Divides this value by the other value. */
- public operator fun div(other: Float): Float
+ public inline operator fun div(other: Float): Float =
+ this.toFloat() / other
+
/** Divides this value by the other value. */
- public operator fun div(other: Double): Double
+ public inline operator fun div(other: Double): Double =
+ this.toDouble() / other
/** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Byte): Long
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Short): Long
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Int): Long
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Long): Long
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Double): Double
+ public inline operator fun rem(other: Byte): Long =
+ this % other.toLong()
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Byte): Long
+ public inline operator fun rem(other: Short): Long =
+ this % other.toLong()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Short): Long
+ public inline operator fun rem(other: Int): Long =
+ this % other.toLong()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Int): Long
+ @WasmInstruction(WasmInstruction.I64_REM_S)
+ public operator fun rem(other: Long): Long =
+ implementedAsIntrinsic
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Long): Long
+ public inline operator fun rem(other: Float): Float =
+ this.toFloat() % other
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Double): Double
+ public inline operator fun rem(other: Double): Double =
+ this.toDouble() % other
/** Increments this value. */
- public operator fun inc(): Long
- /** Decrements this value. */
- public operator fun dec(): Long
- /** Returns this value. */
- public operator fun unaryPlus(): Long
- /** Returns the negative of this value. */
- public operator fun unaryMinus(): Long
+ public inline operator fun inc(): Long =
+ this + 1L
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Byte): LongRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Short): LongRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Int): LongRange
-// /** Creates a range from this value to the specified [other] value. */
-// public operator fun rangeTo(other: Long): LongRange
+ /** Decrements this value. */
+ public inline operator fun dec(): Long =
+ this - 1L
+
+ /** Returns this value. */
+ public inline operator fun unaryPlus(): Long =
+ this
+
+ /** 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())
+// }
/** Shifts this value left by the [bitCount] number of bits. */
- public infix fun shl(bitCount: Int): Long
+ public inline infix fun shl(bitCount: Int): Long =
+ wasm_i64_shl(this, bitCount.toLong())
+
/** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with copies of the sign bit. */
- public infix fun shr(bitCount: Int): Long
+ public inline infix fun shr(bitCount: Int): Long =
+ wasm_i64_shr_s(this, bitCount.toLong())
+
/** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with zeros. */
- public infix fun ushr(bitCount: Int): Long
+ public inline infix fun ushr(bitCount: Int): Long =
+ wasm_i64_shr_u(this, bitCount.toLong())
+
/** Performs a bitwise AND operation between the two values. */
- public infix fun and(other: Long): Long
+ @WasmInstruction(WasmInstruction.I64_AND)
+ public infix fun and(other: Long): Long =
+ implementedAsIntrinsic
+
/** Performs a bitwise OR operation between the two values. */
- public infix fun or(other: Long): Long
+ @WasmInstruction(WasmInstruction.I64_OR)
+ public infix fun or(other: Long): Long =
+ implementedAsIntrinsic
+
/** Performs a bitwise XOR operation between the two values. */
- public infix fun xor(other: Long): Long
+ @WasmInstruction(WasmInstruction.I64_XOR)
+ public infix fun xor(other: Long): Long =
+ implementedAsIntrinsic
+
/** Inverts the bits in this value. */
- public fun inv(): Long
+ public inline fun inv(): Long =
+ this.xor(-1L)
/**
* Converts this [Long] value to [Byte].
@@ -925,7 +1272,9 @@ public class Long private constructor() : Number(), Comparable {
*
* The resulting `Byte` value is represented by the least significant 8 bits of this `Long` value.
*/
- public override fun toByte(): Byte
+ public override inline fun toByte(): Byte =
+ this.toInt().toByte()
+
/**
* Converts this [Long] value to [Char].
*
@@ -934,7 +1283,9 @@ public class Long private constructor() : Number(), Comparable {
*
* The resulting `Char` code is represented by the least significant 16 bits of this `Long` value.
*/
- public override fun toChar(): Char
+ public override inline fun toChar(): Char =
+ this.toInt().toChar()
+
/**
* Converts this [Long] value to [Short].
*
@@ -943,7 +1294,9 @@ public class Long private constructor() : Number(), Comparable {
*
* The resulting `Short` value is represented by the least significant 16 bits of this `Long` value.
*/
- public override fun toShort(): Short
+ public override inline fun toShort(): Short =
+ this.toInt().toShort()
+
/**
* Converts this [Long] value to [Int].
*
@@ -952,9 +1305,14 @@ public class Long private constructor() : Number(), Comparable {
*
* The resulting `Int` value is represented by the least significant 32 bits of this `Long` value.
*/
- public override fun toInt(): Int
+ @WasmInstruction(WasmInstruction.I32_WRAP_I64)
+ public override fun toInt(): Int =
+ implementedAsIntrinsic
+
/** Returns this value. */
- public override fun toLong(): Long
+ public override inline fun toLong(): Long =
+ this
+
/**
* Converts this [Long] value to [Float].
*
@@ -962,7 +1320,10 @@ public class Long private constructor() : Number(), Comparable {
* In case when this `Long` value is exactly between two `Float`s,
* the one with zero at least significant bit of mantissa is selected.
*/
- public override fun toFloat(): Float
+ @WasmInstruction(WasmInstruction.F32_CONVERT_I64_S)
+ public override fun toFloat(): Float =
+ implementedAsIntrinsic
+
/**
* Converts this [Long] value to [Double].
*
@@ -970,39 +1331,57 @@ public class Long private constructor() : Number(), Comparable {
* In case when this `Long` value is exactly between two `Double`s,
* the one with zero at least significant bit of mantissa is selected.
*/
- public override fun toDouble(): Double
+ @WasmInstruction(WasmInstruction.F64_CONVERT_I64_S)
+ public override fun toDouble(): Double =
+ implementedAsIntrinsic
+
+ public inline fun equals(other: Long): Boolean =
+ wasm_i64_eq(this, other).reinterpretAsBoolean()
+
+ // TODO: Support Any? and type operators
+// public override fun equals(other: Any?): Boolean =
+// other is Long && wasm_i64_eq(this, other).reinterpretAsBoolean()
+
+ // TODO: Implement Long.toString()
+ // public override fun toString(): String
+
+ public override fun hashCode(): Int =
+ ((this ushr 32) xor this).toInt()
}
/**
* Represents a single-precision 32-bit IEEE 754 floating point number.
- * On the JVM, non-nullable values of this type are represented as values of the primitive type `float`.
*/
public class Float private constructor() : Number(), Comparable {
+
+ @ExcludedFromCodegen
companion object {
/**
* A constant holding the smallest *positive* nonzero value of Float.
*/
- public val MIN_VALUE: Float
+ public const val MIN_VALUE: Float = 1.40129846432481707e-45f
/**
* A constant holding the largest positive finite value of Float.
*/
- public val MAX_VALUE: Float
+ public const val MAX_VALUE: Float = 3.40282346638528860e+38f
/**
* A constant holding the positive infinity value of Float.
*/
- public val POSITIVE_INFINITY: Float
+ @Suppress("DIVISION_BY_ZERO")
+ public val POSITIVE_INFINITY: Float = 1.0f / 0.0f
/**
* A constant holding the negative infinity value of Float.
*/
- public val NEGATIVE_INFINITY: Float
+ @Suppress("DIVISION_BY_ZERO")
+ public val NEGATIVE_INFINITY: Float = -1.0f / 0.0f
/**
* A constant holding the "not a number" value of Float.
*/
- public val NaN: Float
+ public val NaN: Float = wasm_f32_const_nan()
}
/**
@@ -1010,161 +1389,214 @@ public class Float private constructor() : Number(), Comparable {
* 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 operator fun compareTo(other: Byte): Int
+ public inline operator fun compareTo(other: Byte): Int = compareTo(other.toFloat())
/**
* 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 operator fun compareTo(other: Short): Int
+ public inline operator fun compareTo(other: Short): Int = compareTo(other.toFloat())
/**
* 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 operator fun compareTo(other: Int): Int
+ public inline operator fun compareTo(other: Int): Int = compareTo(other.toFloat())
/**
* 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 operator fun compareTo(other: Long): Int
+ public inline operator fun compareTo(other: Long): Int = compareTo(other.toFloat())
/**
* 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 operator fun compareTo(other: Float): Int
+ public override operator fun compareTo(other: Float): Int {
+ // if any of values in NaN both comparisons return false
+ if (this > other) return 1
+ if (this < other) return -1
+
+ val thisBits = this.bits()
+ val otherBits = other.bits()
+
+ // Canonical NaN bits representation higher than any other value
+ return thisBits.compareTo(otherBits)
+ }
/**
* 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 operator fun compareTo(other: Double): Int
+ public inline operator fun compareTo(other: Double): Int = -other.compareTo(this)
/** Adds the other value to this value. */
- public operator fun plus(other: Byte): Float
+ public inline operator fun plus(other: Byte): Float =
+ this + other.toFloat()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Short): Float
+ public inline operator fun plus(other: Short): Float =
+ this + other.toFloat()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Int): Float
+ public inline operator fun plus(other: Int): Float =
+ this + other.toFloat()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Long): Float
+ public inline operator fun plus(other: Long): Float =
+ this + other.toFloat()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Float): Float
+ @WasmInstruction(WasmInstruction.F32_ADD)
+ public operator fun plus(other: Float): Float =
+ implementedAsIntrinsic
+
/** Adds the other value to this value. */
- public operator fun plus(other: Double): Double
+ public inline operator fun plus(other: Double): Double =
+ this.toDouble() + other
/** Subtracts the other value from this value. */
- public operator fun minus(other: Byte): Float
+ public inline operator fun minus(other: Byte): Float =
+ this - other.toFloat()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Short): Float
+ public inline operator fun minus(other: Short): Float =
+ this - other.toFloat()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Int): Float
+ public inline operator fun minus(other: Int): Float =
+ this - other.toFloat()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Long): Float
+ public inline operator fun minus(other: Long): Float =
+ this - other.toFloat()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Float): Float
+ @WasmInstruction(WasmInstruction.F32_SUB)
+ public operator fun minus(other: Float): Float =
+ implementedAsIntrinsic
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Double): Double
+ public inline operator fun minus(other: Double): Double =
+ this.toDouble() - other
/** Multiplies this value by the other value. */
- public operator fun times(other: Byte): Float
+ public inline operator fun times(other: Byte): Float =
+ this * other.toFloat()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Short): Float
+ public inline operator fun times(other: Short): Float =
+ this * other.toFloat()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Int): Float
+ public inline operator fun times(other: Int): Float =
+ this * other.toFloat()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Long): Float
+ public inline operator fun times(other: Long): Float =
+ this * other.toFloat()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Float): Float
+ @WasmInstruction(WasmInstruction.F32_MUL)
+ public operator fun times(other: Float): Float =
+ implementedAsIntrinsic
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Double): Double
+ public inline operator fun times(other: Double): Double =
+ this.toDouble() * other
/** Divides this value by the other value. */
- public operator fun div(other: Byte): Float
+ public inline operator fun div(other: Byte): Float =
+ this / other.toFloat()
+
/** Divides this value by the other value. */
- public operator fun div(other: Short): Float
+ public inline operator fun div(other: Short): Float =
+ this / other.toFloat()
+
/** Divides this value by the other value. */
- public operator fun div(other: Int): Float
+ public inline operator fun div(other: Int): Float =
+ this / other.toFloat()
+
/** Divides this value by the other value. */
- public operator fun div(other: Long): Float
+ public inline operator fun div(other: Long): Float =
+ this / other.toFloat()
+
/** Divides this value by the other value. */
- public operator fun div(other: Float): Float
+ @WasmInstruction(WasmInstruction.F32_DIV)
+ public operator fun div(other: Float): Float =
+ implementedAsIntrinsic
+
/** Divides this value by the other value. */
- public operator fun div(other: Double): Double
+ public inline operator fun div(other: Double): Double =
+ this.toDouble() / other
/** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Byte): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Short): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Int): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Long): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Double): Double
+ public inline operator fun rem(other: Byte): Float =
+ this % other.toFloat()
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Byte): Float
+ public inline operator fun rem(other: Short): Float =
+ this % other.toFloat()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Short): Float
+ public inline operator fun rem(other: Int): Float =
+ this % other.toFloat()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Int): Float
+ public inline operator fun rem(other: Long): Float =
+ this % other.toFloat()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Long): Float
+ public operator fun rem(other: Float): Float =
+ this - (wasm_f32_nearest(this / other) * other)
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Float): Float
- /** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Double): Double
+ public inline operator fun rem(other: Double): Double =
+ this.toDouble() % other
/** Increments this value. */
- public operator fun inc(): Float
- /** Decrements this value. */
- public operator fun dec(): Float
- /** Returns this value. */
- public operator fun unaryPlus(): Float
- /** Returns the negative of this value. */
- public operator fun unaryMinus(): Float
+ public inline operator fun inc(): Float =
+ this + 1.0f
+ /** Decrements this value. */
+ public inline operator fun dec(): Float =
+ this - 1.0f
+
+ /** Returns this value. */
+ public inline operator fun unaryPlus(): Float = this
+
+ /** Returns the negative of this value. */
+ @WasmInstruction(WasmInstruction.F32_NEG)
+ public operator fun unaryMinus(): Float =
+ implementedAsIntrinsic
/**
* Converts this [Float] value to [Byte].
*
* The resulting `Byte` value is equal to `this.toInt().toByte()`.
*/
- public override fun toByte(): Byte
+ public override inline fun toByte(): Byte = this.toInt().toByte()
+
/**
* Converts this [Float] value to [Char].
*
* The resulting `Char` value is equal to `this.toInt().toChar()`.
*/
- public override fun toChar(): Char
+ public override inline fun toChar(): Char = this.toInt().toChar()
+
/**
* Converts this [Float] value to [Short].
*
* The resulting `Short` value is equal to `this.toInt().toShort()`.
*/
- public override fun toShort(): Short
+ public override inline fun toShort(): Short = this.toInt().toShort()
+
/**
* Converts this [Float] value to [Int].
*
@@ -1172,7 +1604,12 @@ public class Float private constructor() : Number(), Comparable {
* 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`.
*/
- public override fun toInt(): Int
+ // TODO: Implement Float.toInt()
+ public override fun toInt(): Int {
+ wasm_unreachable()
+ return 0
+ }
+
/**
* Converts this [Float] value to [Long].
*
@@ -1180,47 +1617,76 @@ public class Float private constructor() : Number(), Comparable {
* 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`.
*/
- public override fun toLong(): Long
+ // TODO: Implement Float.toLong()
+ public override fun toLong(): Long {
+ wasm_unreachable()
+ return 0
+ }
+
/** Returns this value. */
- public override fun toFloat(): Float
+ public override inline fun toFloat(): Float =
+ this
+
/**
* Converts this [Float] value to [Double].
*
* The resulting `Double` value represents the same numerical value as this `Float`.
*/
- public override fun toDouble(): Double
+ @WasmInstruction(WasmInstruction.F64_PROMOTE_F32)
+ public override fun toDouble(): Double =
+ implementedAsIntrinsic
+
+ 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)
+
+ // TODO: Implement Float.toString()
+ // public override fun toString(): String
+
+ public override inline fun hashCode(): Int =
+ bits()
+
+ @PublishedApi
+ @WasmInstruction(WasmInstruction.I32_REINTERPRET_F32)
+ internal fun bits(): Int = implementedAsIntrinsic
}
/**
* Represents a double-precision 64-bit IEEE 754 floating point number.
- * On the JVM, non-nullable values of this type are represented as values of the primitive type `double`.
*/
public class Double private constructor() : Number(), Comparable {
+
+ @ExcludedFromCodegen
companion object {
/**
* A constant holding the smallest *positive* nonzero value of Double.
*/
- public val MIN_VALUE: Double
+ public const val MIN_VALUE: Double = 4.9e-324
/**
* A constant holding the largest positive finite value of Double.
*/
- public val MAX_VALUE: Double
+ public const val MAX_VALUE: Double = 1.7976931348623157e+308
/**
* A constant holding the positive infinity value of Double.
*/
- public val POSITIVE_INFINITY: Double
+ @Suppress("DIVISION_BY_ZERO")
+ public val POSITIVE_INFINITY: Double = 1.0 / 0.0
/**
* A constant holding the negative infinity value of Double.
*/
- public val NEGATIVE_INFINITY: Double
+ @Suppress("DIVISION_BY_ZERO")
+ public val NEGATIVE_INFINITY: Double = -1.0 / 0.0
/**
* A constant holding the "not a number" value of Double.
*/
- public val NaN: Double
+ public val NaN: Double = wasm_f64_const_nan()
}
/**
@@ -1228,161 +1694,215 @@ public class Double private constructor() : Number(), Comparable {
* 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 operator fun compareTo(other: Byte): Int
+ public inline operator fun compareTo(other: Byte): Int = compareTo(other.toDouble())
/**
* 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 operator fun compareTo(other: Short): Int
+ public inline operator fun compareTo(other: Short): Int = compareTo(other.toDouble())
/**
* 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 operator fun compareTo(other: Int): Int
+ public inline operator fun compareTo(other: Int): Int = compareTo(other.toDouble())
/**
* 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 operator fun compareTo(other: Long): Int
+ public inline operator fun compareTo(other: Long): Int = compareTo(other.toDouble())
/**
* 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 operator fun compareTo(other: Float): Int
+ public inline operator fun compareTo(other: Float): Int = compareTo(other.toDouble())
/**
* 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 operator fun compareTo(other: Double): Int
+ public override operator fun compareTo(other: Double): Int {
+ // if any of values in NaN both comparisons return false
+ if (this > other) return 1
+ if (this < other) return -1
+
+ val thisBits = this.bits()
+ val otherBits = other.bits()
+
+ // Canonical NaN bits representation higher than any other value
+ return thisBits.compareTo(otherBits)
+ }
/** Adds the other value to this value. */
- public operator fun plus(other: Byte): Double
+ public inline operator fun plus(other: Byte): Double =
+ this + other.toDouble()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Short): Double
+ public inline operator fun plus(other: Short): Double =
+ this + other.toDouble()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Int): Double
+ public inline operator fun plus(other: Int): Double =
+ this + other.toDouble()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Long): Double
+ public inline operator fun plus(other: Long): Double =
+ this + other.toDouble()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Float): Double
+ public inline operator fun plus(other: Float): Double =
+ this + other.toDouble()
+
/** Adds the other value to this value. */
- public operator fun plus(other: Double): Double
+ @WasmInstruction(WasmInstruction.F64_ADD)
+ public operator fun plus(other: Double): Double =
+ implementedAsIntrinsic
/** Subtracts the other value from this value. */
- public operator fun minus(other: Byte): Double
+ public inline operator fun minus(other: Byte): Double =
+ this - other.toDouble()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Short): Double
+ public inline operator fun minus(other: Short): Double =
+ this - other.toDouble()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Int): Double
+ public inline operator fun minus(other: Int): Double =
+ this - other.toDouble()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Long): Double
+ public inline operator fun minus(other: Long): Double =
+ this - other.toDouble()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Float): Double
+ public inline operator fun minus(other: Float): Double =
+ this - other.toDouble()
+
/** Subtracts the other value from this value. */
- public operator fun minus(other: Double): Double
+ @WasmInstruction(WasmInstruction.F64_SUB)
+ public operator fun minus(other: Double): Double =
+ implementedAsIntrinsic
/** Multiplies this value by the other value. */
- public operator fun times(other: Byte): Double
+ public inline operator fun times(other: Byte): Double =
+ this * other.toDouble()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Short): Double
+ public inline operator fun times(other: Short): Double =
+ this * other.toDouble()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Int): Double
+ public inline operator fun times(other: Int): Double =
+ this * other.toDouble()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Long): Double
+ public inline operator fun times(other: Long): Double =
+ this * other.toDouble()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Float): Double
+ public inline operator fun times(other: Float): Double =
+ this * other.toDouble()
+
/** Multiplies this value by the other value. */
- public operator fun times(other: Double): Double
+ @WasmInstruction(WasmInstruction.F64_MUL)
+ public operator fun times(other: Double): Double =
+ implementedAsIntrinsic
/** Divides this value by the other value. */
- public operator fun div(other: Byte): Double
+ public inline operator fun div(other: Byte): Double =
+ this / other.toDouble()
+
/** Divides this value by the other value. */
- public operator fun div(other: Short): Double
+ public inline operator fun div(other: Short): Double =
+ this / other.toDouble()
+
/** Divides this value by the other value. */
- public operator fun div(other: Int): Double
+ public inline operator fun div(other: Int): Double =
+ this / other.toDouble()
+
/** Divides this value by the other value. */
- public operator fun div(other: Long): Double
+ public inline operator fun div(other: Long): Double =
+ this / other.toDouble()
+
/** Divides this value by the other value. */
- public operator fun div(other: Float): Double
+ public inline operator fun div(other: Float): Double =
+ this / other.toDouble()
+
/** Divides this value by the other value. */
- public operator fun div(other: Double): Double
+ @WasmInstruction(WasmInstruction.F64_DIV)
+ public operator fun div(other: Double): Double =
+ implementedAsIntrinsic
/** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Byte): Double
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Short): Double
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Int): Double
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Long): Double
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Float): Double
- /** Calculates the remainder of dividing this value by the other value. */
- @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.ERROR)
- public operator fun mod(other: Double): Double
+ public inline operator fun rem(other: Byte): Double =
+ this % other.toDouble()
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Byte): Double
+ public inline operator fun rem(other: Short): Double =
+ this % other.toDouble()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Short): Double
+ public inline operator fun rem(other: Int): Double =
+ this % other.toDouble()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Int): Double
+ public inline operator fun rem(other: Long): Double =
+ this % other.toDouble()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Long): Double
+ public inline operator fun rem(other: Float): Double =
+ this % other.toDouble()
+
/** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Float): Double
- /** Calculates the remainder of dividing this value by the other value. */
- @SinceKotlin("1.1")
- public operator fun rem(other: Double): Double
+ public operator fun rem(other: Double): Double =
+ this - (wasm_f64_nearest(this / other) * other)
/** Increments this value. */
- public operator fun inc(): Double
- /** Decrements this value. */
- public operator fun dec(): Double
- /** Returns this value. */
- public operator fun unaryPlus(): Double
- /** Returns the negative of this value. */
- public operator fun unaryMinus(): Double
+ public inline operator fun inc(): Double =
+ this + 1.0
+ /** Decrements this value. */
+ public inline operator fun dec(): Double =
+ this - 1.0
+
+ /** Returns this value. */
+ public inline operator fun unaryPlus(): Double =
+ this
+
+ /** Returns the negative of this value. */
+ @WasmInstruction(WasmInstruction.F64_NEG)
+ public operator fun unaryMinus(): Double =
+ implementedAsIntrinsic
/**
* Converts this [Double] value to [Byte].
*
* The resulting `Byte` value is equal to `this.toInt().toByte()`.
*/
- public override fun toByte(): Byte
+ public override inline fun toByte(): Byte = this.toInt().toByte()
+
/**
* Converts this [Double] value to [Char].
*
* The resulting `Char` value is equal to `this.toInt().toChar()`.
*/
- public override fun toChar(): Char
+ public override inline fun toChar(): Char = this.toInt().toChar()
+
/**
* Converts this [Double] value to [Short].
*
* The resulting `Short` value is equal to `this.toInt().toShort()`.
*/
- public override fun toShort(): Short
+ public override inline fun toShort(): Short = this.toInt().toShort()
+
/**
* Converts this [Double] value to [Int].
*
@@ -1390,7 +1910,12 @@ public class Double private constructor() : Number(), Comparable {
* 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`.
*/
- public override fun toInt(): Int
+ // TODO: Implement Double.toInt()
+ public override fun toInt(): Int {
+ wasm_unreachable()
+ return 0
+ }
+
/**
* Converts this [Double] value to [Long].
*
@@ -1398,7 +1923,12 @@ public class Double private constructor() : Number(), Comparable {
* 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`.
*/
- public override fun toLong(): Long
+ // TODO: Implement Double.toLong()
+ public override fun toLong(): Long {
+ wasm_unreachable()
+ return 0
+ }
+
/**
* Converts this [Double] value to [Float].
*
@@ -1406,8 +1936,28 @@ public class Double private constructor() : Number(), Comparable {
* In case when this `Double` value is exactly between two `Float`s,
* the one with zero at least significant bit of mantissa is selected.
*/
- public override fun toFloat(): Float
- /** Returns this value. */
- public override fun toDouble(): Double
-}
+ @WasmInstruction(WasmInstruction.F32_DEMOTE_F64)
+ public override fun toFloat(): Float =
+ implementedAsIntrinsic
+ /** Returns this value. */
+ public override inline fun toDouble(): Double =
+ this
+
+ 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()
+
+ // TODO: Implement Double.toString()
+ // public override fun toString(): String
+
+ public override inline fun hashCode(): Int = bits().hashCode()
+
+ @PublishedApi
+ @WasmInstruction(WasmInstruction.I64_REINTERPRET_F64)
+ internal fun bits(): Long =
+ implementedAsIntrinsic
+}
diff --git a/libraries/stdlib/wasm/builtins/native/kotlin/String.kt b/libraries/stdlib/wasm/builtins/native/kotlin/String.kt
index 6078b39b288..198d09abae4 100644
--- a/libraries/stdlib/wasm/builtins/native/kotlin/String.kt
+++ b/libraries/stdlib/wasm/builtins/native/kotlin/String.kt
@@ -13,19 +13,25 @@
package kotlin
+import kotlin.wasm.internal.ExcludedFromCodegen
+import kotlin.wasm.internal.WasmImport
+
/**
* The `String` class represents character strings. All string literals in Kotlin programs, such as `"abc"`, are
* implemented as instances of this class.
*/
public class String : Comparable, CharSequence {
+ @ExcludedFromCodegen
companion object {}
/**
* Returns a string obtained by concatenating this string with the string representation of the given [other] object.
*/
+ @WasmImport("runtime", "String_plus")
public operator fun plus(other: Any?): String
public override val length: Int
+ @WasmImport("runtime", "String_getLength") get
/**
* Returns the character of this string at the specified [index].
@@ -33,9 +39,20 @@ public class String : Comparable, CharSequence {
* If the [index] is out of bounds of this string, throws an [IndexOutOfBoundsException] except in Kotlin/JS
* where the behavior is unspecified.
*/
+ @WasmImport("runtime", "String_getChar")
public override fun get(index: Int): Char
+ @ExcludedFromCodegen
public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence
+ @WasmImport("runtime", "String_compareTo")
public override fun compareTo(other: String): Int
-}
+
+ @ExcludedFromCodegen
+ public override fun equals(other: Any?): Boolean
+
+ public override fun toString(): String = this
+
+ @ExcludedFromCodegen
+ public override fun hashCode(): Int
+}
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/internal/WasmInstructions.kt b/libraries/stdlib/wasm/internal/WasmInstructions.kt
new file mode 100644
index 00000000000..a4369aed7ea
--- /dev/null
+++ b/libraries/stdlib/wasm/internal/WasmInstructions.kt
@@ -0,0 +1,397 @@
+/*
+ * 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:ExcludedFromCodegen
+@file:Suppress("NON_ABSTRACT_FUNCTION_WITH_NO_BODY", "unused")
+
+package kotlin.wasm.internal
+
+@WasmInstruction(WasmInstruction.UNREACHABLE)
+external fun wasm_unreachable(): Nothing
+
+@WasmInstruction(WasmInstruction.I32_EQZ)
+external fun wasm_i32_eqz(a: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_EQ)
+external fun wasm_i32_eq(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_NE)
+external fun wasm_i32_ne(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_LT_S)
+external fun wasm_i32_lt_s(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_LT_U)
+external fun wasm_i32_lt_u(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_GT_S)
+external fun wasm_i32_gt_s(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_GT_U)
+external fun wasm_i32_gt_u(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_LE_S)
+external fun wasm_i32_le_s(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_LE_U)
+external fun wasm_i32_le_u(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_GE_S)
+external fun wasm_i32_ge_s(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_GE_U)
+external fun wasm_i32_ge_u(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I64_EQZ)
+external fun wasm_i64_eqz(a: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_EQ)
+external fun wasm_i64_eq(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_NE)
+external fun wasm_i64_ne(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_LT_S)
+external fun wasm_i64_lt_s(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_LT_U)
+external fun wasm_i64_lt_u(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_GT_S)
+external fun wasm_i64_gt_s(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_GT_U)
+external fun wasm_i64_gt_u(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_LE_S)
+external fun wasm_i64_le_s(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_LE_U)
+external fun wasm_i64_le_u(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_GE_S)
+external fun wasm_i64_ge_s(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.I64_GE_U)
+external fun wasm_i64_ge_u(a: Long, b: Long): Int
+
+@WasmInstruction(WasmInstruction.F32_EQ)
+external fun wasm_f32_eq(a: Float, b: Float): Int
+
+@WasmInstruction(WasmInstruction.F32_NE)
+external fun wasm_f32_ne(a: Float, b: Float): Int
+
+@WasmInstruction(WasmInstruction.F32_LT)
+external fun wasm_f32_lt(a: Float, b: Float): Int
+
+@WasmInstruction(WasmInstruction.F32_GT)
+external fun wasm_f32_gt(a: Float, b: Float): Int
+
+@WasmInstruction(WasmInstruction.F32_LE)
+external fun wasm_f32_le(a: Float, b: Float): Int
+
+@WasmInstruction(WasmInstruction.F32_GE)
+external fun wasm_f32_ge(a: Float, b: Float): Int
+
+@WasmInstruction(WasmInstruction.F64_EQ)
+external fun wasm_f64_eq(a: Double, b: Double): Int
+
+@WasmInstruction(WasmInstruction.F64_NE)
+external fun wasm_f64_ne(a: Double, b: Double): Int
+
+@WasmInstruction(WasmInstruction.F64_LT)
+external fun wasm_f64_lt(a: Double, b: Double): Int
+
+@WasmInstruction(WasmInstruction.F64_GT)
+external fun wasm_f64_gt(a: Double, b: Double): Int
+
+@WasmInstruction(WasmInstruction.F64_LE)
+external fun wasm_f64_le(a: Double, b: Double): Int
+
+@WasmInstruction(WasmInstruction.F64_GE)
+external fun wasm_f64_ge(a: Double, b: Double): Int
+
+@WasmInstruction(WasmInstruction.I32_CLZ)
+external fun wasm_i32_clz(a: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_CTZ)
+external fun wasm_i32_ctz(a: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_POPCNT)
+external fun wasm_i32_popcnt(a: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_ADD)
+external fun wasm_i32_add(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_SUB)
+external fun wasm_i32_sub(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_MUL)
+external fun wasm_i32_mul(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_DIV_S)
+external fun wasm_i32_div_s(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_DIV_U)
+external fun wasm_i32_div_u(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_REM_S)
+external fun wasm_i32_rem_s(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_REM_U)
+external fun wasm_i32_rem_u(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_AND)
+external fun wasm_i32_and(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_OR)
+external fun wasm_i32_or(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_XOR)
+external fun wasm_i32_xor(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_SHL)
+external fun wasm_i32_shl(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_SHR_S)
+external fun wasm_i32_shr_s(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_SHR_U)
+external fun wasm_i32_shr_u(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_ROTL)
+external fun wasm_i32_rotl(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I32_ROTR)
+external fun wasm_i32_rotr(a: Int, b: Int): Int
+
+@WasmInstruction(WasmInstruction.I64_CLZ)
+external fun wasm_i64_clz(a: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_CTZ)
+external fun wasm_i64_ctz(a: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_POPCNT)
+external fun wasm_i64_popcnt(a: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_ADD)
+external fun wasm_i64_add(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_SUB)
+external fun wasm_i64_sub(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_MUL)
+external fun wasm_i64_mul(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_DIV_S)
+external fun wasm_i64_div_s(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_DIV_U)
+external fun wasm_i64_div_u(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_REM_S)
+external fun wasm_i64_rem_s(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_REM_U)
+external fun wasm_i64_rem_u(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_AND)
+external fun wasm_i64_and(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_OR)
+external fun wasm_i64_or(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_XOR)
+external fun wasm_i64_xor(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_SHL)
+external fun wasm_i64_shl(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_SHR_S)
+external fun wasm_i64_shr_s(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_SHR_U)
+external fun wasm_i64_shr_u(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_ROTL)
+external fun wasm_i64_rotl(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.I64_ROTR)
+external fun wasm_i64_rotr(a: Long, b: Long): Long
+
+@WasmInstruction(WasmInstruction.F32_ABS)
+external fun wasm_f32_abs(a: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_NEG)
+external fun wasm_f32_neg(a: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_CEIL)
+external fun wasm_f32_ceil(a: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_FLOOR)
+external fun wasm_f32_floor(a: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_TRUNC)
+external fun wasm_f32_trunc(a: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_NEAREST)
+external fun wasm_f32_nearest(a: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_SQRT)
+external fun wasm_f32_sqrt(a: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_ADD)
+external fun wasm_f32_add(a: Float, b: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_SUB)
+external fun wasm_f32_sub(a: Float, b: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_MUL)
+external fun wasm_f32_mul(a: Float, b: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_DIV)
+external fun wasm_f32_div(a: Float, b: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_FMIN)
+external fun wasm_f32_fmin(a: Float, b: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_FMAX)
+external fun wasm_f32_fmax(a: Float, b: Float): Float
+
+@WasmInstruction(WasmInstruction.F32_COPYSIGN)
+external fun wasm_f32_copysign(a: Float, b: Float): Float
+
+@WasmInstruction(WasmInstruction.F64_ABS)
+external fun wasm_f64_abs(a: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_NEG)
+external fun wasm_f64_neg(a: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_CEIL)
+external fun wasm_f64_ceil(a: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_FLOOR)
+external fun wasm_f64_floor(a: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_TRUNC)
+external fun wasm_f64_trunc(a: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_NEAREST)
+external fun wasm_f64_nearest(a: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_SQRT)
+external fun wasm_f64_sqrt(a: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_ADD)
+external fun wasm_f64_add(a: Double, b: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_SUB)
+external fun wasm_f64_sub(a: Double, b: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_MUL)
+external fun wasm_f64_mul(a: Double, b: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_DIV)
+external fun wasm_f64_div(a: Double, b: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_FMIN)
+external fun wasm_f64_fmin(a: Double, b: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_FMAX)
+external fun wasm_f64_fmax(a: Double, b: Double): Double
+
+@WasmInstruction(WasmInstruction.F64_COPYSIGN)
+external fun wasm_f64_copysign(a: Double, b: Double): Double
+
+@WasmInstruction(WasmInstruction.I32_WRAP_I64)
+external fun wasm_i32_wrap_i64(a: Long): Int
+
+@WasmInstruction(WasmInstruction.I32_TRUNC_F32_S)
+external fun wasm_i32_trunc_f32_s(a: Float): Int
+
+@WasmInstruction(WasmInstruction.I32_TRUNC_F32_U)
+external fun wasm_i32_trunc_f32_u(a: Float): Int
+
+@WasmInstruction(WasmInstruction.I32_TRUNC_F64_S)
+external fun wasm_i32_trunc_f64_s(a: Double): Int
+
+@WasmInstruction(WasmInstruction.I32_TRUNC_F64_U)
+external fun wasm_i32_trunc_f64_u(a: Double): Int
+
+@WasmInstruction(WasmInstruction.I64_EXTEND_I32_S)
+external fun wasm_i64_extend_i32_s(a: Int): Long
+
+@WasmInstruction(WasmInstruction.I64_EXTEND_I32_U)
+external fun wasm_i64_extend_i32_u(a: Int): Long
+
+@WasmInstruction(WasmInstruction.I64_TRUNC_F32_S)
+external fun wasm_i64_trunc_f32_s(a: Float): Long
+
+@WasmInstruction(WasmInstruction.I64_TRUNC_F32_U)
+external fun wasm_i64_trunc_f32_u(a: Float): Long
+
+@WasmInstruction(WasmInstruction.I64_TRUNC_F64_S)
+external fun wasm_i64_trunc_f64_s(a: Double): Long
+
+@WasmInstruction(WasmInstruction.I64_TRUNC_F64_U)
+external fun wasm_i64_trunc_f64_u(a: Double): Long
+
+@WasmInstruction(WasmInstruction.F32_CONVERT_I32_S)
+external fun wasm_f32_convert_i32_s(a: Int): Float
+
+@WasmInstruction(WasmInstruction.F32_CONVERT_I32_U)
+external fun wasm_f32_convert_i32_u(a: Int): Float
+
+@WasmInstruction(WasmInstruction.F32_CONVERT_I64_S)
+external fun wasm_f32_convert_i64_s(a: Long): Float
+
+@WasmInstruction(WasmInstruction.F32_CONVERT_I64_U)
+external fun wasm_f32_convert_i64_u(a: Long): Float
+
+@WasmInstruction(WasmInstruction.F32_DEMOTE_F64)
+external fun wasm_f32_demote_f64(a: Double): Float
+
+@WasmInstruction(WasmInstruction.F64_CONVERT_I32_S)
+external fun wasm_f64_convert_i32_s(a: Int): Double
+
+@WasmInstruction(WasmInstruction.F64_CONVERT_I32_U)
+external fun wasm_f64_convert_i32_u(a: Int): Double
+
+@WasmInstruction(WasmInstruction.F64_CONVERT_I64_S)
+external fun wasm_f64_convert_i64_s(a: Long): Double
+
+@WasmInstruction(WasmInstruction.F64_CONVERT_I64_U)
+external fun wasm_f64_convert_i64_u(a: Long): Double
+
+@WasmInstruction(WasmInstruction.F64_PROMOTE_F32)
+external fun wasm_f64_promote_f32(a: Float): Double
+
+@WasmInstruction(WasmInstruction.I32_REINTERPRET_F32)
+external fun wasm_i32_reinterpret_f32(a: Float): Int
+
+@WasmInstruction(WasmInstruction.I64_REINTERPRET_F64)
+external fun wasm_i64_reinterpret_f64(a: Double): Long
+
+@WasmInstruction(WasmInstruction.F32_REINTERPRET_I32)
+external fun wasm_f32_reinterpret_i32(a: Int): Float
+
+@WasmInstruction(WasmInstruction.F32_CONST_NAN)
+external fun wasm_f32_const_nan(): Float
+
+@WasmInstruction(WasmInstruction.F32_CONST_PLUS_INF)
+external fun wasm_f32_const_plus_inf(): Float
+
+@WasmInstruction(WasmInstruction.F32_CONST_MINUS_INF)
+external fun wasm_f32_const_minus_inf(): Float
+
+@WasmInstruction(WasmInstruction.F64_CONST_NAN)
+external fun wasm_f64_const_nan(): Double
+
+@WasmInstruction(WasmInstruction.F64_CONST_PLUS_INF)
+external fun wasm_f64_const_plus_inf(): Float
+
+@WasmInstruction(WasmInstruction.F64_CONST_MINUS_INF)
+external fun wasm_f64_const_minus_inf(): Float
+
diff --git a/libraries/stdlib/wasm/internal/WasmMath.kt b/libraries/stdlib/wasm/internal/WasmMath.kt
new file mode 100644
index 00000000000..bfe5e1681e4
--- /dev/null
+++ b/libraries/stdlib/wasm/internal/WasmMath.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.wasm.internal
+
+// `compareTo(x, y)` implemented as `(x >= y) - (x <= y)`
+
+fun wasm_i32_compareTo(x: Int, y: Int): Int =
+ wasm_i32_ge_s(x, y) - wasm_i32_le_s(x, y)
+
+fun wasm_i64_compareTo(x: Long, y: Long): Int =
+ wasm_i64_ge_s(x, y) - wasm_i64_le_s(x, y)
+
+fun wasm_f32_compareTo(x: Float, y: Float): Int =
+ wasm_f32_ge(x, y) - wasm_f32_le(x, y)
+
+fun wasm_f64_compareTo(x: Double, y: Double): Int =
+ wasm_f64_ge(x, y) - wasm_f64_le(x, y)
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/runtime/runtime.js b/libraries/stdlib/wasm/runtime/runtime.js
new file mode 100644
index 00000000000..453739330c5
--- /dev/null
+++ b/libraries/stdlib/wasm/runtime/runtime.js
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+const runtime = {
+ /**
+ * kotlin.String#plus(other: Any?): String
+ * @return {string}
+ */
+ String_plus(str1, str2) {
+ if (typeof str1 != "string") throw `Illegal argument str1: ${str1}`;
+ return str1 + String(str2);
+ },
+
+ /**
+ * @return {number}
+ */
+ String_getLength(str) {
+ if (typeof str != "string") throw `Illegal argument x: ${str}`;
+ return str.length;
+ },
+
+ /**
+ * @return {number}
+ */
+ String_getChar(str, index) {
+ if (typeof str != "string") throw `Illegal argument str: ${str}`;
+ if (typeof index != "number") throw `Illegal argument index: ${index}`;
+ return str.charCodeAt(index);
+ },
+
+ /**
+ * @return {number}
+ */
+ String_compareTo(str1, str2) {
+ if (str1 > str2) return 1;
+ if (str1 < str2) return -1;
+ return 0;
+ },
+
+ String_getLiteral(index) {
+ return runtime.stringLiterals[index];
+ }
+};
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/runtime/runtime.kt b/libraries/stdlib/wasm/runtime/runtime.kt
new file mode 100644
index 00000000000..a77b3ef53d2
--- /dev/null
+++ b/libraries/stdlib/wasm/runtime/runtime.kt
@@ -0,0 +1,10 @@
+/*
+ * 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.wasm.internal
+
+@WasmImport("runtime", "String_getLiteral")
+public fun stringLiteral(index: Int): String =
+ implementedAsIntrinsic
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/stubsKotlinRanges.kt b/libraries/stdlib/wasm/stubsKotlinRanges.kt
index 46e668b6826..f7d0dc85568 100644
--- a/libraries/stdlib/wasm/stubsKotlinRanges.kt
+++ b/libraries/stdlib/wasm/stubsKotlinRanges.kt
@@ -1,4 +1,4 @@
-@file:ExcludedFromCodegen
+@file:kotlin.wasm.internal.ExcludedFromCodegen
package kotlin.ranges
diff --git a/libraries/stdlib/wasm/testHelpers.kt b/libraries/stdlib/wasm/testHelpers.kt
new file mode 100644
index 00000000000..1f47007a791
--- /dev/null
+++ b/libraries/stdlib/wasm/testHelpers.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.wasm_unreachable
+
+fun assertEquals(x: Boolean, y: Boolean) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Byte, y: Byte) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Short, y: Short) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Char, y: Char) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Int, y: Int) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Long, y: Long) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Float, y: Float) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Double, y: Double) {
+ if (x != y) wasm_unreachable()
+}
+
+
+fun assertEquals(x: Boolean, y: Boolean, s: String) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Byte, y: Byte, s: String) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Short, y: Short, s: String) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Char, y: Char, s: String) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Int, y: Int, s: String) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Long, y: Long, s: String) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Float, y: Float, s: String) {
+ if (x != y) wasm_unreachable()
+}
+fun assertEquals(x: Double, y: Double, s: String) {
+ if (x != y) wasm_unreachable()
+}
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/wasmAnnotations.kt b/libraries/stdlib/wasm/wasmAnnotations.kt
new file mode 100644
index 00000000000..c8f88a2851a
--- /dev/null
+++ b/libraries/stdlib/wasm/wasmAnnotations.kt
@@ -0,0 +1,173 @@
+/*
+ * 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.wasm.internal
+
+import kotlin.annotation.AnnotationTarget.*
+
+// Exclude declaration or file from lowerings and code generation
+@Target(FILE, CLASS, FUNCTION, PROPERTY)
+@Retention(AnnotationRetention.BINARY)
+internal annotation class ExcludedFromCodegen
+
+@ExcludedFromCodegen
+@Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
+@Retention(AnnotationRetention.BINARY)
+internal annotation class WasmImport(val module: String, val name: String)
+
+/**
+ * Replace calls to this functions with specified Wasm instruction.
+ *
+ * Operands are passed in the following order:
+ * 1. Dispatch receiver (if present)
+ * 2. Extension receiver (if present)
+ * 3. Value arguments
+ *
+ * @mnemonic parameter is an instruction WAT name: "i32.add", "f64.trunc", etc.
+ *
+ * Immediate arguments (label, index, offest, align, etc.) are not supported yet.
+ */
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.BINARY)
+@ExcludedFromCodegen
+internal annotation class WasmInstruction(val mnemonic: String) {
+ companion object {
+ const val NOP = "nop"
+ const val UNREACHABLE = "unreachable"
+ const val I32_EQZ = "i32.eqz"
+ const val I32_EQ = "i32.eq"
+ const val I32_NE = "i32.ne"
+ const val I32_LT_S = "i32.lt_s"
+ const val I32_LT_U = "i32.lt_u"
+ const val I32_GT_S = "i32.gt_s"
+ const val I32_GT_U = "i32.gt_u"
+ const val I32_LE_S = "i32.le_s"
+ const val I32_LE_U = "i32.le_u"
+ const val I32_GE_S = "i32.ge_s"
+ const val I32_GE_U = "i32.ge_u"
+ const val I64_EQZ = "i64.eqz"
+ const val I64_EQ = "i64.eq"
+ const val I64_NE = "i64.ne"
+ const val I64_LT_S = "i64.lt_s"
+ const val I64_LT_U = "i64.lt_u"
+ const val I64_GT_S = "i64.gt_s"
+ const val I64_GT_U = "i64.gt_u"
+ const val I64_LE_S = "i64.le_s"
+ const val I64_LE_U = "i64.le_u"
+ const val I64_GE_S = "i64.ge_s"
+ const val I64_GE_U = "i64.ge_u"
+ const val F32_EQ = "f32.eq"
+ const val F32_NE = "f32.ne"
+ const val F32_LT = "f32.lt"
+ const val F32_GT = "f32.gt"
+ const val F32_LE = "f32.le"
+ const val F32_GE = "f32.ge"
+ const val F64_EQ = "f64.eq"
+ const val F64_NE = "f64.ne"
+ const val F64_LT = "f64.lt"
+ const val F64_GT = "f64.gt"
+ const val F64_LE = "f64.le"
+ const val F64_GE = "f64.ge"
+ const val I32_CLZ = "i32.clz"
+ const val I32_CTZ = "i32.ctz"
+ const val I32_POPCNT = "i32.popcnt"
+ const val I32_ADD = "i32.add"
+ const val I32_SUB = "i32.sub"
+ const val I32_MUL = "i32.mul"
+ const val I32_DIV_S = "i32.div_s"
+ const val I32_DIV_U = "i32.div_u"
+ const val I32_REM_S = "i32.rem_s"
+ const val I32_REM_U = "i32.rem_u"
+ const val I32_AND = "i32.and"
+ const val I32_OR = "i32.or"
+ const val I32_XOR = "i32.xor"
+ const val I32_SHL = "i32.shl"
+ const val I32_SHR_S = "i32.shr_s"
+ const val I32_SHR_U = "i32.shr_u"
+ const val I32_ROTL = "i32.rotl"
+ const val I32_ROTR = "i32.rotr"
+ const val I64_CLZ = "i64.clz"
+ const val I64_CTZ = "i64.ctz"
+ const val I64_POPCNT = "i64.popcnt"
+ const val I64_ADD = "i64.add"
+ const val I64_SUB = "i64.sub"
+ const val I64_MUL = "i64.mul"
+ const val I64_DIV_S = "i64.div_s"
+ const val I64_DIV_U = "i64.div_u"
+ const val I64_REM_S = "i64.rem_s"
+ const val I64_REM_U = "i64.rem_u"
+ const val I64_AND = "i64.and"
+ const val I64_OR = "i64.or"
+ const val I64_XOR = "i64.xor"
+ const val I64_SHL = "i64.shl"
+ const val I64_SHR_S = "i64.shr_s"
+ const val I64_SHR_U = "i64.shr_u"
+ const val I64_ROTL = "i64.rotl"
+ const val I64_ROTR = "i64.rotr"
+ const val F32_ABS = "f32.abs"
+ const val F32_NEG = "f32.neg"
+ const val F32_CEIL = "f32.ceil"
+ const val F32_FLOOR = "f32.floor"
+ const val F32_TRUNC = "f32.trunc"
+ const val F32_NEAREST = "f32.nearest"
+ const val F32_SQRT = "f32.sqrt"
+ const val F32_ADD = "f32.add"
+ const val F32_SUB = "f32.sub"
+ const val F32_MUL = "f32.mul"
+ const val F32_DIV = "f32.div"
+ const val F32_FMIN = "f32.fmin"
+ const val F32_FMAX = "f32.fmax"
+ const val F32_COPYSIGN = "f32.copysign"
+ const val F64_ABS = "f64.abs"
+ const val F64_NEG = "f64.neg"
+ const val F64_CEIL = "f64.ceil"
+ const val F64_FLOOR = "f64.floor"
+ const val F64_TRUNC = "f64.trunc"
+ const val F64_NEAREST = "f64.nearest"
+ const val F64_SQRT = "f64.sqrt"
+ const val F64_ADD = "f64.add"
+ const val F64_SUB = "f64.sub"
+ const val F64_MUL = "f64.mul"
+ const val F64_DIV = "f64.div"
+ const val F64_FMIN = "f64.fmin"
+ const val F64_FMAX = "f64.fmax"
+ const val F64_COPYSIGN = "f64.copysign"
+ const val I32_WRAP_I64 = "i32.wrap/i64"
+ const val I32_TRUNC_F32_S = "i32.trunc_s/f32"
+ const val I32_TRUNC_F32_U = "i32.trunc_u/f32"
+ const val I32_TRUNC_F64_S = "i32.trunc_s/f64"
+ const val I32_TRUNC_F64_U = "i32.trunc_u/f64"
+ const val I64_EXTEND_I32_S = "i64.extend_s/i32"
+ const val I64_EXTEND_I32_U = "i64.extend_u/i32"
+ const val I64_TRUNC_F32_S = "i64.trunc_s/f32"
+ const val I64_TRUNC_F32_U = "i64.trunc_u/f32"
+ const val I64_TRUNC_F64_S = "i64.trunc_s/f64"
+ const val I64_TRUNC_F64_U = "i64.trunc_u/f64"
+ const val F32_CONVERT_I32_S = "f32.convert_s/i32"
+ const val F32_CONVERT_I32_U = "f32.convert_u/i32"
+ const val F32_CONVERT_I64_S = "f32.convert_s/i64"
+ const val F32_CONVERT_I64_U = "f32.convert_u/i64"
+ const val F64_CONVERT_I32_S = "f64.convert_s/i32"
+ const val F64_CONVERT_I32_U = "f64.convert_u/i32"
+ const val F64_CONVERT_I64_S = "f64.convert_s/i64"
+ const val F64_CONVERT_I64_U = "f64.convert_u/i64"
+ const val F32_DEMOTE_F64 = "f32.demote/f64"
+ const val F64_PROMOTE_F32 = "f64.promote/f32"
+ const val I32_REINTERPRET_F32 = "i32.reinterpret/f32"
+ const val I64_REINTERPRET_F64 = "i64.reinterpret/f64"
+ const val F32_REINTERPRET_I32 = "f32.reinterpret/i32"
+
+ const val F32_CONST_NAN = "f32.const nan"
+ const val F64_CONST_NAN = "f64.const nan"
+ const val F32_CONST_PLUS_INF = "f32.const +inf"
+ const val F32_CONST_MINUS_INF = "f32.const -inf"
+ const val F64_CONST_PLUS_INF = "f64.const +inf"
+ const val F64_CONST_MINUS_INF = "f64.const -inf"
+ }
+}
+
+@ExcludedFromCodegen
+internal val implementedAsIntrinsic: Nothing
+ get() = null!!
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index e45928b4df7..bed22d493c6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -57,6 +57,7 @@ include ":kotlin-build-common",
":compiler:ir.serialization.common",
":compiler:ir.serialization.js",
":compiler:backend.js",
+ ":compiler:backend.wasm",
":compiler:backend.jvm",
":compiler:backend-common",
":compiler:backend",
@@ -323,6 +324,7 @@ project(':compiler:ir.psi2ir').projectDir = "$rootDir/compiler/ir/ir.psi2ir" as
project(':compiler:ir.ir2cfg').projectDir = "$rootDir/compiler/ir/ir.ir2cfg" as File
project(':compiler:ir.backend.common').projectDir = "$rootDir/compiler/ir/backend.common" as File
project(':compiler:backend.js').projectDir = "$rootDir/compiler/ir/backend.js" as File
+project(':compiler:backend.wasm').projectDir = "$rootDir/compiler/ir/backend.wasm" as File
project(':compiler:backend.jvm').projectDir = "$rootDir/compiler/ir/backend.jvm" as File
project(':compiler:ir.serialization.common').projectDir = "$rootDir/compiler/ir/serialization.common" as File
project(':compiler:ir.serialization.js').projectDir = "$rootDir/compiler/ir/serialization.js" as File