Initial .wasm file generation for the wasm32 target.
Some basic launcher.js and runtime.
This commit is contained in:
committed by
alexander-gorshenev
parent
9ec5b24832
commit
b4660d03a1
+57
-15
@@ -37,17 +37,17 @@ internal abstract class PlatformFlags(val properties: KonanProperties) {
|
||||
val linkerKonanFlags = properties.linkerKonanFlags
|
||||
val linkerDebugFlags = properties.linkerDebugFlags
|
||||
val llvmDebugOptFlags = properties.llvmDebugOptFlags
|
||||
val s2wasmFlags = properties.s2wasmFlags
|
||||
val targetToolchain = properties.absoluteTargetToolchain
|
||||
val targetSysRoot = properties.absoluteTargetSysRoot
|
||||
|
||||
val targetLibffi = properties.libffiDir ?.let { listOf("${properties.absoluteLibffiDir}/lib/libffi.a") } ?: emptyList()
|
||||
|
||||
open val useCompilerDriverAsLinker: Boolean get() = false // TODO: refactor.
|
||||
|
||||
abstract fun linkCommand(objectFiles: List<ObjectFile>,
|
||||
abstract fun linkCommand(objectFiles: List<ObjectFile>,
|
||||
executable: ExecutableFile, optimize: Boolean, debug: Boolean): List<String>
|
||||
|
||||
val targetLibffiDir = properties.absoluteLibffiDir
|
||||
val targetLibffi = "$targetLibffiDir/lib/libffi.a"
|
||||
val targetToolchain = properties.absoluteTargetToolchain
|
||||
val targetSysRoot = properties.absoluteTargetSysRoot
|
||||
|
||||
open fun linkCommandSuffix(): List<String> = emptyList()
|
||||
|
||||
protected fun propertyTargetString(name: String)
|
||||
@@ -178,19 +178,19 @@ internal open class WasmPlatform(distribution: Distribution)
|
||||
|
||||
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean): List<String> {
|
||||
|
||||
return mutableListOf(clang).apply{
|
||||
throw Error("Implement me!")
|
||||
}
|
||||
//No link stage for WASM yet, just give '.wasm' as output.
|
||||
return mutableListOf("/bin/cp", objectFiles.single(), executable)
|
||||
}
|
||||
}
|
||||
|
||||
internal class LinkStage(val context: Context) {
|
||||
|
||||
val config = context.config.configuration
|
||||
val target = context.config.targetManager.target
|
||||
|
||||
private val distribution = context.config.distribution
|
||||
|
||||
private val platform = when (context.config.targetManager.target) {
|
||||
private val platform = when (target) {
|
||||
KonanTarget.LINUX, KonanTarget.RASPBERRYPI ->
|
||||
LinuxBasedPlatform(distribution)
|
||||
KonanTarget.MACBOOK, KonanTarget.IPHONE, KonanTarget.IPHONE_SIM ->
|
||||
@@ -202,7 +202,7 @@ internal class LinkStage(val context: Context) {
|
||||
KonanTarget.WASM32 ->
|
||||
WasmPlatform(distribution)
|
||||
else ->
|
||||
error("Unexpected target platform: ${context.config.targetManager.target}")
|
||||
error("Unexpected target platform: ${target}")
|
||||
}
|
||||
|
||||
private val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false
|
||||
@@ -216,9 +216,7 @@ internal class LinkStage(val context: Context) {
|
||||
}
|
||||
|
||||
private fun llvmLto(files: List<BitcodeFile>): ObjectFile {
|
||||
val tmpCombined = createTempFile("combined", ".o")
|
||||
tmpCombined.deleteOnExit()
|
||||
val combined = tmpCombined.absolutePath
|
||||
val combined = temporary("combined", ".o")
|
||||
|
||||
val tool = distribution.llvmLto
|
||||
val command = mutableListOf(tool, "-o", combined)
|
||||
@@ -234,6 +232,41 @@ internal class LinkStage(val context: Context) {
|
||||
return combined
|
||||
}
|
||||
|
||||
private fun temporary(name: String, suffix: String): String {
|
||||
val temporaryFile = createTempFile(name, suffix)
|
||||
temporaryFile.deleteOnExit()
|
||||
return temporaryFile.absolutePath
|
||||
}
|
||||
|
||||
private fun targetTool(tool: String, vararg arg: String) {
|
||||
val absoluteToolName = "${platform.targetToolchain}/bin/$tool"
|
||||
runTool(absoluteToolName, *arg)
|
||||
}
|
||||
|
||||
private fun hostLlvmTool(tool: String, args: List<String>) {
|
||||
val absoluteToolName = "${distribution.llvmBin}/$tool"
|
||||
val command = listOf(absoluteToolName) + args
|
||||
runTool(*command.toTypedArray())
|
||||
}
|
||||
|
||||
private fun bitcodeToWasm(bitcodeFiles: List<BitcodeFile>): String {
|
||||
val combinedBc = temporary("combined", ".bc")
|
||||
hostLlvmTool("llvm-link", bitcodeFiles + listOf("-o", combinedBc))
|
||||
|
||||
val combinedS = temporary("combined", ".s")
|
||||
targetTool("llc", combinedBc, "-o", combinedS)
|
||||
|
||||
val s2wasmFlags = platform.s2wasmFlags.toTypedArray()
|
||||
val combinedWast = temporary( "combined", ".wast")
|
||||
targetTool("s2wasm", combinedS, "-o", combinedWast, *s2wasmFlags)
|
||||
|
||||
val combinedWasm = temporary( "combined", ".wasm")
|
||||
val combinedSmap = temporary( "combined", ".smap")
|
||||
targetTool("wasm-as", combinedWast, "-o", combinedWasm, "-g", "-s", combinedSmap)
|
||||
|
||||
return combinedWasm
|
||||
}
|
||||
|
||||
private fun asLinkerArgs(args: List<String>): List<String> {
|
||||
if (platform.useCompilerDriverAsLinker) {
|
||||
return args
|
||||
@@ -261,8 +294,12 @@ internal class LinkStage(val context: Context) {
|
||||
private val entryPointSelector: List<String>
|
||||
get() = if (nomain) emptyList() else platform.entrySelector
|
||||
|
||||
private val libffi
|
||||
get() = platform.targetLibffi ?.let { listOf(it) } ?: emptyList()
|
||||
|
||||
private fun link(objectFiles: List<ObjectFile>, libraryProvidedLinkerFlags: List<String>): ExecutableFile {
|
||||
val executable = context.config.outputFile
|
||||
|
||||
val linkCommand = platform.linkCommand(objectFiles, executable, optimize, debug) +
|
||||
platform.targetLibffi +
|
||||
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
|
||||
@@ -333,7 +370,12 @@ internal class LinkStage(val context: Context) {
|
||||
|
||||
val phaser = PhaseManager(context)
|
||||
phaser.phase(KonanPhase.OBJECT_FILES) {
|
||||
objectFiles = listOf( llvmLto(bitcodeFiles ) )
|
||||
objectFiles = listOf(
|
||||
if (target == KonanTarget.WASM32)
|
||||
bitcodeToWasm(bitcodeFiles)
|
||||
else
|
||||
llvmLto(bitcodeFiles)
|
||||
)
|
||||
}
|
||||
phaser.phase(KonanPhase.LINKER) {
|
||||
link(objectFiles, libraryProvidedLinkerFlags)
|
||||
|
||||
@@ -218,14 +218,6 @@ dependencies.osx-wasm32 = \
|
||||
target-toolchain-1-osx-wasm
|
||||
|
||||
quadruple.wasm32 = wasm32
|
||||
entrySelector.wasm32 = -Wl,--defsym -Wl,main=Konan_main
|
||||
llvmLtoFlags.wasm32 =
|
||||
targetSysRoot.wasm32 = target-sysroot-1-wasm
|
||||
clangFlags.wasm32 = -O1 -fno-rtti -fno-exceptions \
|
||||
-D_LIBCPP_ABI_VERSION=2 -DKONAN_NO_FFI=1 -DKONAN_NO_THREADS=1 -DKONAN_NO_EXCEPTIONS=1 \
|
||||
-DKONAN_NO_DEBUG_API=1 \
|
||||
-nostdinc -Xclang -nobuiltininc -Xclang -nostdsysteminc \
|
||||
-Xclang -isystem<sysrootDir>/include/libcxx -Xclang -isystem<sysrootDir>/lib/libcxxabi/include \
|
||||
-Xclang -isystem<sysrootDir>/include/compat -Xclang -isystem<sysrootDir>/include/libc
|
||||
linkerKonanFlags.wasm32 = -lc
|
||||
linkerDebugFlags.wasm32 = -Wl,-S
|
||||
s2wasmFlags.wasm32 = --allocate-stack 1024 --import-memory
|
||||
|
||||
@@ -328,6 +328,7 @@ task codegen_controlflow_for_loops_overflow(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task codegen_controlflow_for_loops_errors(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
source = "codegen/controlflow/for_loops_errors.kt"
|
||||
goldValue = "OK\n"
|
||||
}
|
||||
@@ -349,6 +350,7 @@ task codegen_controlflow_for_loops_nested(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task codegen_controlflow_for_loops_coroutines(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
source = "codegen/controlflow/for_loops_coroutines.kt"
|
||||
goldValue = "before: 0 after: 0\n" +
|
||||
"before: 2 after: 2\n" +
|
||||
@@ -376,6 +378,7 @@ task cast_simple(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task cast_null(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
goldValue = "Ok\n"
|
||||
source = "codegen/basics/cast_null.kt"
|
||||
}
|
||||
@@ -392,6 +395,7 @@ task unchecked_cast2(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task unchecked_cast3(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "Ok\n"
|
||||
source = "codegen/basics/unchecked_cast3.kt"
|
||||
}
|
||||
@@ -411,13 +415,13 @@ task hello0(type: RunKonanTest) {
|
||||
|
||||
task hello1(type: RunKonanTest) {
|
||||
goldValue = "Hello World"
|
||||
testData = "Hello World"
|
||||
testData = "Hello World\n"
|
||||
source = "runtime/basic/hello1.kt"
|
||||
}
|
||||
|
||||
task hello2(type: RunKonanTest) {
|
||||
goldValue = "you entered 'Hello World'"
|
||||
testData = "Hello World"
|
||||
testData = "Hello World\n"
|
||||
source = "runtime/basic/hello2.kt"
|
||||
}
|
||||
|
||||
@@ -481,16 +485,19 @@ task empty_substring(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task worker0(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "Got Input processed\nOK\n"
|
||||
source = "runtime/workers/worker0.kt"
|
||||
}
|
||||
|
||||
task worker1(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "OK\n"
|
||||
source = "runtime/workers/worker1.kt"
|
||||
}
|
||||
|
||||
task worker2(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "OK\n"
|
||||
source = "runtime/workers/worker2.kt"
|
||||
}
|
||||
@@ -813,77 +820,92 @@ task classDelegation_withBridge(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task delegatedProperty_simpleVal(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails: not global_ctros support.
|
||||
goldValue = "x\n42\n"
|
||||
source = "codegen/delegatedProperty/simpleVal.kt"
|
||||
}
|
||||
|
||||
task delegatedProperty_simpleVar(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "get x\n42\nset x\nget x\n117\n"
|
||||
source = "codegen/delegatedProperty/simpleVar.kt"
|
||||
}
|
||||
|
||||
task delegatedProperty_packageLevel(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "x\n42\n"
|
||||
source = "codegen/delegatedProperty/packageLevel.kt"
|
||||
}
|
||||
|
||||
task delegatedProperty_local(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "x\n42\n"
|
||||
source = "codegen/delegatedProperty/local.kt"
|
||||
}
|
||||
|
||||
task delegatedProperty_delegatedOverride(type: LinkKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "156\nx\n117\n42\n"
|
||||
source = "codegen/delegatedProperty/delegatedOverride_main.kt"
|
||||
lib = "codegen/delegatedProperty/delegatedOverride_lib.kt"
|
||||
}
|
||||
|
||||
task delegatedProperty_lazy(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "computed!\nHello\nHello\n"
|
||||
source = "codegen/delegatedProperty/lazy.kt"
|
||||
}
|
||||
|
||||
task delegatedProperty_observable(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "<no name> -> first\nfirst -> second\n"
|
||||
source = "codegen/delegatedProperty/observable.kt"
|
||||
}
|
||||
|
||||
task delegatedProperty_map(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "John Doe\n25\n"
|
||||
source = "codegen/delegatedProperty/map.kt"
|
||||
}
|
||||
|
||||
task propertyCallableReference_valClass(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "42\n117\n"
|
||||
source = "codegen/propertyCallableReference/valClass.kt"
|
||||
}
|
||||
|
||||
task propertyCallableReference_valModule(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "42\n"
|
||||
source = "codegen/propertyCallableReference/valModule.kt"
|
||||
}
|
||||
|
||||
task propertyCallableReference_varClass(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // RuntimeError: memory access out of bounds
|
||||
goldValue = "117\n117\n42\n42\n"
|
||||
source = "codegen/propertyCallableReference/varClass.kt"
|
||||
}
|
||||
|
||||
task propertyCallableReference_varModule(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "117\n117\n"
|
||||
source = "codegen/propertyCallableReference/varModule.kt"
|
||||
}
|
||||
|
||||
task propertyCallableReference_valExtension(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "42\n117\n"
|
||||
source = "codegen/propertyCallableReference/valExtension.kt"
|
||||
}
|
||||
|
||||
task propertyCallableReference_varExtension(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "117\n117\n42\n42\n"
|
||||
source = "codegen/propertyCallableReference/varExtension.kt"
|
||||
}
|
||||
|
||||
task propertyCallableReference_linkTest(type: LinkKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "42\n117\n"
|
||||
source = "codegen/propertyCallableReference/linkTest_main.kt"
|
||||
lib = "codegen/propertyCallableReference/linkTest_lib.kt"
|
||||
@@ -900,6 +922,7 @@ task lateinit_initialized(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task lateinit_notInitialized(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails.
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/lateinit/notInitialized.kt"
|
||||
}
|
||||
@@ -910,116 +933,139 @@ task lateinit_inBaseClass(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task coroutines_simple(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "42\n"
|
||||
source = "codegen/coroutines/simple.kt"
|
||||
}
|
||||
|
||||
task coroutines_withReceiver(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "42\n"
|
||||
source = "codegen/coroutines/withReceiver.kt"
|
||||
}
|
||||
|
||||
task coroutines_correctOrder1(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "f1\ns1\nf2\n160\n"
|
||||
source = "codegen/coroutines/correctOrder1.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_if1(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "f1\ns1\nf3\n84\n"
|
||||
source = "codegen/coroutines/controlFlow_if1.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_if2(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "f1\ns1\nf2\n43\n"
|
||||
source = "codegen/coroutines/controlFlow_if2.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_finally1(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "f1\ns1\n117\n"
|
||||
source = "codegen/coroutines/controlFlow_finally1.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_finally2(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "f1\ns1\n117\n"
|
||||
source = "codegen/coroutines/controlFlow_finally2.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_finally3(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "f1\ns1\n117\n"
|
||||
source = "codegen/coroutines/controlFlow_finally3.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_finally4(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s1\nfinally\n42\n"
|
||||
source = "codegen/coroutines/controlFlow_finally4.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_finally5(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s1\nf2\nfinally\n1\n"
|
||||
source = "codegen/coroutines/controlFlow_finally5.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_finally6(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s1\nfinally\nerror\n0\n"
|
||||
source = "codegen/coroutines/controlFlow_finally6.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_finally7(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s1\nf2\nfinally1\ns2\nfinally2\n42\n"
|
||||
source = "codegen/coroutines/controlFlow_finally7.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_inline1(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "42\n"
|
||||
source = "codegen/coroutines/controlFlow_inline1.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_inline2(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s1\n42\n"
|
||||
source = "codegen/coroutines/controlFlow_inline2.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_inline3(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "f1\ns1\n42\n"
|
||||
source = "codegen/coroutines/controlFlow_inline3.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_tryCatch1(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s1\n42\n"
|
||||
source = "codegen/coroutines/controlFlow_tryCatch1.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_tryCatch2(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s1\n42\n"
|
||||
source = "codegen/coroutines/controlFlow_tryCatch2.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_tryCatch3(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s2\nf2\n1\n"
|
||||
source = "codegen/coroutines/controlFlow_tryCatch3.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_tryCatch4(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s2\nf2\n1\n"
|
||||
source = "codegen/coroutines/controlFlow_tryCatch4.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_tryCatch5(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s2\ns1\nError\n42\n"
|
||||
source = "codegen/coroutines/controlFlow_tryCatch5.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_while1(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s3\ns3\ns3\ns3\n3\n"
|
||||
source = "codegen/coroutines/controlFlow_while1.kt"
|
||||
}
|
||||
|
||||
task coroutines_controlFlow_while2(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "s3\ns3\ns3\n3\n"
|
||||
source = "codegen/coroutines/controlFlow_while2.kt"
|
||||
}
|
||||
|
||||
task coroutines_returnsUnit1(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "117\ns1\n0\n"
|
||||
source = "codegen/coroutines/returnsUnit1.kt"
|
||||
}
|
||||
@@ -1030,6 +1076,7 @@ task AbstractMutableCollection(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task BitSet(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
expectedExitStatus = 0
|
||||
source = "runtime/collections/BitSet.kt"
|
||||
}
|
||||
@@ -1223,6 +1270,7 @@ task boxing6(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task boxing7(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
goldValue = "1\n0\n"
|
||||
source = "codegen/boxing/boxing7.kt"
|
||||
}
|
||||
@@ -1283,6 +1331,7 @@ task array_list1(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task hash_map0(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails on wasm32 (remainder by zero)
|
||||
goldValue = "OK\n"
|
||||
source = "runtime/collections/hash_map0.kt"
|
||||
}
|
||||
@@ -1315,6 +1364,7 @@ task moderately_large_array1(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task string_builder0(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails on wasm32.
|
||||
goldValue = "OK\n"
|
||||
source = "runtime/text/string_builder0.kt"
|
||||
}
|
||||
@@ -1344,21 +1394,25 @@ task to_string0(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task chars0(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
source = "runtime/text/chars0.kt"
|
||||
expectedExitStatus = 0
|
||||
}
|
||||
|
||||
task catch1(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
goldValue = "Before\nCaught Throwable\nDone\n"
|
||||
source = "runtime/exceptions/catch1.kt"
|
||||
}
|
||||
|
||||
task catch2(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
goldValue = "Before\nCaught Error\nDone\n"
|
||||
source = "runtime/exceptions/catch2.kt"
|
||||
}
|
||||
|
||||
task catch7(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
goldValue = "Error happens\n"
|
||||
source = "runtime/exceptions/catch7.kt"
|
||||
}
|
||||
@@ -1379,11 +1433,13 @@ task catch4(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task catch5(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
goldValue = "Before\nCaught Error\nDone\n"
|
||||
source = "codegen/try/catch5.kt"
|
||||
}
|
||||
|
||||
task catch6(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
goldValue = "Before\nCaught Error\nDone\n"
|
||||
source = "codegen/try/catch6.kt"
|
||||
}
|
||||
@@ -1646,6 +1702,7 @@ task objectExpression3(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task initializers2(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails on wasm32.
|
||||
goldValue = "init globalValue2\n" +
|
||||
"init globalValue3\n" +
|
||||
"1\n" +
|
||||
@@ -1656,11 +1713,13 @@ task initializers2(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task initializers3(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails on wasm32.
|
||||
goldValue = "42\n"
|
||||
source = "runtime/basic/initializers3.kt"
|
||||
}
|
||||
|
||||
task initializers4(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails on wasm32.
|
||||
goldValue = "1073741824\ntrue\n"
|
||||
source = "runtime/basic/initializers4.kt"
|
||||
}
|
||||
@@ -1671,6 +1730,7 @@ task initializers5(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task expression_as_statement(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // The test fails on wasm32.
|
||||
goldValue = "Ok\n"
|
||||
source = "codegen/basics/expression_as_statement.kt"
|
||||
}
|
||||
@@ -1692,6 +1752,7 @@ task memory_var4(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task memory_throw_cleanup(type: RunKonanTest) {
|
||||
expectedFail = (project.testTarget == 'wasm32') // Uses exceptions.
|
||||
goldValue = "Ok\n"
|
||||
source = "runtime/memory/throw_cleanup.kt"
|
||||
}
|
||||
@@ -1947,18 +2008,21 @@ kotlinNativeInterop {
|
||||
}
|
||||
|
||||
task interop0(type: RunInteropKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
goldValue = "0\n0\n"
|
||||
source = "interop/basics/0.kt"
|
||||
interop = 'sysstat'
|
||||
}
|
||||
|
||||
task interop1(type: RunInteropKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
goldValue = "257\n-1\n-2\n"
|
||||
source = "interop/basics/1.kt"
|
||||
interop = 'cstdlib'
|
||||
}
|
||||
|
||||
task interop2(type: RunInteropKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
goldValue = "Hello\n"
|
||||
source = "interop/basics/2.kt"
|
||||
interop = 'cstdio'
|
||||
@@ -1970,19 +2034,22 @@ task interop3(type: RunInteropKonanTest) {
|
||||
// should be different depending on the bitness of the target.
|
||||
// There are plans to provide a solution and turn this
|
||||
// test back on.
|
||||
disabled = (project.testTarget == 'raspberrypi')
|
||||
disabled = (project.testTarget == 'raspberrypi') ||
|
||||
(project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
goldValue = "8 9 12 13 14 \n"
|
||||
source = "interop/basics/3.kt"
|
||||
interop = 'cstdlib'
|
||||
}
|
||||
|
||||
task interop4(type: RunInteropKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
goldValue = "a b -1 2 3 9223372036854775807 0.1 0.2\n1 42\n"
|
||||
source = "interop/basics/4.kt"
|
||||
interop = 'cstdio'
|
||||
}
|
||||
|
||||
task interop_echo_server(type: RunInteropKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
if (!isMac()) {
|
||||
// Not supported or not tested.
|
||||
disabled = true
|
||||
@@ -1994,6 +2061,7 @@ task interop_echo_server(type: RunInteropKonanTest) {
|
||||
|
||||
if (isMac()) {
|
||||
task interop_opengl_teapot(type: RunInteropKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
run = false
|
||||
source = "interop/basics/opengl_teapot.kt"
|
||||
interop = 'opengl'
|
||||
|
||||
@@ -254,6 +254,11 @@ targetList.each { target ->
|
||||
rename("${target}Start.bc", 'start.bc')
|
||||
into("klib/stdlib/targets/$target/native")
|
||||
}
|
||||
if (target == 'wasm32') {
|
||||
from(project(':runtime').file('src/launcher/js')) {
|
||||
into('konan/nativelib')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,16 @@ import org.gradle.api.tasks.ParallelizableTask
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.process.ExecResult
|
||||
import org.jetbrains.kotlin.konan.target.*
|
||||
import org.jetbrains.kotlin.konan.properties.*
|
||||
|
||||
abstract class KonanTest extends JavaExec {
|
||||
protected String source
|
||||
def targetManager = new TargetManager(project.testTarget)
|
||||
def target = targetManager.target
|
||||
def backendNative = project.project(":backend.native")
|
||||
def runtimeProject = project.project(":runtime")
|
||||
def dist = project.rootProject.file("dist")
|
||||
def dependenciesDir = project.findProject(":dependencies").file("all")
|
||||
def runtimeBc = new File("${dist.canonicalPath}/lib/runtime.bc").absolutePath
|
||||
def launcherBc = new File("${dist.canonicalPath}/lib/launcher.bc").absolutePath
|
||||
def startKtBc = new File("${dist.canonicalPath}/lib/start.kt.bc").absolutePath
|
||||
def stdlibKtBc = new File("${dist.canonicalPath}/lib/stdlib.kt.bc").absolutePath
|
||||
def dependenciesDir = project.rootProject.dependenciesDir
|
||||
def konancDriver = project.isWindows() ? "konanc.bat" : "konanc"
|
||||
def konanc = new File("${dist.canonicalPath}/bin/$konancDriver").absolutePath
|
||||
def mainC = 'main.c'
|
||||
@@ -47,12 +46,17 @@ abstract class KonanTest extends JavaExec {
|
||||
List<String> flags = null
|
||||
|
||||
boolean enabled = true
|
||||
boolean expectedFail = false
|
||||
boolean run = true
|
||||
|
||||
void setDisabled(boolean value) {
|
||||
this.enabled = !value
|
||||
}
|
||||
|
||||
void setExpectedFail(boolean value) {
|
||||
this.expectedFail = value
|
||||
}
|
||||
|
||||
// Uses directory defined in $outputSourceSetName source set.
|
||||
// If such source set doesn't exist, uses temporary directory.
|
||||
void createOutputDirectory() {
|
||||
@@ -102,7 +106,7 @@ abstract class KonanTest extends JavaExec {
|
||||
*moreArgs,
|
||||
*project.globalTestArgs]
|
||||
if (project.testTarget) {
|
||||
args "-target", project.testTarget
|
||||
args "-target", target.userName
|
||||
}
|
||||
if (enableKonanAssertions) {
|
||||
args "-ea"
|
||||
@@ -212,7 +216,6 @@ fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation<Any?> = ob
|
||||
void executeTest() {
|
||||
createOutputDirectory()
|
||||
def program = buildExePath()
|
||||
def targetManager = new TargetManager(project.testTarget)
|
||||
def suffix = targetManager.programSuffix
|
||||
def exe = "$program$suffix"
|
||||
|
||||
@@ -227,7 +230,9 @@ fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation<Any?> = ob
|
||||
def out = new ByteArrayOutputStream()
|
||||
//TODO Add test timeout
|
||||
ExecResult execResult = project.execRemote {
|
||||
commandLine exe
|
||||
|
||||
commandLine executionCommandLine(exe)
|
||||
|
||||
if (arguments != null) {
|
||||
args arguments
|
||||
}
|
||||
@@ -239,15 +244,43 @@ fun handleExceptionContinuation(x: (Throwable) -> Unit): Continuation<Any?> = ob
|
||||
ignoreExitValue = true
|
||||
}
|
||||
def result = out.toString("UTF-8")
|
||||
|
||||
println(result)
|
||||
|
||||
if (execResult.exitValue != expectedExitStatus) {
|
||||
throw new TestFailedException(
|
||||
"Test failed. Expected exit status: $expectedExitStatus, actual: ${execResult.exitValue}")
|
||||
}
|
||||
|
||||
def exitCodeMismatch = execResult.exitValue != expectedExitStatus
|
||||
if (exitCodeMismatch) {
|
||||
def message = "Expected exit status: $expectedExitStatus, actual: ${execResult.exitValue}"
|
||||
if (this.expectedFail) {
|
||||
println("Expected failure. $message")
|
||||
} else {
|
||||
throw new TestFailedException("Test failed. $message")
|
||||
}
|
||||
}
|
||||
|
||||
def goldValueMismatch = goldValue != null && goldValue != result.replace(System.lineSeparator(), "\n")
|
||||
if (goldValueMismatch) {
|
||||
def message = "Expected output: $goldValue, actual output: $result"
|
||||
if (this.expectedFail) {
|
||||
println("Expected failure. $message")
|
||||
} else {
|
||||
throw new TestFailedException("Test failed. $message")
|
||||
}
|
||||
}
|
||||
|
||||
if (goldValue != null && goldValue != result.replace(System.lineSeparator(), "\n")) {
|
||||
throw new TestFailedException("Test failed. Expected output: $goldValue, actual output: $result")
|
||||
if (!exitCodeMismatch && !goldValueMismatch && this.expectedFail) println("Unexpected pass")
|
||||
}
|
||||
|
||||
List<String> executionCommandLine(String exe) {
|
||||
if (target == KonanTarget.WASM32) {
|
||||
def properties = project.rootProject.konanProperties
|
||||
def targetToolchain = TargetPropertiesKt.hostTargetString(properties, "targetToolchain", target)
|
||||
def absoluteTargetToolchain = "$dependenciesDir/$targetToolchain"
|
||||
def d8 = "$absoluteTargetToolchain/bin/d8"
|
||||
def launcherJs = "${dist.absolutePath}/konan/nativelib/launcher.js"
|
||||
return [d8, '--expose-wasm', launcherJs, '--', exe]
|
||||
} else {
|
||||
return [exe]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,7 +322,7 @@ class RunDriverKonanTest extends KonanTest {
|
||||
*moreArgs,
|
||||
*project.globalTestArgs]
|
||||
if (project.testTarget) {
|
||||
args "-target", project.testTarget
|
||||
args "-target", target.userName
|
||||
}
|
||||
if (enableKonanAssertions) {
|
||||
args "-ea"
|
||||
@@ -312,7 +345,7 @@ class RunInteropKonanTest extends KonanTest {
|
||||
void setInterop(String value) {
|
||||
this.interop = value
|
||||
this.interopConf = project.kotlinNativeInterop[value]
|
||||
this.interopConf.target = project.testTarget
|
||||
this.interopConf.target = target.userName
|
||||
this.dependsOn(this.interopConf.genTask)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ targetList.each { targetName ->
|
||||
dependsOn ":common:${targetName}Hash"
|
||||
dependsOn "${targetName}Launcher"
|
||||
target targetName
|
||||
compilerArgs '-g'
|
||||
compilerArgs '-I' + project.file('../common/src/hash/headers')
|
||||
if (rootProject.hasProperty("${targetName}LibffiDir"))
|
||||
compilerArgs '-I' + project.file(rootProject.ext.get("${targetName}LibffiDir") + "/include")
|
||||
@@ -38,7 +37,6 @@ targetList.each { targetName ->
|
||||
name "launcher"
|
||||
srcRoot file('src/launcher')
|
||||
target targetName
|
||||
compilerArgs '-g'
|
||||
compilerArgs '-I' + project.file('../common/src/hash/headers')
|
||||
compilerArgs '-I' + project.file('src/main/cpp')
|
||||
}
|
||||
|
||||
@@ -57,4 +57,20 @@ extern "C" RUNTIME_USED int Konan_main(int argc, const char** argv) {
|
||||
return exitStatus;
|
||||
}
|
||||
|
||||
#ifdef KONAN_WASM
|
||||
// Before we pass control to Konan_main, we need to obtain argv elements
|
||||
// from the javascript world.
|
||||
extern "C" int Konan_js_arg_size(int index);
|
||||
extern "C" int Konan_js_fetch_arg(int index, char* ptr);
|
||||
|
||||
extern "C" int Konan_js_main(int argc) {
|
||||
char** argv = (char**)konan::calloc(1, argc);
|
||||
for (int i = 0; i< argc; ++i) {
|
||||
argv[i] = (char*)konan::calloc(1, Konan_js_arg_size(i));
|
||||
Konan_js_fetch_arg(i, argv[i]);
|
||||
}
|
||||
return Konan_main(argc, (const char**)argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var module;
|
||||
var instance;
|
||||
var heap;
|
||||
var memory;
|
||||
var global_arguments = arguments;
|
||||
var exit_status = 0;
|
||||
var globalBase = 0; // Is there any way to obtain global_base from JavaScript?
|
||||
|
||||
function print_usage() {
|
||||
// TODO: any reliable way to obtain the current script name?
|
||||
print('Usage: d8 --expose-wasm launcher.js -- <program.wasm> <program arg1> <program arg2> ...')
|
||||
quit(1); // TODO: this is d8 specific
|
||||
}
|
||||
|
||||
function utf8encode(s) {
|
||||
return unescape(encodeURIComponent(s));
|
||||
}
|
||||
|
||||
function utf8decode(s) {
|
||||
return decodeURIComponent(escape(s));
|
||||
}
|
||||
|
||||
function fromString(string, pointer) {
|
||||
for (i = 0; i < string.length; i++) {
|
||||
heap[pointer + i] = string.charCodeAt(i);
|
||||
}
|
||||
heap[pointer + string.length] = 0;
|
||||
}
|
||||
|
||||
function toString(pointer) {
|
||||
var string = '';
|
||||
for (var i = pointer; heap[i] != 0; i++) {
|
||||
string += String.fromCharCode(heap[i]);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
function int32ToHeap(value, pointer) {
|
||||
heap[pointer] = value & 0xff;
|
||||
heap[pointer+1] = (value & 0xff00) >>> 8;
|
||||
heap[pointer+2] = (value & 0xff0000) >>> 16;
|
||||
heap[pointer+3] = (value & 0xff000000) >>> 24;
|
||||
}
|
||||
|
||||
function stackTop() {
|
||||
// Read the value module's `__stack_pointer` is initialized with.
|
||||
// It is the very first static in .data section.
|
||||
var addr = (globalBase == 0 ? 4 : globalBase);
|
||||
var fourBytes = heap.buffer.slice(addr, addr+4);
|
||||
return new Uint32Array(fourBytes)[0];
|
||||
}
|
||||
|
||||
var konan_dependencies = {
|
||||
env: {
|
||||
abort: function() {
|
||||
throw new Error("abort()");
|
||||
},
|
||||
// TODO: Account for file and size.
|
||||
fgets: function(str, size, file) {
|
||||
fromString(utf8encode(readline()), str);
|
||||
return str;
|
||||
},
|
||||
Konan_heap_upper: function() {
|
||||
return memory.buffer.byteLength;
|
||||
},
|
||||
Konan_heap_lower: function() {
|
||||
return konanStackTop;
|
||||
},
|
||||
Konan_abort: function(pointer) {
|
||||
throw new Error("Konan_abort(" + utf8decode(toString(pointer)) + ")");
|
||||
},
|
||||
Konan_js_arg_size: function(index) {
|
||||
if (index >= global_arguments.length) return -1;
|
||||
return global_arguments[index].length + 1; // + 1 for trailing zero.
|
||||
},
|
||||
Konan_js_fetch_arg: function(index, ptr) {
|
||||
var arg = utf8encode(global_arguments[index]);
|
||||
fromString(arg, ptr);
|
||||
},
|
||||
Konan_date_now: function(pointer) {
|
||||
var now = Date.now();
|
||||
var high = Math.floor(now / 0xffffffff);
|
||||
var low = Math.floor(now % 0xffffffff);
|
||||
int32ToHeap(low, pointer);
|
||||
int32ToHeap(high, pointer+4);
|
||||
},
|
||||
stdin: 0, // This is for fgets(,,stdin) to resolve. It is ignored.
|
||||
// TODO: Account for fd and size.
|
||||
write: function(fd, str, size) {
|
||||
if (fd != 1 && fd != 2) throw ("write(" + fd + ", ...)");
|
||||
// TODO: There is no writeErr() in d8.
|
||||
// Approximate it with write() to stdout for now.
|
||||
write(utf8decode(toString(str))); // TODO: write() d8 specific.
|
||||
},
|
||||
memory: new WebAssembly.Memory({ initial: 256 })
|
||||
}
|
||||
};
|
||||
|
||||
if (arguments.length < 1) print_usage();
|
||||
|
||||
module = new WebAssembly.Module(new Uint8Array(readbuffer(arguments[0])));
|
||||
module.env = {};
|
||||
module.env.memoryBase = 0;
|
||||
module.env.tablebase = 0;
|
||||
|
||||
instance = new WebAssembly.Instance(module, konan_dependencies);
|
||||
memory = konan_dependencies.env.memory
|
||||
heap = new Uint8Array(konan_dependencies.env.memory.buffer);
|
||||
heap32 = new Uint32Array(konan_dependencies.env.memory.buffer);
|
||||
konanStackTop = stackTop();
|
||||
|
||||
try {
|
||||
exit_status = instance.exports.Konan_js_main(arguments.length);
|
||||
} catch (e) {
|
||||
print("Exception executing Konan_js_main: " + e);
|
||||
print(e.stack);
|
||||
exit_status = 1;
|
||||
}
|
||||
|
||||
quit(exit_status); // TODO: d8 specific.
|
||||
|
||||
@@ -50,7 +50,7 @@ class AutoFree {
|
||||
AutoFree(void* mem): mem_(mem) {}
|
||||
|
||||
~AutoFree() {
|
||||
free(mem_);
|
||||
konan::free(mem_);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,7 +105,7 @@ _Unwind_Reason_Code unwindCallback(
|
||||
}
|
||||
|
||||
char line[512];
|
||||
snprintf(line, sizeof(line) - 1, "%s (%p)",
|
||||
konan::snprintf(line, sizeof(line) - 1, "%s (%p)",
|
||||
symbol, (void*)(intptr_t)address);
|
||||
backtrace->setNextElement(line);
|
||||
return _URC_NO_REASON;
|
||||
@@ -162,6 +162,7 @@ void ThrowException(KRef exception) {
|
||||
RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo),
|
||||
"Throwing something non-throwable");
|
||||
#if KONAN_NO_EXCEPTIONS
|
||||
PrintThrowable(exception);
|
||||
RuntimeAssert(false, "Exceptions unsupported");
|
||||
#else
|
||||
#if (__MINGW32__ || __MINGW64__)
|
||||
|
||||
@@ -44,6 +44,8 @@ void ThrowArithmeticException();
|
||||
void ThrowNumberFormatException();
|
||||
// Throws out of memory error.
|
||||
void ThrowOutOfMemoryError();
|
||||
// Prints out mesage of Throwable.
|
||||
void PrintThrowable(KRef);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
@@ -53,7 +53,7 @@ void* Kotlin_interop_malloc(KLong size, KInt align) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* result = malloc(size);
|
||||
void* result = konan::calloc(1, size);
|
||||
if ((reinterpret_cast<uintptr_t>(result) & (align - 1)) != 0) {
|
||||
// Unaligned!
|
||||
RuntimeAssert(false, "unsupported alignment");
|
||||
@@ -63,7 +63,7 @@ void* Kotlin_interop_malloc(KLong size, KInt align) {
|
||||
}
|
||||
|
||||
void Kotlin_interop_free(void* ptr) {
|
||||
free(ptr);
|
||||
konan::free(ptr);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -76,7 +76,7 @@ void abort() {
|
||||
// memcpy/memmove are not here intentionally, as frequently implemented/optimized
|
||||
// by C compiler.
|
||||
void* memmem(const void *big, size_t bigLen, const void *little, size_t littleLen) {
|
||||
#if KONAN_WINDOWS
|
||||
#if KONAN_WINDOWS || KONAN_WASM
|
||||
for (size_t i = 0; i + littleLen <= bigLen; ++i) {
|
||||
void* pos = ((char*)big) + i;
|
||||
if (::memcmp(little, pos, littleLen) == 0) return pos;
|
||||
@@ -88,10 +88,19 @@ void* memmem(const void *big, size_t bigLen, const void *little, size_t littleLe
|
||||
|
||||
}
|
||||
|
||||
// The sprintf family.
|
||||
#if KONAN_INTERNAL_SNPRINTF
|
||||
extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list);
|
||||
#endif
|
||||
|
||||
int snprintf(char* buffer, size_t size, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
#if KONAN_INTERNAL_SNPRINTF
|
||||
int rv = rpl_vsnprintf(buffer, size, format, args);
|
||||
#else
|
||||
int rv = ::vsnprintf(buffer, size, format, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
return rv;
|
||||
}
|
||||
@@ -122,6 +131,22 @@ void free(void* pointer) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if KONAN_INTERNAL_NOW
|
||||
|
||||
extern "C" void Konan_date_now(uint64_t*);
|
||||
|
||||
uint64_t getTimeMillis() {
|
||||
uint64_t now;
|
||||
Konan_date_now(&now);
|
||||
return now;
|
||||
}
|
||||
uint64_t getTimeMicros() {
|
||||
return getTimeMillis() * 1000ULL;
|
||||
}
|
||||
uint64_t getTimeNanos() {
|
||||
return getTimeMillis() * 1000000ULL;
|
||||
}
|
||||
#else
|
||||
// Time operations.
|
||||
using namespace std::chrono;
|
||||
|
||||
@@ -136,12 +161,166 @@ uint64_t getTimeNanos() {
|
||||
uint64_t getTimeMicros() {
|
||||
return duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KONAN_INTERNAL_DLMALLOC
|
||||
// This function is being called when memory allocator needs more RAM.
|
||||
|
||||
#ifdef KONAN_WASM
|
||||
|
||||
// This one is an interface to query module.env.memory.buffer.byteLength
|
||||
extern "C" unsigned long Konan_heap_upper();
|
||||
extern "C" unsigned long Konan_heap_lower();
|
||||
|
||||
#define MFAIL ((void*) ~(size_t)0)
|
||||
#define WASM_PAGESIZE 65536U
|
||||
#define WASM_PAGEMASK ((WASM_PAGESIZE-(size_t)1))
|
||||
#define PAGE_ALIGN(value) ((value + WASM_PAGEMASK) & ~(WASM_PAGEMASK))
|
||||
|
||||
void* moreCore(int size) {
|
||||
return sbrk(size);
|
||||
static int initialized = 0;
|
||||
static void* sbrk_top = MFAIL;
|
||||
static void* upperHeapLimit = MFAIL;
|
||||
|
||||
if (!initialized) {
|
||||
sbrk_top = (void*)PAGE_ALIGN(Konan_heap_lower());
|
||||
upperHeapLimit = (void*)Konan_heap_upper();
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return sbrk_top;
|
||||
} else if (size < 0) {
|
||||
return MFAIL;
|
||||
}
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
void* old_sbrk_top = sbrk_top;
|
||||
sbrk_top = (char*)sbrk_top + size;
|
||||
|
||||
if (((char*)sbrk_top - (char*)upperHeapLimit) >= 0) {
|
||||
// TODO: Consider using grow() and .maximum Memory settings.
|
||||
abort();
|
||||
}
|
||||
return old_sbrk_top;
|
||||
}
|
||||
|
||||
// dlmalloc wants to know the page size.
|
||||
long getpagesize() {
|
||||
return WASM_PAGESIZE;
|
||||
}
|
||||
|
||||
#else
|
||||
void* moreCore(int size) {
|
||||
return sbrk(size);
|
||||
}
|
||||
|
||||
long getpagesize() {
|
||||
return sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} // namespace konan
|
||||
|
||||
extern "C" {
|
||||
#ifdef KONAN_WASM
|
||||
extern void Konan_abort(const char*);
|
||||
|
||||
// TODO: get rid of these.
|
||||
void _ZNKSt3__220__vector_base_commonILb1EE20__throw_length_errorEv(void) {
|
||||
Konan_abort("TODO: throw_length_error not implemented.");
|
||||
}
|
||||
void _ZNKSt3__221__basic_string_commonILb1EE20__throw_length_errorEv(void) {
|
||||
Konan_abort("TODO: throw_length_error not implemented.");
|
||||
}
|
||||
int _ZNSt3__212__next_primeEm(unsigned long n) {
|
||||
static unsigned long primes[] = {
|
||||
11UL,
|
||||
101UL,
|
||||
1009UL,
|
||||
10007UL,
|
||||
100003UL,
|
||||
1000003UL,
|
||||
10000019UL,
|
||||
100000007UL,
|
||||
1000000007UL
|
||||
};
|
||||
int table_length = sizeof(primes)/sizeof(unsigned long);
|
||||
|
||||
if (n > primes[table_length - 1]) konan::abort();
|
||||
|
||||
unsigned long prime = primes[0];
|
||||
for (unsigned long i=0; i< table_length; i++) {
|
||||
prime = primes[i];
|
||||
if (prime >= n) break;
|
||||
}
|
||||
return prime;
|
||||
}
|
||||
void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function) {
|
||||
char buf[1024];
|
||||
konan::snprintf(buf, sizeof(buf), "%s:%d in %s: runtime assert: %s\n", file, line, function, assertion);
|
||||
Konan_abort(buf);
|
||||
}
|
||||
int* __errno_location() {
|
||||
static int theErrno = 0;
|
||||
return &theErrno;
|
||||
}
|
||||
|
||||
// Some math.h functions.
|
||||
|
||||
double pow(double x, double y) {
|
||||
return __builtin_pow(x, y);
|
||||
}
|
||||
|
||||
// Some string.h functions.
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t n) {
|
||||
for (long i = 0; i != n; ++i)
|
||||
*((char*)dst + i) = *((char*)src + i);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *memmove(void *dst, const void *src, size_t len) {
|
||||
if (src < dst) {
|
||||
for (long i = len; i != 0; --i) {
|
||||
*((char*)dst + i - 1) = *((char*)src + i - 1);
|
||||
}
|
||||
} else {
|
||||
memcpy(dst, src, len);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
for (long i = 0; i != n; ++i) {
|
||||
if (*((char*)s1 + i) != *((char*)s2 + i)) {
|
||||
return *((char*)s1 + i) - *((char*)s2 + i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *memset(void *b, int c, size_t len) {
|
||||
for (long i = 0; i != len; ++i) {
|
||||
*((char*)b + i) = c;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
for (long i = 0;; ++i) {
|
||||
if (s[i] == 0) return i;
|
||||
}
|
||||
}
|
||||
|
||||
size_t strnlen(const char *s, size_t maxlen) {
|
||||
for (long i = 0; i<=maxlen; ++i) {
|
||||
if (s[i] == 0) return i;
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ OBJ_GETTER(Kotlin_Any_toString, KConstRef thiz) {
|
||||
|
||||
OBJ_GETTER(Kotlin_Byte_toString, KByte value) {
|
||||
char cstring[8];
|
||||
snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
konan::snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
@@ -95,13 +95,13 @@ OBJ_GETTER(Kotlin_Char_toString, KChar value) {
|
||||
|
||||
OBJ_GETTER(Kotlin_Short_toString, KShort value) {
|
||||
char cstring[8];
|
||||
snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
konan::snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_Int_toString, KInt value) {
|
||||
char cstring[16];
|
||||
snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
konan::snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ OBJ_GETTER(Kotlin_Int_toStringRadix, KInt value, KInt radix) {
|
||||
|
||||
OBJ_GETTER(Kotlin_Long_toString, KLong value) {
|
||||
char cstring[32];
|
||||
snprintf(cstring, sizeof(cstring), "%lld", static_cast<long long>(value));
|
||||
konan::snprintf(cstring, sizeof(cstring), "%lld", static_cast<long long>(value));
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
|
||||
@@ -525,14 +525,22 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP
|
||||
|
||||
/**** Start of Konan-specific dlmalloc configuration. ****/
|
||||
#define USE_DL_PREFIX 1
|
||||
#if !KONAN_WASM
|
||||
#if KONAN_WASM
|
||||
#define USE_LOCKS 0
|
||||
#define LACKS_TIME_H 1
|
||||
#define NO_MALLOC_STATS 1
|
||||
#define HAVE_MMAP 0 // don't try to allocate large chunks of memory using mmap().
|
||||
// It will go to malloc->calloc->sbrk->morecore chain anyways.
|
||||
#else
|
||||
#define USE_LOCKS 1
|
||||
#endif
|
||||
#define DLMALLOC_EXPORT extern "C"
|
||||
#define HAVE_MORECORE 1
|
||||
#define MORECORE konan::moreCore
|
||||
#define malloc_getpagesize konan::getpagesize()
|
||||
namespace konan {
|
||||
extern void* moreCore(int size);
|
||||
extern long getpagesize();
|
||||
} // namespace konan
|
||||
|
||||
/**** End of Konan-specific dlmalloc configuration. ****/
|
||||
|
||||
@@ -173,8 +173,8 @@ static const KDouble tens[] = {
|
||||
}
|
||||
#define ERROR_OCCURED(x) (HIGH_I32_FROM_VAR(x) < 0)
|
||||
|
||||
#define allocateU64(x, n) if (!((x) = (U_64*) malloc((n) * sizeof(U_64)))) goto OutOfMemory;
|
||||
#define release(r) if ((r)) free((r));
|
||||
#define allocateU64(x, n) if (!((x) = (U_64*) konan::calloc(1, (n) * sizeof(U_64)))) goto OutOfMemory;
|
||||
#define release(r) if ((r)) konan::free((r));
|
||||
|
||||
/*NB the Number converter methods are synchronized so it is possible to
|
||||
*have global data for use by bigIntDigitGenerator */
|
||||
|
||||
@@ -121,8 +121,8 @@ static const U_32 tens[] = {
|
||||
} \
|
||||
}
|
||||
|
||||
#define allocateU64(x, n) if (!((x) = (U_64*) malloc((n) * sizeof(U_64)))) goto OutOfMemory;
|
||||
#define release(r) if ((r)) free((r));
|
||||
#define allocateU64(x, n) if (!((x) = (U_64*) konan::calloc(1, (n) * sizeof(U_64)))) goto OutOfMemory;
|
||||
#define release(r) if ((r)) konan::free((r));
|
||||
|
||||
KFloat
|
||||
createFloat (const char *s, KInt e)
|
||||
|
||||
+25
-4
@@ -163,6 +163,26 @@
|
||||
* <http://www.jhweiss.de/software/snprintf.html>.
|
||||
*/
|
||||
|
||||
#if KONAN_INTERNAL_SNPRINTF
|
||||
|
||||
/**** Start of Konan-specific c99-snprintf configuration. ****/
|
||||
|
||||
#define HAVE_FLOAT_H 1
|
||||
#define HAVE_STDARG_H 1
|
||||
#define HAVE_STDDEF_H 1
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define HAVE_SNPRINTF 1
|
||||
#define HAVE_VASPRINTF 1
|
||||
#define HAVE_ASPRINTF 1
|
||||
#define HAVE_LONG_LONG_INT 1
|
||||
#define HAVE_UNSIGNED_LONG_LONG_INT 1
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list);
|
||||
#define malloc(size) konan:calloc(1, size)
|
||||
|
||||
/**** End of Konan-specific c99-snprintf configuration. ****/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
@@ -831,7 +851,7 @@ rpl_vsnprintf(char *str, size_t size, const char *format, va_list args)
|
||||
* characters, in an implementation-defined
|
||||
* manner." (C99: 7.19.6.1, 8)
|
||||
*/
|
||||
if ((strvalue = va_arg(args, void *)) == NULL)
|
||||
if ((strvalue = (char*)va_arg(args, void *)) == NULL)
|
||||
/*
|
||||
* We use the glibc format. BSD prints
|
||||
* "0x0", SysV "0".
|
||||
@@ -1472,8 +1492,8 @@ mypow10(int exponent)
|
||||
void *
|
||||
mymemcpy(void *dst, void *src, size_t len)
|
||||
{
|
||||
const char *from = src;
|
||||
char *to = dst;
|
||||
const char *from = (char*)src;
|
||||
char *to = (char*)dst;
|
||||
|
||||
/* No need for optimization, we use this only to replace va_copy(3). */
|
||||
while (len-- > 0)
|
||||
@@ -1492,7 +1512,7 @@ rpl_vasprintf(char **ret, const char *format, va_list ap)
|
||||
VA_COPY(aq, ap);
|
||||
len = vsnprintf(NULL, 0, format, aq);
|
||||
VA_END_COPY(aq);
|
||||
if (len < 0 || (*ret = malloc(size = len + 1)) == NULL)
|
||||
if (len < 0 || (*ret = (char*)malloc(size = len + 1)) == NULL)
|
||||
return -1;
|
||||
return vsnprintf(*ret, size, format, ap);
|
||||
}
|
||||
@@ -2092,4 +2112,5 @@ do { \
|
||||
}
|
||||
#endif /* TEST_SNPRINTF */
|
||||
|
||||
#endif // KONAN_INTERNAL_SNPRINTF
|
||||
/* vim: set joinspaces noexpandtab textwidth=80 cinoptions=(4,u0: */
|
||||
@@ -60,6 +60,11 @@ fun ThrowUninitializedPropertyAccessException(): Nothing {
|
||||
throw UninitializedPropertyAccessException()
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
fun PrintThrowable(throwable: Throwable) {
|
||||
println(throwable)
|
||||
}
|
||||
|
||||
@ExportForCppRuntime
|
||||
internal fun TheEmptyString() = ""
|
||||
|
||||
@@ -95,4 +100,4 @@ fun getProgressionLast(start: Char, end: Char, step: Int): Char =
|
||||
getProgressionLast(start.toInt(), end.toInt(), step).toChar()
|
||||
|
||||
fun getProgressionLast(start: Int, end: Int, step: Int): Int = getProgressionLastElement(start, end, step)
|
||||
fun getProgressionLast(start: Long, end: Long, step: Long): Long = getProgressionLastElement(start, end, step)
|
||||
fun getProgressionLast(start: Long, end: Long, step: Long): Long = getProgressionLastElement(start, end, step)
|
||||
|
||||
@@ -69,8 +69,8 @@ class ClangTarget(val target: KonanTarget, konanProperties: KonanProperties) {
|
||||
|
||||
KonanTarget.WASM32 ->
|
||||
listOf("-target", targetArg!!, "-O1", "-fno-rtti", "-fno-exceptions", "-DKONAN_WASM=1",
|
||||
"-D_LIBCPP_ABI_VERSION=2", "-DKONAN_NO_FFI=1", "-DKONAN_NO_THREADS=1", "-DKONAN_NO_EXCEPTIONS=1",
|
||||
"-DKONAN_INTERNAL_DLMALLOC=1",
|
||||
"-D_LIBCPP_ABI_VERSION=2", "-D_LIBCPP_NO_EXCEPTIONS=1", "-DKONAN_NO_FFI=1", "-DKONAN_NO_THREADS=1", "-DKONAN_NO_EXCEPTIONS=1",
|
||||
"-DKONAN_INTERNAL_DLMALLOC=1", "-DKONAN_INTERNAL_SNPRINTF=1", "-DKONAN_INTERNAL_NOW=1",
|
||||
"-nostdinc", "-Xclang", "-nobuiltininc", "-Xclang", "-nostdsysteminc",
|
||||
"-Xclang", "-isystem$sysRoot/include/libcxx", "-Xclang", "-isystem$sysRoot/lib/libcxxabi/include",
|
||||
"-Xclang", "-isystem$sysRoot/include/compat", "-Xclang", "-isystem$sysRoot/include/libc")
|
||||
|
||||
@@ -43,6 +43,7 @@ class KonanProperties(val target: KonanTarget, val properties: Properties, val b
|
||||
val linkerKonanFlags get() = targetList("linkerKonanFlags")
|
||||
val linkerDebugFlags get() = targetList("linkerDebugFlags")
|
||||
val llvmDebugOptFlags get() = targetList("llvmDebugOptFlags")
|
||||
val s2wasmFlags get() = targetList("s2wasmFlags")
|
||||
|
||||
val targetSysRoot get() = targetString("targetSysRoot")
|
||||
val libffiDir get() = targetString("libffiDir")
|
||||
|
||||
@@ -25,7 +25,7 @@ enum class KonanTarget(val targetSuffix: String, val programSuffix: String, var
|
||||
MINGW("mingw", "exe"),
|
||||
MACBOOK("osx", "kexe"),
|
||||
RASPBERRYPI("raspberrypi", "kexe"),
|
||||
WASM32("wasm32", "kexe");
|
||||
WASM32("wasm32", "wasm");
|
||||
|
||||
val userName get() = name.toLowerCase()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user