diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt index 9b55e94d0a1..439fe366c4d 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt @@ -88,7 +88,8 @@ private val knownTargets = mapOf( "raspberrypi" to "raspberrypi", "android_arm32" to "android_arm32", "android_arm64" to "android_arm64", - "mingw" to "mingw" + "mingw" to "mingw", + "wasm32" to "wasm32" ) @@ -198,6 +199,12 @@ private fun maybeExecuteHelper(dependenciesRoot: String, properties: Properties, } } +private fun Properties.getClangFlags(target: String, targetSysRoot: String) : List { + val flags = getTargetSpecific("clangFlags", target) + if (flags == null) return emptyList() + return flags.replace("", targetSysRoot).split(' ') +} + private fun Properties.defaultCompilerOpts(target: String, dependencies: String): List { val targetToolchainDir = getHostTargetSpecific("targetToolchain", target)!! val targetToolchain = "$dependencies/$targetToolchainDir" @@ -224,7 +231,7 @@ private fun Properties.defaultCompilerOpts(target: String, dependencies: String) val arch = getTargetSpecific("arch", target) val archSelector = if (quadruple != null) listOf("-target", quadruple) else listOf("-arch", arch!!) - val commonArgs = listOf("-isystem", isystem, "--sysroot=$targetSysRoot") + val commonArgs = listOf("-isystem", isystem, "--sysroot=$targetSysRoot") + getClangFlags(target, targetSysRoot) when (host) { "osx" -> { val osVersionMinFlag = getTargetSpecific("osVersionMinFlagClang", target) diff --git a/backend.native/build.gradle b/backend.native/build.gradle index 978696fdadd..d8250282425 100644 --- a/backend.native/build.gradle +++ b/backend.native/build.gradle @@ -161,7 +161,9 @@ targetList.each { target -> "-Djava.library.path=${project.buildDir}/nativelibs", "-Dfile.encoding=UTF-8"] - def konanArgs = ['-nopack', '-nostdlib','-ea', '-g', + def defaultArgs = ['-nopack', '-nostdlib','-ea' ] + if (target != "wasm32") defaultArgs += '-g' + def konanArgs = [*defaultArgs, '-target', target, '-runtime', project(':runtime').file("build/${target}/runtime.bc"), '-properties', rootProject.konanPropertiesFile.canonicalPath, diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt index 07bca9fd8be..d932b8b375d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt @@ -169,6 +169,21 @@ internal open class MingwPlatform(distribution: Distribution) override fun linkCommandSuffix() = linkerKonanFlags } +internal open class WasmPlatform(distribution: Distribution) + : PlatformFlags(distribution.targetProperties) { + + private val clang = "clang" + + override val useCompilerDriverAsLinker: Boolean get() = false + + override fun linkCommand(objectFiles: List, executable: ExecutableFile, optimize: Boolean, debug: Boolean): List { + + return mutableListOf(clang).apply{ + throw Error("Implement me!") + } + } +} + internal class LinkStage(val context: Context) { val config = context.config.configuration @@ -184,6 +199,8 @@ internal class LinkStage(val context: Context) { AndroidPlatform(distribution) KonanTarget.MINGW -> MingwPlatform(distribution) + KonanTarget.WASM32 -> + WasmPlatform(distribution) else -> error("Unexpected target platform: ${context.config.targetManager.target}") } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt index b89367d69a7..b7dc2cff444 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt @@ -43,11 +43,14 @@ class Runtime(bitcodeFile: String) { val target = LLVMGetTarget(llvmModule)!!.toKString() // TODO: deduce TLS model from explicit config parameter. - val tlsMode = if (target.indexOf("android") != -1) - LLVMThreadLocalMode.LLVMGeneralDynamicTLSModel else LLVMThreadLocalMode.LLVMLocalExecTLSModel - + val tlsMode by lazy { + when { + target.indexOf("android") != -1 -> LLVMThreadLocalMode.LLVMGeneralDynamicTLSModel + target.indexOf("wasm") != -1 -> LLVMThreadLocalMode.LLVMNotThreadLocal + else -> LLVMThreadLocalMode.LLVMLocalExecTLSModel + } + } val dataLayout = LLVMGetDataLayout(llvmModule)!!.toKString() val targetData = LLVMCreateTargetData(dataLayout)!! - } diff --git a/backend.native/konan.properties b/backend.native/konan.properties index aab15273da5..edf2c7aca39 100644 --- a/backend.native/konan.properties +++ b/backend.native/konan.properties @@ -209,3 +209,22 @@ entrySelector.mingw = -Wl,--defsym,main=Konan_main dependencies.mingw = \ msys2-mingw-w64-x86_64-gcc-6.3.0-clang-llvm-3.9.1-windows-x86-64 \ libffi-3.2.1-mingw-w64-x86-64 + +# WebAssembly 32-bit. +targetToolchain.osx-wasm32 = target-toolchain-1-osx-wasm +dependencies.osx-wasm32 = \ + clang-llvm-3.9.0-darwin-macos \ + target-sysroot-1-wasm \ + target-toolchain-1-osx-wasm + +quadruple.wasm32 = wasm32 +entrySelector.wasm32 = -Wl,--defsym -Wl,main=Konan_main +llvmLtoFlags.wasm32 = -exported-symbol=Konan_main +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 \ + -nostdinc -Xclang -nobuiltininc -Xclang -nostdsysteminc \ + -Xclang -isystem/include/libcxx -Xclang -isystem/lib/libcxxabi/include \ + -Xclang -isystem/include/compat -Xclang -isystem/include/libc +linkerKonanFlags.wasm32 = -lc +linkerDebugFlags.wasm32 = -Wl,-S \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0e2f1bf87a2..d71b57c3308 100644 --- a/build.gradle +++ b/build.gradle @@ -102,7 +102,7 @@ void loadLocalProperties() { if (new File("$project.rootDir/local.properties").exists()) { Properties props = new Properties() props.load(new FileInputStream("$project.rootDir/local.properties")) - props.each {prop -> project.ext.set(prop.key, prop.value)} + props.each { prop -> project.ext.set(prop.key, prop.value) } } } @@ -111,11 +111,11 @@ void loadCommandLineProperties() { throw new Error("Specify either -Ptest_flags or -Pbuild_flags.") } ext.globalBuildArgs = project.hasProperty("build_flags") - ? ext.build_flags.split(' ') : [] + ? ext.build_flags.split(' '): [] ext.globalTestArgs = project.hasProperty("test_flags") - ? ext.test_flags.split(' ') : [] + ? ext.test_flags.split(' '): [] ext.testTarget = project.hasProperty("test_target") - ? ext.test_target : null + ? ext.test_target: null } class PlatformInfo { diff --git a/contrib/binaryen.diff b/contrib/binaryen.diff new file mode 100644 index 00000000000..36a2913ff75 --- /dev/null +++ b/contrib/binaryen.diff @@ -0,0 +1,193 @@ +diff --git a/src/s2wasm.h b/src/s2wasm.h +index 0fc0201c..c56a3a8c 100644 +--- a/src/s2wasm.h ++++ b/src/s2wasm.h +@@ -153,9 +153,16 @@ class S2WasmBuilder { + + Name getStr() { + std::string str; // TODO: optimize this and the other get* methods +- while (*s && !isspace(*s)) { +- str += *s; +- s++; ++ if (*s == '\"') { ++ str += *s++; ++ while (*s && *s != '\"') { ++ str += *s++; ++ } ++ if (*s == '\"') str += *s++; ++ } else { ++ while (*s && !isspace(*s)) { ++ str += *s++; ++ } + } + return cashew::IString(str.c_str(), false); + } +@@ -168,6 +175,11 @@ class S2WasmBuilder { + + Name getStrToSep() { + std::string str; ++ if (*s == '\"') { ++ str += *s++; ++ while (*s && *s != '\"') str += *s++; ++ if (*s == '\"') str += *s++; ++ } + while (*s && !isspace(*s) && *s != ',' && *s != '(' && *s != ')' && *s != ':' && *s != '+' && *s != '-' && *s != '=') { + str += *s; + s++; +@@ -177,10 +189,15 @@ class S2WasmBuilder { + + Name getStrToColon() { + std::string str; +- while (*s && !isspace(*s) && *s != ':') { +- str += *s; +- s++; ++ if (*s == '\"') { ++ str += *s++; ++ while (*s && *s != '\"') { ++ str += *s++; ++ } ++ if (*s == '\"') str += *s++; + } ++ while (*s && !isspace(*s) && *s != ':') ++ str += *s++; + return cashew::IString(str.c_str(), false); + } + +@@ -330,9 +347,18 @@ class S2WasmBuilder { + Name getSeparated(char separator) { + skipWhitespace(); + std::string str; +- while (*s && *s != separator && *s != '\n') { +- str += *s; +- s++; ++ bool inQuoted = false; ++ int inBrackets = 0; ++ while (*s && (*s != separator || inQuoted || inBrackets > 0) && *s != '\n') { ++ if (*s == '\"') { ++ inQuoted = !inQuoted; ++ } else if (*s == '(') { ++ inBrackets++; ++ } else if (*s == ')') { ++ inBrackets--; ++ } ++ ++ str += *s++; + } + skipWhitespace(); + return cashew::IString(str.c_str(), false); +@@ -421,14 +447,32 @@ class S2WasmBuilder { + bool isFunctionName(Name name) { + return !!strstr(name.str, "@FUNCTION"); + } +- // Drop the @ and after it. +- Name cleanFunction(Name name) { +- if (!strchr(name.str, '@')) return name; ++ ++ Name cleanName(Name name, char terminator = 0) { + char *temp = strdup(name.str); +- *strchr(temp, '@') = 0; ++ static const char* bads = "\";<>() "; ++ static const char* goods = "\'$__$$$"; ++ int index = 0; ++ while (bads[index] != 0) { ++ char *pos = temp; ++ while ((pos = strchr(pos, bads[index])) != nullptr) { ++ *pos = goods[index]; ++ pos++; ++ } ++ index++; ++ } ++ if (terminator != 0) { ++ char* pos = strrchr(temp, terminator); ++ if (pos != nullptr) *pos = '\0'; ++ } + Name ret = cashew::IString(temp, false); + free(temp); + return ret; ++ } ++ ++ // Drop the @ and after it. ++ Name cleanFunction(Name name) { ++ return cleanName(name, '@'); + } + + // processors +@@ -446,7 +490,7 @@ class S2WasmBuilder { + if (match(".hidden")) mustMatch(name.str); + mustMatch(name.str); + if (match(":")) { +- info->implementedFunctions.insert(name); ++ info->implementedFunctions.insert(cleanName(name)); + } else if (match("=")) { + Name alias = getAtSeparated(); + mustMatch("@FUNCTION"); +@@ -461,7 +505,7 @@ class S2WasmBuilder { + s = strchr(s, '\n'); + } else { + // add data aliases +- Name lhs = getStrToSep(); ++ Name lhs = cleanName(getStrToSep()); + // When the current line contains only one word, e.g.".text" + if (match("\n")) + continue; +@@ -473,7 +517,7 @@ class S2WasmBuilder { + } + + // get the original name +- Name rhs = getStrToSep(); ++ Name rhs = cleanName(getStrToSep()); + assert(!isFunctionName(rhs)); + Offset offset = 0; + if (*s == '+') { +@@ -620,7 +664,7 @@ class S2WasmBuilder { + } + + void parseGlobl() { +- linkerObj->addGlobal(getStr()); ++ linkerObj->addGlobal(cleanName(getStr())); + skipWhitespace(); + } + +@@ -753,7 +797,7 @@ class S2WasmBuilder { + skipWhitespace(); + } else break; + } +- Function* func = builder.makeFunction(name, std::move(params), resultType, std::move(vars)); ++ Function* func = builder.makeFunction(cleanName(name), std::move(params), resultType, std::move(vars)); + + // parse body + func->body = allocator->alloc(); +@@ -1343,6 +1387,11 @@ class S2WasmBuilder { + mustMatch(name.str); + skipWhitespace(); + } ++ if (match(".weak")) { ++ // Do nothing special on weak symbols so far. ++ mustMatch(name.str); ++ skipWhitespace(); ++ } + if (match(".align") || match(".p2align")) { + align = getInt(); + skipWhitespace(); +@@ -1436,9 +1485,10 @@ class S2WasmBuilder { + r->data = (uint32_t*)&raw[i]; + } + // assign the address, add to memory +- linkerObj->addStatic(size, align, name); ++ Name wasmName = cleanName(name); ++ linkerObj->addStatic(size, align, wasmName); + if (!zero) { +- linkerObj->addSegment(name, raw); ++ linkerObj->addSegment(wasmName, raw); + } + } + +@@ -1451,7 +1501,7 @@ class S2WasmBuilder { + skipComma(); + localAlign = 1 << getInt(); + } +- linkerObj->addStatic(size, std::max(align, localAlign), name); ++ linkerObj->addStatic(size, std::max(align, localAlign), cleanName(name)); + } + + void skipImports() { diff --git a/dependencies/build.gradle b/dependencies/build.gradle index d3a215f90f9..f1f7b8918fc 100644 --- a/dependencies/build.gradle +++ b/dependencies/build.gradle @@ -227,13 +227,18 @@ if (isLinux()) { } dependencyTask(MINGW, LIBFFI) -} else { +} else if (isMac()) { dependencyTask(MACBOOK, SYSROOT) dependencyTask(MACBOOK, LIBFFI) dependencyTask(IPHONE, SYSROOT) dependencyTask(IPHONE, LIBFFI) + dependencyTask(WASM32, SYSROOT) + // No FFI for webassembly. + // TODO: re-enable when we known how to bring the simulator sysroot to dependencies. - // dependencyTask(IPHONE_SIM, SYSROOT) + // dependencyTask("iphoneSim", SYSROOT) +} else { + throw new Error("Unsupported host") } if (isLinux() || isMac()) { diff --git a/runtime/build.gradle b/runtime/build.gradle index 6e893ff4228..48bb4408c95 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -27,7 +27,8 @@ targetList.each { targetName -> target targetName compilerArgs '-g' compilerArgs '-I' + project.file('../common/src/hash/headers') - compilerArgs '-I' + project.file(rootProject.ext.get("${targetName}LibffiDir") + "/include") + if (rootProject.hasProperty("${targetName}LibffiDir")) + compilerArgs '-I' + project.file(rootProject.ext.get("${targetName}LibffiDir") + "/include") linkerArgs project.file("../common/build/$targetName/hash.bc").path } } diff --git a/runtime/src/main/cpp/Common.h b/runtime/src/main/cpp/Common.h index 8295fa4e685..677794c9443 100644 --- a/runtime/src/main/cpp/Common.h +++ b/runtime/src/main/cpp/Common.h @@ -20,5 +20,10 @@ #define RUNTIME_NOTHROW __attribute__((nothrow)) #define RUNTIME_CONST __attribute__((const)) #define RUNTIME_PURE __attribute__((pure)) +#if KONAN_NO_THREADS +#define THREAD_LOCAL_VARIABLE +#else +#define THREAD_LOCAL_VARIABLE __thread +#endif #endif // RUNTIME_COMMON_H diff --git a/runtime/src/main/cpp/Console.cpp b/runtime/src/main/cpp/Console.cpp index ba8fed8a23c..c3b9c876791 100644 --- a/runtime/src/main/cpp/Console.cpp +++ b/runtime/src/main/cpp/Console.cpp @@ -30,7 +30,7 @@ void Kotlin_io_Console_print(KString message) { // TODO: system stdout must be aware about UTF-8. const KChar* utf16 = CharArrayAddressOfElementAt(message, 0); KStdString utf8; - utf8::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8)); + utf8::unchecked::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8)); konan::consoleWriteUtf8(utf8.c_str(), utf8.size()); } diff --git a/runtime/src/main/cpp/Exceptions.cpp b/runtime/src/main/cpp/Exceptions.cpp index d3d1bb27e8d..20878f84164 100644 --- a/runtime/src/main/cpp/Exceptions.cpp +++ b/runtime/src/main/cpp/Exceptions.cpp @@ -17,6 +17,10 @@ #include #include #include + +#if KONAN_NO_EXCEPTIONS +#define OMIT_BACKTRACE 1 +#endif #ifndef OMIT_BACKTRACE #if USE_GCC_UNWIND // GCC unwinder for backtrace. @@ -54,7 +58,7 @@ class AutoFree { struct Backtrace { Backtrace(int count, int skip) : index(0), skipCount(skip) { auto result = AllocArrayInstance( - theArrayTypeInfo, count - skipCount, arrayHolder.slot()); + theArrayTypeInfo, count - skipCount, arrayHolder.slot()); // TODO: throw cached OOME? RuntimeAssert(result != nullptr, "Cannot create backtrace array"); } @@ -156,8 +160,10 @@ OBJ_GETTER0(GetCurrentStackTrace) { void ThrowException(KRef exception) { RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo), - "Throwing something non-throwable"); - + "Throwing something non-throwable"); +#if KONAN_NO_EXCEPTIONS + RuntimeAssert(false, "Exceptions unsupported"); +#else #if (__MINGW32__ || __MINGW64__) // Workaround for https://bugs.llvm.org/show_bug.cgi?id=33220 // This code forces the function to have at least one landingpad: @@ -165,6 +171,7 @@ void ThrowException(KRef exception) { #endif throw ObjHolder(exception); +#endif } diff --git a/runtime/src/main/cpp/Interop.cpp b/runtime/src/main/cpp/Interop.cpp index 10a267b52ab..b40f4cbf0dd 100644 --- a/runtime/src/main/cpp/Interop.cpp +++ b/runtime/src/main/cpp/Interop.cpp @@ -17,14 +17,20 @@ #include #include #include + +#ifndef KONAN_NO_FFI #include +#endif #include "Memory.h" #include "Types.h" + namespace { typedef int FfiTypeKind; + +#ifndef KONAN_NO_FFI // Also declared in Varargs.kt const FfiTypeKind FFI_TYPE_KIND_VOID = 0; const FfiTypeKind FFI_TYPE_KIND_SINT8 = 1; @@ -49,6 +55,7 @@ ffi_type* convertFfiTypeKindToType(FfiTypeKind typeKind) { default: assert(false); return nullptr; } } +#endif // KONAN_NO_FFI } // namespace @@ -57,8 +64,9 @@ extern "C" { void Kotlin_Interop_callWithVarargs(void* codePtr, void* returnValuePtr, FfiTypeKind returnTypeKind, void** arguments, intptr_t* argumentTypeKinds, int fixedArgumentsNumber, int totalArgumentsNumber) { - - +#ifdef KONAN_NO_FFI + RuntimeAssert(false, "Vararg calls are not supported on this platform"); +#else ffi_type** argumentTypes = (ffi_type**)argumentTypeKinds; // In-place convertion: for (int i = 0; i < totalArgumentsNumber; ++i) { @@ -71,6 +79,7 @@ void Kotlin_Interop_callWithVarargs(void* codePtr, void* returnValuePtr, FfiType convertFfiTypeKindToType(returnTypeKind), argumentTypes); ffi_call(&cif, (void (*)())codePtr, returnValuePtr, arguments); +#endif } KNativePtr Kotlin_Interop_createStablePointer(KRef any) { diff --git a/runtime/src/main/cpp/KString.cpp b/runtime/src/main/cpp/KString.cpp index 9129e545f42..f966081ee58 100644 --- a/runtime/src/main/cpp/KString.cpp +++ b/runtime/src/main/cpp/KString.cpp @@ -38,12 +38,12 @@ namespace { OBJ_GETTER(utf8ToUtf16, const char* rawString, size_t rawStringLength) { - uint32_t charCount = utf8::distance(rawString, rawString + rawStringLength); + uint32_t charCount = utf8::unchecked::distance(rawString, rawString + rawStringLength); ArrayHeader* result = AllocArrayInstance( theStringTypeInfo, charCount, OBJ_RESULT)->array(); KChar* rawResult = CharArrayAddressOfElementAt(result, 0); auto convertResult = - utf8::utf8to16(rawString, rawString + rawStringLength, rawResult); + utf8::unchecked::utf8to16(rawString, rawString + rawStringLength, rawResult); RETURN_OBJ(result->obj()); } @@ -738,7 +738,7 @@ OBJ_GETTER(Kotlin_String_toUtf8Array, KString thiz, KInt start, KInt size) { } const KChar* utf16 = CharArrayAddressOfElementAt(thiz, start); KStdString utf8; - utf8::utf16to8(utf16, utf16 + size, back_inserter(utf8)); + utf8::unchecked::utf16to8(utf16, utf16 + size, back_inserter(utf8)); ArrayHeader* result = AllocArrayInstance( theByteArrayTypeInfo, utf8.size() + 1, OBJ_RESULT)->array(); ::memcpy(ByteArrayAddressOfElementAt(result, 0), utf8.c_str(), utf8.size()); diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index 8ecf808b23f..3fd750d818a 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -94,7 +94,7 @@ struct MemoryState { namespace { // TODO: can we pass this variable as an explicit argument? -__thread MemoryState* memoryState = nullptr; +THREAD_LOCAL_VARIABLE MemoryState* memoryState = nullptr; inline bool isFreeable(const ContainerHeader* header) { return (header->refCount_ & CONTAINER_TAG_MASK) < CONTAINER_TAG_PERMANENT; @@ -649,6 +649,13 @@ OBJ_GETTER(InitInstance, ObjHeader* object = AllocInstance(type_info, OBJ_RESULT); UpdateRef(location, object); +#if KONAN_NO_EXCEPTIONS + ctor(object); +#if TRACE_MEMORY + memoryState->globalObjects->push_back(location); +#endif + return object; +#else try { ctor(object); #if TRACE_MEMORY @@ -660,6 +667,7 @@ OBJ_GETTER(InitInstance, UpdateRef(location, nullptr); throw; } +#endif } void SetRef(ObjHeader** location, const ObjHeader* object) { @@ -882,7 +890,9 @@ OBJ_GETTER(DerefStablePointer, KNativePtr pointer) { } OBJ_GETTER(AdoptStablePointer, KNativePtr pointer) { +#ifndef KONAN_NO_THREADS __sync_synchronize(); +#endif KRef ref = reinterpret_cast(pointer); // Somewhat hacky. *OBJ_RESULT = ref; diff --git a/runtime/src/main/cpp/Types.h b/runtime/src/main/cpp/Types.h index 4da60abb70c..60d299d1be8 100644 --- a/runtime/src/main/cpp/Types.h +++ b/runtime/src/main/cpp/Types.h @@ -17,6 +17,13 @@ #ifndef RUNTIME_TYPES_H #define RUNTIME_TYPES_H +#include + +#if KONAN_WASM +// assert() is needed by WASM STL. +#define assert(cond) if (!(cond)) abort() +#endif + #include #include #include diff --git a/runtime/src/main/cpp/Worker.cpp b/runtime/src/main/cpp/Worker.cpp index 96038aaaac1..abf24a75492 100644 --- a/runtime/src/main/cpp/Worker.cpp +++ b/runtime/src/main/cpp/Worker.cpp @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define WITH_WORKERS 1 + +#ifndef KONAN_NO_THREADS +# define WITH_WORKERS 1 +#endif #include #include @@ -462,6 +465,11 @@ KInt stateOfFuture(KInt id) { return 0; } +KInt schedule(KInt id, KInt transferMode, KRef producer, KNativePtr jobFunction) { + ThrowWorkerUnsupported(); + return 0; +} + OBJ_GETTER(consumeFuture, KInt id) { ThrowWorkerUnsupported(); RETURN_OBJ(nullptr); diff --git a/runtime/src/main/cpp/dlmalloc/malloc.cpp b/runtime/src/main/cpp/dlmalloc/malloc.cpp index 9b434b6f6d3..3862f73adf5 100644 --- a/runtime/src/main/cpp/dlmalloc/malloc.cpp +++ b/runtime/src/main/cpp/dlmalloc/malloc.cpp @@ -525,7 +525,9 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP /**** Start of Konan-specific dlmalloc configuration. ****/ #define USE_DL_PREFIX 1 +#if !KONAN_WASM #define USE_LOCKS 1 +#endif #define DLMALLOC_EXPORT extern "C" #define HAVE_MORECORE 1 #define MORECORE konan::moreCore diff --git a/runtime/src/main/cpp/dtoa/dblparse.cpp b/runtime/src/main/cpp/dtoa/dblparse.cpp index e124240d2bc..a5b081ad710 100644 --- a/runtime/src/main/cpp/dtoa/dblparse.cpp +++ b/runtime/src/main/cpp/dtoa/dblparse.cpp @@ -642,7 +642,7 @@ KDouble Konan_FloatingPointParser_parseDoubleImpl (KString s, KInt e) { const KChar* utf16 = CharArrayAddressOfElementAt(s, 0); KStdString utf8; - utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)); + utf8::unchecked::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)); const char *str = utf8.c_str(); auto dbl = createDouble (str, e); diff --git a/runtime/src/main/cpp/dtoa/fltparse.cpp b/runtime/src/main/cpp/dtoa/fltparse.cpp index f464d6a996b..34f81518ee5 100644 --- a/runtime/src/main/cpp/dtoa/fltparse.cpp +++ b/runtime/src/main/cpp/dtoa/fltparse.cpp @@ -549,7 +549,7 @@ Konan_FloatingPointParser_parseFloatImpl (KString s, KInt e) { const KChar* utf16 = CharArrayAddressOfElementAt(s, 0); KStdString utf8; - utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)); + utf8::unchecked::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)); const char *str = utf8.c_str(); auto flt = createFloat (str, e); diff --git a/runtime/src/main/cpp/utf8.h b/runtime/src/main/cpp/utf8.h index 4e4451403f6..383db296139 100644 --- a/runtime/src/main/cpp/utf8.h +++ b/runtime/src/main/cpp/utf8.h @@ -28,7 +28,6 @@ DEALINGS IN THE SOFTWARE. #ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 -#include "utf8/checked.h" #include "utf8/unchecked.h" #endif // header guard diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt index f45fe3c8362..fccedab1cec 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt @@ -19,16 +19,15 @@ package org.jetbrains.kotlin.konan.target import org.jetbrains.kotlin.konan.properties.KonanProperties import org.jetbrains.kotlin.konan.file.File -class ClangTarget(val target: KonanTarget, val konanProperties: KonanProperties) { +class ClangTarget(val target: KonanTarget, konanProperties: KonanProperties) { - val sysRoot = konanProperties.absoluteTargetSysRoot!! + val sysRoot = konanProperties.absoluteTargetSysRoot val targetArg = konanProperties.targetArg val specificClangArgs: List get() { - return when (target) { - + val result = when (target) { KonanTarget.LINUX -> - listOf("--sysroot=$sysRoot", + listOf("--sysroot=$sysRoot", "-DUSE_GCC_UNWIND=1", "-DUSE_ELF_SYMBOLS=1", "-DELFSIZE=64") KonanTarget.RASPBERRYPI -> listOf("-target", targetArg!!, @@ -67,7 +66,16 @@ class ClangTarget(val target: KonanTarget, val konanProperties: KonanProperties) // HACKS! "-I$sysRoot/usr/include/c++/4.9.x", "-I$sysRoot/usr/include/c++/4.9.x/aarch64-linux-android") + + 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", + "-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") } + return result + (if (target != KonanTarget.WASM32) listOf("-g") else emptyList()) } } diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/KonanTarget.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/KonanTarget.kt index fafead82f30..d0226ab65fb 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/KonanTarget.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/KonanTarget.kt @@ -24,7 +24,9 @@ enum class KonanTarget(val targetSuffix: String, val programSuffix: String, var LINUX("linux", "kexe"), MINGW("mingw", "exe"), MACBOOK("osx", "kexe"), - RASPBERRYPI("raspberrypi", "kexe"); + RASPBERRYPI("raspberrypi", "kexe"), + WASM32("wasm32", "kexe"); + val userName get() = name.toLowerCase() } @@ -115,7 +117,7 @@ class TargetManager(val userRequest: String? = null) { else -> throw TargetSupportException("Unknown host: $host.") } - fun host_arch(): String { + fun host_arch(): String { val javaArch = System.getProperty("os.arch") return when (javaArch) { "x86_64" -> "x86_64" @@ -153,6 +155,7 @@ class TargetManager(val userRequest: String? = null) { //KonanTarget.IPHONE_SIM.enabled = true KonanTarget.ANDROID_ARM32.enabled = true KonanTarget.ANDROID_ARM64.enabled = true + KonanTarget.WASM32.enabled = true } else -> throw TargetSupportException("Unknown host platform: $host")