From 6e6ffa12a6893b8078986cd3b16c08f41ebb4809 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Wed, 7 Aug 2019 14:27:18 +0300 Subject: [PATCH] [WASM] Initial infrastructure - New module ":compiler:backend.wasm" - Initial compiler infra (driver, phaser, context) - Subset of Wasm AST - Skeleton of IR -> Wasm AST - Wasm AST -> WAT transformer - Testing infra - SpiderMonkey jsshell tool --- .idea/dictionaries/skuzmich.xml | 9 + .idea/misc.xml | 22 +- build.gradle.kts | 7 +- .../kotlin/ir/backend/js/compiler.kt | 2 +- .../ir/backend/js/utils/AnnotationUtils.kt | 2 +- .../kotlin/ir/backend/js/utils/NameTables.kt | 8 +- compiler/ir/backend.wasm/build.gradle.kts | 26 + .../kotlin/backend/wasm/WasmBackendContext.kt | 91 + .../kotlin/backend/wasm/WasmLoweringPhases.kt | 414 +++++ .../kotlin/backend/wasm/WasmSymbols.kt | 121 ++ .../kotlin/backend/wasm/ast/WasmAstToWat.kt | 64 + .../backend/wasm/ast/WasmDeclarations.kt | 55 + .../backend/wasm/ast/WasmInstructions.kt | 65 + .../kotlin/backend/wasm/ast/WasmTypes.kt | 15 + .../backend/wasm/codegen/BaseTransformer.kt | 16 + .../wasm/codegen/DeclarationTransformer.kt | 123 ++ .../wasm/codegen/ExpressionTransformer.kt | 206 +++ .../backend/wasm/codegen/ModuleTransformer.kt | 82 + .../kotlin/backend/wasm/codegen/NameTable.kt | 64 + .../wasm/codegen/StatementTransformer.kt | 35 + .../backend/wasm/codegen/TypeTransformer.kt | 27 + .../wasm/codegen/WasmCodegenContext.kt | 29 + .../jetbrains/kotlin/backend/wasm/compiler.kt | 65 + .../wasm/lower/BlockDecomposerLowering.kt | 14 + .../backend/wasm/lower/BuiltInsLowering.kt | 48 + .../lower/ExcludeDeclarationsFromCodegen.kt | 124 ++ .../kotlin/backend/wasm/utils/Annotations.kt | 29 + compiler/ir/serialization.js/build.gradle.kts | 4 +- .../jetbrains/kotlin/test/TargetBackend.kt | 3 +- js/js.tests/build.gradle.kts | 77 +- .../generators/tests/GenerateJsTests.kt | 9 + .../kotlin/js/test/BasicWasmBoxTest.kt | 194 ++ .../kotlin/js/test/engines/SpiderMonkey.kt | 44 + .../semantics/IrWasmBoxJsTestGenerated.java | 548 ++++++ .../abstractClassesForGeneratedIrTests.kt | 5 + .../semantics/IrWasmBoxWasmTestGenerated.java | 553 ++++++ .../abstractClassesForGeneratedWasmTests.kt | 16 + .../testData/wasmBox/basicTypes.kt | 44 + .../wasmBox/number/assignmentIntOverflow.kt | 26 + .../wasmBox/number/byteAndShortConversions.kt | 46 + .../number/conversionsWithTruncation.kt | 51 + .../number/conversionsWithoutTruncation.kt | 81 + .../testData/wasmBox/number/division.kt | 45 + .../wasmBox/number/doubleConversions.kt | 77 + .../testData/wasmBox/number/hashCode.kt | 23 + .../wasmBox/number/hexadecimalConstant.kt | 7 + .../wasmBox/number/incDecOptimization.kt | 21 + .../testData/wasmBox/number/intConversions.kt | 29 + .../testData/wasmBox/number/intDivFloat.kt | 20 + .../wasmBox/number/intIncDecOverflow.kt | 25 + .../testData/wasmBox/number/intOverflow.kt | 35 + .../testData/wasmBox/number/kt2342.kt | 20 + .../wasmBox/number/longBinaryOperations.kt | 57 + .../wasmBox/number/longBitOperations.kt | 24 + .../wasmBox/number/longCompareToIntrinsic.kt | 41 + .../wasmBox/number/longEqualsIntrinsic.kt | 45 + .../testData/wasmBox/number/longHashCode.kt | 18 + .../wasmBox/number/longUnaryOperations.kt | 32 + .../wasmBox/number/mixedTypesOverflow.kt | 34 + .../wasmBox/number/numberCompareTo.kt | 127 ++ .../wasmBox/number/numberConversions.kt | 91 + .../testData/wasmBox/number/numberEquals.kt | 55 + .../testData/wasmBox/number/numberIncDec.kt | 17 + .../explicitEqualsOnDouble.kt | 7 + .../passedCommonTests/classes/kt2482.kt | 9 + .../passedCommonTests/constants/float.kt | 18 + .../passedCommonTests/constants/long.kt | 10 + .../controlStructures/ifConst1.kt | 19 + .../controlStructures/ifConst2.kt | 19 + .../controlStructures/kt1899.kt | 5 + .../extensionProperties/topLevel.kt | 6 + .../passedCommonTests/functions/kt2280.kt | 7 + .../lessDouble_properIeeeAndNewInference.kt | 8 + .../closureConversion/closureConversion1.kt | 6 + .../closureConversion/closureConversion3.kt | 11 + .../closureConversion/closureConversion4.kt | 6 + .../labels/propertyAccessor.kt | 11 + .../optimizations/negateConstantCompare.kt | 7 + .../annotatedAssignment.kt | 14 + .../infixFunctionOverBuiltinMember.kt | 18 + .../primitiveTypes/ea35963.kt | 6 + .../primitiveTypes/incrementByteCharShort.kt | 22 + .../primitiveTypes/kt1634.kt | 4 + .../primitiveTypes/kt3078.kt | 7 + .../primitiveTypes/kt6590_identityEquals.kt | 15 + .../passedCommonTests/primitiveTypes/kt737.kt | 5 + .../passedCommonTests/primitiveTypes/kt828.kt | 15 + .../passedCommonTests/primitiveTypes/kt877.kt | 9 + .../publishedApi/topLevel.kt | 10 + .../passedCommonTests/unaryOp/intrinsic.kt | 17 + .../passedCommonTests/when/noElseNoMatch.kt | 8 + .../testData/wasmBox/primitivesOperatos.kt | 4 + libraries/stdlib/wasm/annotations.kt | 12 - .../wasm/builtins/native/kotlin/Boolean.kt | 13 +- .../wasm/builtins/native/kotlin/Char.kt | 56 +- .../wasm/builtins/native/kotlin/Library.kt | 2 +- .../wasm/builtins/native/kotlin/Primitives.kt | 1582 +++++++++++------ .../wasm/builtins/native/kotlin/String.kt | 19 +- .../stdlib/wasm/internal/WasmInstructions.kt | 397 +++++ libraries/stdlib/wasm/internal/WasmMath.kt | 20 + libraries/stdlib/wasm/runtime/runtime.js | 45 + libraries/stdlib/wasm/runtime/runtime.kt | 10 + libraries/stdlib/wasm/stubsKotlinRanges.kt | 2 +- libraries/stdlib/wasm/testHelpers.kt | 59 + libraries/stdlib/wasm/wasmAnnotations.kt | 173 ++ settings.gradle | 2 + 106 files changed, 6418 insertions(+), 584 deletions(-) create mode 100644 .idea/dictionaries/skuzmich.xml create mode 100644 compiler/ir/backend.wasm/build.gradle.kts create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmAstToWat.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmDeclarations.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmInstructions.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ast/WasmTypes.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/BaseTransformer.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/DeclarationTransformer.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/ExpressionTransformer.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/ModuleTransformer.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/NameTable.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/StatementTransformer.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/TypeTransformer.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/codegen/WasmCodegenContext.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BlockDecomposerLowering.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ExcludeDeclarationsFromCodegen.kt create mode 100644 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/Annotations.kt create mode 100644 js/js.tests/test/org/jetbrains/kotlin/js/test/BasicWasmBoxTest.kt create mode 100644 js/js.tests/test/org/jetbrains/kotlin/js/test/engines/SpiderMonkey.kt create mode 100644 js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrWasmBoxJsTestGenerated.java create mode 100644 js/js.tests/test/org/jetbrains/kotlin/js/test/wasm/semantics/IrWasmBoxWasmTestGenerated.java create mode 100644 js/js.tests/test/org/jetbrains/kotlin/js/test/wasm/semantics/abstractClassesForGeneratedWasmTests.kt create mode 100644 js/js.translator/testData/wasmBox/basicTypes.kt create mode 100644 js/js.translator/testData/wasmBox/number/assignmentIntOverflow.kt create mode 100644 js/js.translator/testData/wasmBox/number/byteAndShortConversions.kt create mode 100644 js/js.translator/testData/wasmBox/number/conversionsWithTruncation.kt create mode 100644 js/js.translator/testData/wasmBox/number/conversionsWithoutTruncation.kt create mode 100644 js/js.translator/testData/wasmBox/number/division.kt create mode 100644 js/js.translator/testData/wasmBox/number/doubleConversions.kt create mode 100644 js/js.translator/testData/wasmBox/number/hashCode.kt create mode 100644 js/js.translator/testData/wasmBox/number/hexadecimalConstant.kt create mode 100644 js/js.translator/testData/wasmBox/number/incDecOptimization.kt create mode 100644 js/js.translator/testData/wasmBox/number/intConversions.kt create mode 100644 js/js.translator/testData/wasmBox/number/intDivFloat.kt create mode 100644 js/js.translator/testData/wasmBox/number/intIncDecOverflow.kt create mode 100644 js/js.translator/testData/wasmBox/number/intOverflow.kt create mode 100644 js/js.translator/testData/wasmBox/number/kt2342.kt create mode 100644 js/js.translator/testData/wasmBox/number/longBinaryOperations.kt create mode 100644 js/js.translator/testData/wasmBox/number/longBitOperations.kt create mode 100644 js/js.translator/testData/wasmBox/number/longCompareToIntrinsic.kt create mode 100644 js/js.translator/testData/wasmBox/number/longEqualsIntrinsic.kt create mode 100644 js/js.translator/testData/wasmBox/number/longHashCode.kt create mode 100644 js/js.translator/testData/wasmBox/number/longUnaryOperations.kt create mode 100644 js/js.translator/testData/wasmBox/number/mixedTypesOverflow.kt create mode 100644 js/js.translator/testData/wasmBox/number/numberCompareTo.kt create mode 100644 js/js.translator/testData/wasmBox/number/numberConversions.kt create mode 100644 js/js.translator/testData/wasmBox/number/numberEquals.kt create mode 100644 js/js.translator/testData/wasmBox/number/numberIncDec.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/boxingOptimization/explicitEqualsOnDouble.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/classes/kt2482.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/constants/float.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/constants/long.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst1.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/ifConst2.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/controlStructures/kt1899.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/extensionProperties/topLevel.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/functions/kt2280.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/ieee754/lessDouble_properIeeeAndNewInference.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion1.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion3.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/ir/closureConversion/closureConversion4.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/labels/propertyAccessor.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/lazyCodegen/optimizations/negateConstantCompare.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/annotatedAssignment.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/operatorConventions/infixFunctionOverBuiltinMember.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/ea35963.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/incrementByteCharShort.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt1634.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt3078.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt6590_identityEquals.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt737.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt828.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/primitiveTypes/kt877.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/publishedApi/topLevel.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/unaryOp/intrinsic.kt create mode 100644 js/js.translator/testData/wasmBox/passedCommonTests/when/noElseNoMatch.kt create mode 100644 js/js.translator/testData/wasmBox/primitivesOperatos.kt delete mode 100644 libraries/stdlib/wasm/annotations.kt create mode 100644 libraries/stdlib/wasm/internal/WasmInstructions.kt create mode 100644 libraries/stdlib/wasm/internal/WasmMath.kt create mode 100644 libraries/stdlib/wasm/runtime/runtime.js create mode 100644 libraries/stdlib/wasm/runtime/runtime.kt create mode 100644 libraries/stdlib/wasm/testHelpers.kt create mode 100644 libraries/stdlib/wasm/wasmAnnotations.kt 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