From: Brendan Hansen Date: Mon, 18 Oct 2021 14:06:18 +0000 (-0500) Subject: converted to a multi-threaded program X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=0f732471d6b9e6773d46209d743017822019d3f2;p=onyx-wasm-analyzer.git converted to a multi-threaded program --- diff --git a/build.bat b/build.bat index 400374e..ec49a10 100644 --- a/build.bat +++ b/build.bat @@ -4,7 +4,8 @@ set TARGET=site\analyzer.wasm set ONYX_MODULE_DIRECTORY=\dev\onyx copy "%ONYX_MODULE_DIRECTORY%\bin\onyx-loader.js" .\site\js\onyx-loader.js >NUL +copy "%ONYX_MODULE_DIRECTORY%\bin\onyx-thread.js" .\site\js\onyx-thread.js >NUL copy "%ONYX_MODULE_DIRECTORY%\modules\webgl2\webgl2.js" .\site\js\webgl2.js >NUL copy "%ONYX_MODULE_DIRECTORY%\modules\js_events\js_events.js" .\site\js\js_events.js >NUL -\dev\onyx\onyx --no-colors -r js -V --use-post-mvp-features -I %ONYX_MODULE_DIRECTORY% --doc doc\source_reference -o %TARGET% src\build.onyx \ No newline at end of file +\dev\onyx\onyx --no-colors -r js -V --use-post-mvp-features --use-multi-threading -I %ONYX_MODULE_DIRECTORY% --doc doc\source_reference -o %TARGET% src\build.onyx \ No newline at end of file diff --git a/build.sh b/build.sh index dd1f364..6048a03 100755 --- a/build.sh +++ b/build.sh @@ -5,6 +5,7 @@ ONYX_MODULE_DIRECTORY=/home/brendan/dev/c/onyx # Copy relative javascript modules from Onyx source directory cp "$ONYX_MODULE_DIRECTORY/bin/onyx-loader.js" ./site/js/onyx-loader.js +cp "$ONYX_MODULE_DIRECTORY/bin/onyx-thread.js" ./site/js/onyx-thread.js cp "$ONYX_MODULE_DIRECTORY/modules/webgl2/webgl2.js" ./site/js/webgl2.js cp "$ONYX_MODULE_DIRECTORY/modules/js_events/js_events.js" ./site/js/js_events.js @@ -16,6 +17,7 @@ RUNTIME=js onyx --no-colors $FLAGS -r $RUNTIME -V \ --use-post-mvp-features \ + --use-multi-threading \ -I $ONYX_MODULE_DIRECTORY \ --doc doc/source_reference \ -o $TARGET \ diff --git a/server.py b/server.py new file mode 100755 index 0000000..67cdccb --- /dev/null +++ b/server.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +from http import server + +class COOPServer(server.SimpleHTTPRequestHandler): + def end_headers(self): + self.send_header("Cross-Origin-Embedder-Policy", "require-corp") + self.send_header("Cross-Origin-Opener-Policy", "same-origin") + + server.SimpleHTTPRequestHandler.end_headers(self) + +if __name__ == '__main__': + httpd = server.HTTPServer(('', 8000), COOPServer) + httpd.serve_forever() diff --git a/site/index.html b/site/index.html index dfefdad..b68943b 100644 --- a/site/index.html +++ b/site/index.html @@ -14,11 +14,13 @@ } - + + + diff --git a/site/js/decompiler.js b/site/js/decompiler.js index bc51697..56024b4 100644 --- a/site/js/decompiler.js +++ b/site/js/decompiler.js @@ -30,39 +30,31 @@ window.ONYX_MODULES.push({ }, set_cursor: function(curptr, curlen) { - const decoder = new TextDecoder(); - const data = new Uint8Array(window.ONYX_MEMORY.buffer, curptr, curlen); - const str = decoder.decode(data); + const str = onyx_decode_text(curptr, curlen); document.getElementById("main_canvas").style.cursor = str; }, local_storage_store: function(keyptr, keylen, valueptr, valuelen) { - const decoder = new TextDecoder(); - - const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen)); - const value = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, valueptr, valuelen)); + const key = onyx_decode_text(keyptr, keylen); + const value = onyx_decode_text(valueptr, valuelen); localStorage[key] = value; }, local_storage_value_length: function(keyptr, keylen) { - const decoder = new TextDecoder(); const encoder = new TextEncoder(); - - const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen)); + const key = onyx_decode_text(keyptr, keylen); return encoder.encode(localStorage[key]).length; }, local_storage_load: function(keyptr, keylen, bufferptr, bufferlen) { - const decoder = new TextDecoder(); - const encoder = new TextEncoder(); - - const key = decoder.decode(new Uint8Array(window.ONYX_MEMORY.buffer, keyptr, keylen)); + const key = onyx_decode_text(keyptr, keylen); + const encoder = new TextEncoder(); const value_data = encoder.encode(localStorage[key]); - + let WASM_U8 = new Uint8Array(window.ONYX_MEMORY.buffer); WASM_U8.set(value_data, bufferptr); } diff --git a/site/js/js_events.js b/site/js/js_events.js index 2679c3e..9a40603 100644 --- a/site/js/js_events.js +++ b/site/js/js_events.js @@ -66,7 +66,7 @@ window.ONYX_MODULES.push({ if (ev.altKey) modifiers |= 0x02; if (ev.metaKey) modifiers |= 0x04; if (ev.shiftKey) modifiers |= 0x08; - + push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode, modifiers ]); var keyname = ev.code; @@ -141,8 +141,9 @@ window.ONYX_MODULES.push({ request_file(esp, event_size, filename_ptr, filename_len, fileid) { esp /= 4; - var path_memory = new Uint8Array(ONYX_MEMORY.buffer, filename_ptr, filename_len); - var path = new TextDecoder("utf-8").decode(path_memory); + var data_view = new DataView(ONYX_MEMORY.buffer); + var path = ""; + for (var i = 0; i < filename_len; i++) path += String.fromCharCode(data_view.getUint8(filename_ptr + i)); console.log(`Requesting file '${path}'`); fetch(path) diff --git a/site/js/onyx-loader.js b/site/js/onyx-loader.js index a48a38a..017dbbb 100644 --- a/site/js/onyx-loader.js +++ b/site/js/onyx-loader.js @@ -2,19 +2,62 @@ window.ONYX_MODULES = window.ONYX_MODULES || []; window.ONYX_MEMORY = null; window.ONYX_INSTANCE = null; +window.ONYX_BYTES = null; +window.ONYX_THREAD_SCRIPT = "onyx-thread.js"; window.ONYX_MODULES.push({ module_name: "host", print_str: function(ptr, len) { - var buffer = new Uint8Array(ONYX_MEMORY.buffer, ptr, len); - var string = new TextDecoder().decode(buffer); - console.log(string); + console.log(onyx_decode_text(ptr, len)); }, - exit: function() { debugger; } + exit: function() { debugger; }, + + spawn_thread: function(id, funcidx, dataptr) { + try { + let needed_imports = {}; + + for (let i = 0; i < window.ONYX_MODULES.length; i++) { + needed_imports[window.ONYX_MODULES[i].module_name] = []; + + for (let k of Object.keys(window.ONYX_MODULES[i])) { + if (k == "module_name") continue; + + needed_imports[window.ONYX_MODULES[i].module_name].push(k); + } + } + + const worker = new Worker(window.ONYX_THREAD_SCRIPT); + worker.postMessage({ + thread_id : id, + memory : window.ONYX_MEMORY, + wasm_bytes : window.ONYX_BYTES, + funcidx : funcidx, + dataptr : dataptr, + imports : needed_imports, + }); + + return 1; + + } catch (e) { + console.error(e); + return 0; + } + }, }); +function onyx_decode_text(ptr, len) { + let v = new DataView(window.ONYX_MEMORY.buffer); + + let s = ""; + for (let i = 0; i < len; i++) { + s += String.fromCharCode(v.getUint8(ptr + i)); + } + + return s; +} + function launch_onyx_program(script_path, call_start) { fetch(script_path) .then(function(res) { return res.arrayBuffer(); }) @@ -35,13 +78,41 @@ function launch_onyx_program(script_path, call_start) { }); } +function launch_multi_threaded_onyx_program(script_path, data_path, call_start) { + Promise.all([fetch(script_path), fetch(data_path)]) + .then(function(xs) { return Promise.all([xs[0].arrayBuffer(), xs[1].arrayBuffer()]); }) + .then(function(data) { + var import_object = {}; + + for (var i = 0; i < window.ONYX_MODULES.length; i++) { + import_object[window.ONYX_MODULES[i].module_name] = window.ONYX_MODULES[i]; + } + + import_object["onyx"] = { memory: new WebAssembly.Memory({ initial: 1024, maximum: 65536, shared: true }) }; + window.ONYX_MEMORY = import_object["onyx"]["memory"]; + window.ONYX_BYTES = data[0]; + + WebAssembly.instantiate(data[1], import_object) + .then(function (data_module) { + WebAssembly.instantiate(data[0], import_object) + .then(function (code_module) { + window.ONYX_INSTANCE = code_module.instance; + code_module.instance.exports._start(); + }); + }); + }); +} + window.onload = function() { var script_tags = document.getElementsByTagName("script"); for (var i = 0; i < script_tags.length; i++) { if (script_tags[i].getAttribute("type") == "application/onyx") { - // @ROBUSTNESS: It should be configurable which function is called on start up of a Onyx WASM module. - launch_onyx_program(script_tags[i].getAttribute("src"), true); + if (script_tags[i].getAttribute("multi-threaded")) { + launch_multi_threaded_onyx_program(script_tags[i].getAttribute("src"), script_tags[i].getAttribute("data"), true); + } else { + launch_onyx_program(script_tags[i].getAttribute("src"), true); + } } } }; diff --git a/site/js/onyx-thread.js b/site/js/onyx-thread.js new file mode 100644 index 0000000..881b2ee --- /dev/null +++ b/site/js/onyx-thread.js @@ -0,0 +1,38 @@ + +function onyx_decode_text(ptr, len) { + let v = new DataView(self.ONYX_MEMORY.buffer); + + let s = ""; + for (let i = 0; i < len; i++) { + s += String.fromCharCode(v.getUint8(ptr + i)); + } + + return s; +} + + +self.onmessage = function (msg) { + const data = msg.data; + + let import_object = {}; + for (let k of Object.keys(data.imports)) { + import_object[k] = {}; + for (let v of data.imports[k]) { + import_object[k][v] = function(a, b, c, d, e, f, g, h, i, j) { + console.error("ATTEMPT TO CALL MAIN THREAD FUNCTION FROM WORKER THREAD! " + v + "." + k); + } + } + } + + import_object.host.print_str = function(ptr, len) { console.log(onyx_decode_text(ptr, len)); }; + import_object.host.exit = function() { debugger; }; + import_object.onyx = { memory: data.memory }; + + WebAssembly.instantiate(new Uint8Array(data.wasm_bytes), import_object) + .then(function(res) { + self.ONYX_MEMORY = data.memory; + + res.instance.exports._thread_start(data.thread_id, data.funcidx, data.dataptr); + res.instance.exports._thread_exit(data.thread_id); + }); +} \ No newline at end of file diff --git a/site/js/webgl2.js b/site/js/webgl2.js index df8936d..6964651 100644 --- a/site/js/webgl2.js +++ b/site/js/webgl2.js @@ -15,9 +15,7 @@ window.ONYX_MODULES.push({ module_name: "gl", init(name, namelen) { - const decoder = new TextDecoder(); - const str = new Uint8Array(window.ONYX_MEMORY.buffer, name, namelen); - const canvasname = decoder.decode(str); + const canvasname = onyx_decode_text(name, namelen); canvas = document.getElementById(canvasname); if (canvas == null) return 0; @@ -207,9 +205,7 @@ window.ONYX_MODULES.push({ }, // getAttachedShaders() { console.log("NOT IMPLEMENTED!"); }, getAttribLocation(program, name, namelen) { - const decoder = new TextDecoder(); - const str = new Uint8Array(window.ONYX_MEMORY.buffer, name, namelen); - const attribname = decoder.decode(str); + const attribname = onyx_decode_text(name, namelen); return gl.getAttribLocation(programs[program], attribname); }, @@ -224,9 +220,7 @@ window.ONYX_MODULES.push({ getShaderParameter(shader, param) { return gl.getShaderParameter(shaders[shader], param); }, getProgramParameter(program, param) { return gl.getProgramParameter(programs[program], param); }, getUniformLocation(program, name, namelen) { - const decoder = new TextDecoder(); - const str = new Int8Array(window.ONYX_MEMORY.buffer, name, namelen); - const uniname = decoder.decode(str); + const uniname = onyx_decode_text(name, namelen); uniformlocs.push(gl.getUniformLocation(programs[program], uniname)); return uniformlocs.length - 1; @@ -261,9 +255,7 @@ window.ONYX_MODULES.push({ scissor(x, y, width, height) { gl.scissor(x, y, width, height); }, setSize(width, height) { canvas.width = width; canvas.height = height; }, shaderSource(shader, source, sourcelen) { - const decoder = new TextDecoder(); - const str = new Int8Array(window.ONYX_MEMORY.buffer, source, sourcelen); - const sourcedata = decoder.decode(str); + const sourcedata = onyx_decode_text(source, sourcelen); gl.shaderSource(shaders[shader], sourcedata); }, diff --git a/src/app/app.onyx b/src/app/app.onyx index eb4640c..e86e6b6 100644 --- a/src/app/app.onyx +++ b/src/app/app.onyx @@ -195,6 +195,28 @@ init :: () { } } } + + use package core.intrinsics.atomics + + t, t2: thread.Thread; + thread.spawn(^t, (_: ^i32) { + printf("Hello from another thread!\n"); + + for i: 1000 { + __atomic_wait(_, 0, 1000000000); + printf("Hello from another thread! {}\n", i); + } + + }, null); + + thread.spawn(^t2, (_: ^i32) { + i := 1; + while true { + i *= 2; + __atomic_wait(_, 0, 1000000000); + debug_log(.Warning, "Debug message: {}\n", i); + } + }, null); } handle_event :: (event: ^events.Event) {