diff --git a/Makefile b/Makefile index af064e1a..330f3d24 100644 --- a/Makefile +++ b/Makefile @@ -202,7 +202,7 @@ EMCC = emcc #EMCCOPTS = -s TOTAL_MEMORY=2097152 -s TOTAL_STACK=524288 --memory-init-file 0 EMCCOPTS = -O2 -std=c99 -Wall --memory-init-file 0 -s WASM=0 -s POLYFILL_OLD_MATH_FUNCTIONS EMCCOPTS_DUKVM = -O2 -std=c99 -Wall --memory-init-file 0 -DEMSCRIPTEN -s WASM=0 -EMCCOPTS_DUKWEB_EXPORT = -s EXPORTED_FUNCTIONS='["_dukweb_is_open", "_dukweb_open","_dukweb_close","_dukweb_eval"]' -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall","cwrap"]' +EMCCOPTS_DUKWEB_EXPORT = -s EXPORTED_FUNCTIONS='["_main","_dukweb_is_open", "_dukweb_open","_dukweb_close","_dukweb_eval"]' -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall","cwrap"]' EMDUKOPTS = -s TOTAL_MEMORY=268435456 -DDUK_CMDLINE_PRINTALERT_SUPPORT EMDUKOPTS += -DEMSCRIPTEN # enable stdin workaround in duk_cmdline.c @@ -574,9 +574,8 @@ emduk.js: prep/emduk # and providing an eval() facility from both sides. This is a placeholder now # and doesn't do anything useful yet. dukweb.js: prep/dukweb - $(EMCC) $(EMCCOPTS_DUKVM) $(EMCCOPTS_DUKWEB_EXPORT) \ + $(EMCC) $(EMCCOPTS_DUKVM) $(EMCCOPTS_DUKWEB_EXPORT) --post-js dukweb/dukweb_extra.js \ -Iprep/dukweb prep/dukweb/duktape.c dukweb/dukweb.c -o dukweb.js - cat dukweb/dukweb_extra.js >> dukweb.js @wc dukweb.js literal_intern_test: prep/nondebug misc/literal_intern_test.c $(CC) -o $@ -std=c99 -O2 -fstrict-aliasing -Wall -Wextra \ diff --git a/dukweb/dukweb.c b/dukweb/dukweb.c index 86190015..907fa9b9 100644 --- a/dukweb/dukweb.c +++ b/dukweb/dukweb.c @@ -9,6 +9,10 @@ #include #include "duktape.h" +#if defined(__cplusplus) +extern "C" { +#endif + static duk_context *dukweb_ctx = NULL; static char duk__evalbuf[1024 * 1024]; @@ -17,7 +21,7 @@ static int dukweb__emscripten_run_script(duk_context *ctx) { if (!code) { return DUK_RET_TYPE_ERROR; } - /* FIXME: return value */ + /* XXX: return value */ emscripten_run_script(code); return 0; } @@ -108,7 +112,7 @@ void dukweb_close(void) { * output (eval result or error, coerced with ToString()). Data marshalling * needs to be implemented on top of this. * - * FIXME: proper return value model which identifies errors from success values + * XXX: proper return value model which identifies errors from success values */ const char *dukweb_eval(const char *code) { const char *res; @@ -158,4 +162,9 @@ const char *dukweb_eval(const char *code) { int main(int argc, char *argv[]) { printf("main()\n"); + emscripten_run_script("Duktape.initialize();"); } + +#if defined(__cplusplus) +} +#endif diff --git a/dukweb/dukweb_extra.js b/dukweb/dukweb_extra.js index 55e940f0..31297fa5 100644 --- a/dukweb/dukweb_extra.js +++ b/dukweb/dukweb_extra.js @@ -76,26 +76,11 @@ Duktape.escapeString = function(x) { return res.join(''); } -/* - * Raw C function bindings. - * - * The dukweb_eval() binding is a very raw binding which provides an - * interface to eval one string, and to get one string output (ToString - * coerced result or error). - */ - -// FIXME: not sure about the memory use here (leaks?), check -Duktape.dukweb_is_open = Module.cwrap('dukweb_is_open', 'number', [ ]); -Duktape.dukweb_open = Module.cwrap('dukweb_open', 'void', [ ]); -Duktape.dukweb_close = Module.cwrap('dukweb_close', 'void', [ ]); -Duktape.dukweb_eval = Module.cwrap('dukweb_eval', 'string', [ 'string' ]); -Duktape.logOwnProperties(); - /* * Duktape.eval: run code inside Duktape, encode output value using JSON. */ -// FIXME: errors should probably be promoted to work better +// XXX: errors should probably be promoted to work better Duktape.eval = function(code) { // Code escape into a Javascript string var escapedString = JSON.stringify(String(code)); @@ -129,76 +114,97 @@ Duktape.alertHandler = function(msg) { log(msg); } -/* - * Initialize Duktape heap automatically (not closed for now), and use - * Duktape.eval() to pull in some convenience properties like Duktape - * version. - */ - -Duktape.dukweb_open(); -Duktape.version = Duktape.eval('Duktape.version'); -Duktape.env = Duktape.eval('Duktape.env'); -Duktape.logOwnProperties(); - -/* - * Initialize a 'Dukweb' instance inside Duktape for interfacing with the - * browser side. - */ - -// Minimal console object. -var DUKWEB_CONSOLE_INIT = - 'Dukweb.console = (function () {\n' + - ' var useProxyWrapper = true;\n' + - ' var c = {};\n' + - ' function console_log(args, errName) {\n' + - ' var msg = Array.prototype.map.call(args, function (v) {\n' + - ' if (typeof v === "object" && v !== null) { return console.format(v); };\n' + - ' return v;\n' + - ' }).join(" ");\n' + - ' if (errName) {\n' + - ' var err = new Error(msg);\n' + - ' err.name = "Trace";\n' + - ' Dukweb.print(err.stack || err);\n' + - ' } else {\n' + - ' Dukweb.print(msg);\n' + - ' }\n' + - ' };\n' + - ' c.format = function format(v) { try { return Duktape.enc("jx", v); } catch (e) { return String(v); } };\n' + - ' c.assert = function assert(v) {\n' + - ' if (arguments[0]) { return; }\n' + - ' console_log(arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [ "false == true" ], "AssertionError");\n' + - ' };\n'+ - ' c.log = function log() { console_log(arguments, null); };\n' + - ' c.debug = function debug() { console_log(arguments, null); };\n' + - ' c.trace = function trace() { console_log(arguments, "Trace"); };\n' + - ' c.info = function info() { console_log(arguments, null); };\n' + - ' c.warn = function warn() { console_log(arguments, null); };\n' + - ' c.error = function error() { console_log(arguments, "Error"); };\n' + - ' c.exception = function exception() { console_log(arguments, "Error"); };\n' + - ' c.dir = function dir() { console_log(arguments, null); };\n' + - ' if (typeof Proxy === "function" && useProxyWrapper) {\n' + - ' var orig = c;\n' + - ' var dummy = function () {};\n' + - ' c = new Proxy(orig, {\n' + - ' get: function (targ, key, recv) {\n' + - ' var v = targ[key];\n' + - ' return typeof v === "function" ? v : dummy;\n' + - ' }\n' + - ' });\n' + - ' }\n' + - ' return c;\n' + - '})();'; - -Duktape.eval('Dukweb = {};'); -Duktape.eval('Dukweb.userAgent = ' + (JSON.stringify(navigator.userAgent.toString()) || '"unknown"') + ';'); -Duktape.eval('Dukweb.emscripten_run_script = this.emscripten_run_script; delete this.emscripten_run_script;'); -Duktape.eval('Dukweb.eval = Dukweb.emscripten_run_script;') // FIXME: better binding -Duktape.eval('Dukweb.print = function() { Dukweb.eval("Duktape.printHandler(" + JSON.stringify(Array.prototype.join.call(arguments, " ")) + ")") };'); -Duktape.eval('Dukweb.alert = function() { Dukweb.eval("Duktape.alertHandler(" + JSON.stringify(Array.prototype.join.call(arguments, " ")) + ")") };'); -Duktape.eval(DUKWEB_CONSOLE_INIT); -Duktape.eval('print = Dukweb.print;'); -Duktape.eval('alert = Dukweb.print;'); // intentionally bound to print() -Duktape.eval('console = Dukweb.console;'); - -Duktape.initSuccess = !!Duktape.dukweb_is_open(); -//console.log('=== ' + Duktape.eval('Duktape.enc("jx", { env: Duktape.env, version: Duktape.version })') + ' ==='); +// Asynchronous init, triggered from C main(). +Duktape.initialize = function initialize() { + console.log('Duktape.initialize() start'); + + /* + * Raw C function bindings. + * + * The dukweb_eval() binding is a very raw binding which provides an + * interface to eval one string, and to get one string output (ToString + * coerced result or error). + */ + + Duktape.dukweb_is_open = Module.cwrap('dukweb_is_open', 'number', [ ]); + Duktape.dukweb_open = Module.cwrap('dukweb_open', null, [ ]); + Duktape.dukweb_close = Module.cwrap('dukweb_close', null, [ ]); + Duktape.dukweb_eval = Module.cwrap('dukweb_eval', 'string', [ 'string' ]); + Duktape.logOwnProperties(); + + /* + * Initialize Duktape heap automatically (not closed for now), and use + * Duktape.eval() to pull in some convenience properties like Duktape + * version. + */ + + Duktape.dukweb_open(); + Duktape.version = Duktape.eval('Duktape.version'); + Duktape.env = Duktape.eval('Duktape.env'); + Duktape.logOwnProperties(); + + /* + * Initialize a 'Dukweb' instance inside Duktape for interfacing with the + * browser side. + */ + + // Minimal console object. + var DUKWEB_CONSOLE_INIT = + 'Dukweb.console = (function () {\n' + + ' var useProxyWrapper = true;\n' + + ' var c = {};\n' + + ' function console_log(args, errName) {\n' + + ' var msg = Array.prototype.map.call(args, function (v) {\n' + + ' if (typeof v === "object" && v !== null) { return console.format(v); };\n' + + ' return v;\n' + + ' }).join(" ");\n' + + ' if (errName) {\n' + + ' var err = new Error(msg);\n' + + ' err.name = "Trace";\n' + + ' Dukweb.print(err.stack || err);\n' + + ' } else {\n' + + ' Dukweb.print(msg);\n' + + ' }\n' + + ' };\n' + + ' c.format = function format(v) { try { return Duktape.enc("jx", v); } catch (e) { return String(v); } };\n' + + ' c.assert = function assert(v) {\n' + + ' if (arguments[0]) { return; }\n' + + ' console_log(arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [ "false == true" ], "AssertionError");\n' + + ' };\n'+ + ' c.log = function log() { console_log(arguments, null); };\n' + + ' c.debug = function debug() { console_log(arguments, null); };\n' + + ' c.trace = function trace() { console_log(arguments, "Trace"); };\n' + + ' c.info = function info() { console_log(arguments, null); };\n' + + ' c.warn = function warn() { console_log(arguments, null); };\n' + + ' c.error = function error() { console_log(arguments, "Error"); };\n' + + ' c.exception = function exception() { console_log(arguments, "Error"); };\n' + + ' c.dir = function dir() { console_log(arguments, null); };\n' + + ' if (typeof Proxy === "function" && useProxyWrapper) {\n' + + ' var orig = c;\n' + + ' var dummy = function () {};\n' + + ' c = new Proxy(orig, {\n' + + ' get: function (targ, key, recv) {\n' + + ' var v = targ[key];\n' + + ' return typeof v === "function" ? v : dummy;\n' + + ' }\n' + + ' });\n' + + ' }\n' + + ' return c;\n' + + '})();'; + + Duktape.eval('Dukweb = {};'); + Duktape.eval('Dukweb.userAgent = ' + (JSON.stringify(navigator.userAgent.toString()) || '"unknown"') + ';'); + Duktape.eval('Dukweb.emscripten_run_script = this.emscripten_run_script; delete this.emscripten_run_script;'); + Duktape.eval('Dukweb.eval = Dukweb.emscripten_run_script;') // XXX: better binding + Duktape.eval('Dukweb.print = function() { Dukweb.eval("Duktape.printHandler(" + JSON.stringify(Array.prototype.join.call(arguments, " ")) + ")") };'); + Duktape.eval('Dukweb.alert = function() { Dukweb.eval("Duktape.alertHandler(" + JSON.stringify(Array.prototype.join.call(arguments, " ")) + ")") };'); + Duktape.eval(DUKWEB_CONSOLE_INIT); + Duktape.eval('print = Dukweb.print;'); + Duktape.eval('alert = Dukweb.print;'); // intentionally bound to print() + Duktape.eval('console = Dukweb.console;'); + + Duktape.initSuccess = !!Duktape.dukweb_is_open(); + //console.log('=== ' + Duktape.eval('Duktape.enc("jx", { env: Duktape.env, version: Duktape.version })') + ' ==='); + + console.log('Duktape.initialize() end'); +}