From a9bc37ab913885f041fc5b2c82adb103ab68ef7c Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Thu, 5 May 2016 00:42:32 +0300 Subject: [PATCH 01/11] Add Duktape 2.x duk_safe_call() support --- src/main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main.c b/src/main.c index 7d4f8db..49d4aab 100644 --- a/src/main.c +++ b/src/main.c @@ -454,11 +454,19 @@ static duk_ret_t duv_main(duk_context *ctx) { return 0; } +#if DUK_VERSION >= 19999 /* duk_safe_call() udata added in 2.0.0 (1.99.99 is pre-release) */ +static duk_ret_t duv_stash_argv(duk_context *ctx, void *udata) { +#else static duk_ret_t duv_stash_argv(duk_context *ctx) { +#endif char **argv = (char **) duk_require_pointer(ctx, 0); int argc = (int) duk_require_int(ctx, 1); int i; +#if DUK_VERSION >= 19999 /* duk_safe_call() udata added in 2.0.0 (1.99.99 is pre-release) */ + (void) udata; +#endif + duk_push_global_stash(ctx); duk_push_array(ctx); for (i = 0; i < argc; i++) { @@ -504,7 +512,11 @@ int main(int argc, char *argv[]) { // Stash argv for later access duk_push_pointer(ctx, (void *) argv); duk_push_int(ctx, argc); +#if DUK_VERSION >= 19999 /* duk_safe_call() udata added in 2.0.0 (1.99.99 is pre-release) */ + if (duk_safe_call(ctx, duv_stash_argv, NULL, 2, 1)) { +#else if (duk_safe_call(ctx, duv_stash_argv, 2, 1)) { +#endif duv_dump_error(ctx, -1); uv_loop_close(&loop); duk_destroy_heap(ctx); From 5fb5e1cf460ae2eb6785d20f409e8fd52bf00a59 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Sat, 7 May 2016 03:25:50 +0300 Subject: [PATCH 02/11] Avoid duk_dump_context_stderr() for Duktape 2.x --- src/schema.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/schema.c b/src/schema.c index bbeb5dc..3fdb145 100644 --- a/src/schema.c +++ b/src/schema.c @@ -1,3 +1,4 @@ +#include #include "schema.h" duk_bool_t dschema_is_data(duk_context* ctx, duk_idx_t index) { @@ -16,11 +17,15 @@ void dschema_check(duk_context *ctx, const duv_schema_entry schema[]) { for (i = 0; schema[i].name; ++i) { // printf("Checking arg %d-%s\n", i, schema[i].name); if (schema[i].checker(ctx, i)) continue; - duk_dump_context_stderr(ctx); + duk_push_context_dump(ctx); + fprintf(stderr, "%s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); duk_error(ctx, DUK_ERR_TYPE_ERROR, "Invalid argument type for %s", schema[i].name); } if (top > i) { - duk_dump_context_stderr(ctx); + duk_push_context_dump(ctx); + fprintf(stderr, "%s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); duk_error(ctx, DUK_ERR_TYPE_ERROR, "Too many arguments. Expected at %d, but got %d", i, top); } } From 0613b2318a1e8b026ff6157040ae16171180273d Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Sun, 8 May 2016 03:13:21 +0300 Subject: [PATCH 03/11] Add print/alert provider for Duktape 2.x support --- src/main.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 49d4aab..b01bca0 100644 --- a/src/main.c +++ b/src/main.c @@ -478,6 +478,37 @@ static duk_ret_t duv_stash_argv(duk_context *ctx) { return 0; } +#if DUK_VERSION >= 19999 +// Print/alert provider with Duktape 1.x semantics. +static duk_ret_t duv_print_alert_helper(duk_context *ctx, FILE *fh) { + duk_idx_t nargs, i; + const duk_uint8_t *buf; + duk_size_t sz_buf; + const char nl = (const char) '\n'; + + nargs = duk_get_top(ctx); + if (nargs == 1 && duk_is_buffer(ctx, 0)) { + buf = (const duk_uint8_t *) duk_get_buffer(ctx, 0, &sz_buf); + fwrite((const void *) buf, 1, (size_t) sz_buf, fh); + return 0; + } + /* Coerce all arguments before writing anything so that if there are + * side effects with print() calls, they are written first. + */ + duk_push_string(ctx, " "); + duk_insert(ctx, 0); + duk_join(ctx, nargs); + fprintf(fh, "%s\n", duk_to_string(ctx, -1)); + return 0; +} +static duk_ret_t duv_print(duk_context *ctx) { + return duv_print_alert_helper(ctx, stdout); +} +static duk_ret_t duv_alert(duk_context *ctx) { + return duv_print_alert_helper(ctx, stderr); +} +#endif + static void duv_dump_error(duk_context *ctx, duk_idx_t idx) { fprintf(stderr, "\nUncaught Exception:\n"); if (duk_is_object(ctx, idx)) { @@ -504,11 +535,23 @@ int main(int argc, char *argv[]) { // Tie loop and context together ctx = duk_create_heap(NULL, NULL, NULL, &loop, NULL); if (!ctx) { - fprintf(stderr, "Problem initiailizing duktape heap\n"); + fprintf(stderr, "Problem initializing duktape heap\n"); return -1; } loop.data = ctx; + // Minimal print/alert (removed in Duktape 2.x) +#if DUK_VERSION >= 19999 + duk_push_global_object(ctx); + duk_push_string(ctx, "print"); + duk_push_c_function(ctx, duv_print, DUK_VARARGS); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_CONFIGURABLE); + duk_push_string(ctx, "alert"); + duk_push_c_function(ctx, duv_alert, DUK_VARARGS); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_CONFIGURABLE); + duk_pop(ctx); +#endif + // Stash argv for later access duk_push_pointer(ctx, (void *) argv); duk_push_int(ctx, argc); From 6c24b8c21a15215e337e66856b4941e73e2fb32a Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Sun, 15 May 2016 13:53:45 +0300 Subject: [PATCH 04/11] Add a fatal error handler --- src/main.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index b01bca0..9a3188c 100644 --- a/src/main.c +++ b/src/main.c @@ -521,6 +521,22 @@ static void duv_dump_error(duk_context *ctx, duk_idx_t idx) { } } +#if DUK_VERSION >= 19999 +static void duv_fatal(void *udata, const char *msg) { + (void) udata; + fprintf(stderr, "*** FATAL ERROR: %s\n", (msg ? msg : "no message")); + fflush(stderr); + abort(); +} +#else +static void duv_fatal(duk_context *ctx, duk_errcode_t err_code, const char *msg) { + (void) ctx; (void) err_code; + fprintf(stderr, "*** FATAL ERROR: %s\n", (msg ? msg : "no message")); + fflush(stderr); + abort(); +} +#endif + int main(int argc, char *argv[]) { duk_context *ctx = NULL; uv_loop_init(&loop); @@ -533,7 +549,7 @@ int main(int argc, char *argv[]) { } // Tie loop and context together - ctx = duk_create_heap(NULL, NULL, NULL, &loop, NULL); + ctx = duk_create_heap(NULL, NULL, NULL, &loop, duv_fatal); if (!ctx) { fprintf(stderr, "Problem initializing duktape heap\n"); return -1; From b64d9d528d33144fd4d0fff6d4c2774bb5b8fff9 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Sat, 28 May 2016 03:01:07 +0300 Subject: [PATCH 05/11] Add Duktape.modLoaded in 2.x (missing otherwise) --- src/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.c b/src/main.c index 9a3188c..809c7b5 100644 --- a/src/main.c +++ b/src/main.c @@ -422,6 +422,13 @@ static duk_ret_t duv_main(duk_context *ctx) { duk_put_prop_string(ctx, -2, "loadlib"); duk_pop(ctx); +#if DUK_VERSION >= 19999 + /* Built-in module loader was removed in 2.0.0. Duktape.modLoaded[] + * was also removed and we depend on it, so add it if missing. + */ + duk_eval_string_noresult(ctx, "Object.defineProperty(Duktape, 'modLoaded', { value: {}, writable: true, enumerable: false, configurable: true });"); +#endif + // Put in some quick globals to test things. duk_push_c_function(ctx, duv_path_join, DUK_VARARGS); duk_put_prop_string(ctx, -2, "pathJoin"); From aa46cc52b7fcb310625ba7c2c413ef11551adb61 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Thu, 28 Jul 2016 02:16:18 +0300 Subject: [PATCH 06/11] Support both Duktape 1.x and 2.x buffer bindings --- repl.js | 2 +- tcp-echo.js | 2 +- unit-tests.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/repl.js b/repl.js index b8fd6d0..b30689c 100644 --- a/repl.js +++ b/repl.js @@ -4,7 +4,7 @@ var utils = require('./modules/utils.js'); var p = utils.prettyPrint; function Timer() { - var obj = new Duktape.Buffer(uv.new_timer()); + var obj = Object(uv.new_timer()); // coerce to ArrayBuffer obj.__proto__ = Timer.prototype; return obj; } diff --git a/tcp-echo.js b/tcp-echo.js index fcf660a..efb1f54 100644 --- a/tcp-echo.js +++ b/tcp-echo.js @@ -59,7 +59,7 @@ Client.prototype.onConnect = function onConnect(err) { assert(this === client); if (err) { throw err; } this.readStart(this.onRead); - var buffer = Duktape.Buffer(3); + var buffer = (typeof ArrayBuffer.allocPlain === 'function' ? ArrayBuffer.allocPlain(3) : Duktape.Buffer(3)); buffer[0] = 0x10; buffer[1] = 0x00; buffer[2] = 0x50; diff --git a/unit-tests.js b/unit-tests.js index 3337c07..cdf3d1d 100644 --- a/unit-tests.js +++ b/unit-tests.js @@ -203,7 +203,7 @@ test("pretty printer", function () { p({ thread: new Duktape.Thread(test), buffer: timer, - dynamic: new Duktape.Buffer("Hello"), + dynamic: (typeof ArrayBuffer.allocPlain === 'function' ? Object(ArrayBuffer.allocPlain("Hello")) : new Duktape.Buffer("Hello")), pointer: new Duktape.Pointer(p), error: new Error("test"), typeError: new TypeError("test2"), @@ -216,7 +216,7 @@ test("pretty printer", function () { p({ thread: Duktape.Thread(test), - dynamic: Duktape.Buffer("Hello"), + dynamic: (typeof ArrayBuffer.allocPlain === 'function' ? ArrayBuffer.allocPlain("Hello") : Duktape.Buffer("Hello")), pointer: Duktape.Pointer(p), error: Error("test"), typeError: TypeError("test2"), From 54771efc46638ac2f2ec72faad591ad07b5ddf55 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Thu, 28 Jul 2016 02:36:05 +0300 Subject: [PATCH 07/11] Support dumping of all buffer types External buffer is not directly supported however. --- modules/utils.js | 56 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/modules/utils.js b/modules/utils.js index b78c7e9..04a7712 100644 --- a/modules/utils.js +++ b/modules/utils.js @@ -25,6 +25,21 @@ cbrace = colorize("braces", '}'); comma = colorize("sep", ','); colon = colorize("sep", ':'); +var bufferObjectTypes = { + Buffer: true, + ArrayBuffer: true, // Duktape 2.x: both plain buffer and ArrayBuffer + Uint8Array: true, + Uint8ClampedArray: true, + Int8Array: true, + Uint16Array: true, + Int16Array: true, + Uint32Array: true, + Int32Array: true, + Float32Array: true, + Float64Array: true, + DataView: true +}; + function color(color_name) { return "\x1b[" + (color_name ? theme[color_name] : "0") + "m"; } @@ -33,13 +48,19 @@ function colorize(color_name, string, reset_name) { return color(color_name) + string + color(reset_name); } -function dump(value) { +var getPlainBuffer = typeof ArrayBuffer.plainOf === 'function' ? + ArrayBuffer.plainOf : Duktape.Buffer; +var isPlainBuffer = function (v) { + return Duktape.info(v)[0] === 7; // Duktape 1.x and 2.x +}; +function dump(value) { var seen = []; return dumper(value, 0); + function dumper(value, depth) { + var i, n, t; var type = typeof value; - if (type === "undefined") { return colorize("undefined", "undefined"); } @@ -60,6 +81,8 @@ function dump(value) { }); } var info = Duktape.info(value); + var fullName = Object.prototype.toString.call(value); + var name = fullName.substring(8, fullName.length - 1); if (type === "function") { var fname = value.name || info[1]; // Native CFunctions don't have a .prototype property. @@ -68,24 +91,31 @@ function dump(value) { } return colorize("cfunction", "[Native " + fname + "]"); } - var fullName = Object.prototype.toString.call(value); - var name = fullName.substring(8, fullName.length - 1); if (name === "RegExp") { return colorize("regexp", "[RegExp " + value + "]"); } if (name === "Thread") { return colorize("thread", "[Thread " + info[1] + "]"); } - if (name === "Buffer") { - var preview = Array.prototype.slice.call(value, 0, 10).map(function (byte) { - return byte < 16 ? "0" + byte.toString(16) : byte.toString(16); - }).join(" "); - if (value.length > 10) { preview += "..."; } - // Fixed buffers have undefined for info[4] - if (info[4] === undefined) { - return colorize("buffer", "[Buffer " + preview + "]"); + if (type === "buffer" || // Duktape 1.x plain buffer + bufferObjectTypes[name]) { // Duktape 2.x plain buffer, ArrayBuffer, typed array, Node.js Buffer + var plain = getPlainBuffer(value); + var bytes = []; + for (i = 0, n = Math.min(value.byteLength, 10); i < n; i++) { + t = plain[value.byteOffset + i]; + bytes.push(t < 16 ? "0" + t.toString(16) : t.toString(16)); + } + var preview = bytes.join(" "); + if (value.byteLength > 10) { preview += "..."; } + if (isPlainBuffer(value)) { + if (info[4] === void 0) { + // Fixed buffers have undefined for info[4] + return colorize("buffer", "[Buffer " + preview + "]"); + } else { + return colorize("dbuffer", "[Dynamic Buffer " + preview + "]"); + } } - return colorize("dbuffer", "[Dynamic Buffer " + preview + "]"); + return colorize("buffer", "[" + name + " " + preview + "]"); } if (name === "Pointer") { return colorize("pointer", "[Pointer " + info[1] + "]"); From ca2b18ced05ee58498f739ba6b097f24502e4599 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Thu, 28 Jul 2016 02:38:18 +0300 Subject: [PATCH 08/11] Fix REPL buffer handling to be 2.x compatible --- repl.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/repl.js b/repl.js index b30689c..641030a 100644 --- a/repl.js +++ b/repl.js @@ -16,7 +16,11 @@ uv.read_start(utils.stdin, function (err, chunk) { if (err) { throw err; } if (!chunk) { return uv.read_stop(utils.stdin); } try { - p(eval(chunk.toString())); + if (Duktape.version >= 19999) { + p(eval(String.fromBuffer(chunk))); + } else { + p(eval(chunk.toString())); + } } catch (error) { uv.write(utils.stderr, utils.colorize("error", error.toString()) + "\n"); From 15390a0854c49a2a3c7b3b50fd5c2dcc95551dbd Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Thu, 28 Jul 2016 17:58:36 +0300 Subject: [PATCH 09/11] Add logging extra when using 2.0 --- duktape.cmake | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/duktape.cmake b/duktape.cmake index c5856ef..3e78baf 100644 --- a/duktape.cmake +++ b/duktape.cmake @@ -1,10 +1,22 @@ set(DUKTAPEDIR ${CMAKE_CURRENT_LIST_DIR}/lib/duktape) +if(EXISTS ${DUKTAPEDIR}/extras/logging/duk_logging.c) include_directories( ${DUKTAPEDIR}/src + ${DUKTAPEDIR}/extras/logging ) - -add_library(duktape STATIC ${DUKTAPEDIR}/src/duktape.c) +add_library(duktape STATIC + ${DUKTAPEDIR}/src/duktape.c + ${DUKTAPEDIR}/extras/logging/duk_logging.c +) +else() +include_directories( + ${DUKTAPEDIR}/src +) +add_library(duktape STATIC + ${DUKTAPEDIR}/src/duktape.c +) +endif() if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") target_link_libraries(duktape From 2fc56c1577f330de7b46ed540d281f51ad1ae083 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Thu, 28 Jul 2016 17:58:57 +0300 Subject: [PATCH 10/11] Init logging extra for Duktape 2.x --- src/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.c b/src/main.c index 809c7b5..062d403 100644 --- a/src/main.c +++ b/src/main.c @@ -563,6 +563,11 @@ int main(int argc, char *argv[]) { } loop.data = ctx; + // Logging framework (removed in Duktape 2.x) +#if DUK_VERSION >= 19999 + duk_logging_init(ctx, 0 /*flags*/); +#endif + // Minimal print/alert (removed in Duktape 2.x) #if DUK_VERSION >= 19999 duk_push_global_object(ctx); From 12a978df31804c7001d21961c3b4d141032043f1 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Tue, 2 Aug 2016 04:21:10 +0300 Subject: [PATCH 11/11] Add duk_v1_compat.c for duk_put_function_list() --- duktape.cmake | 4 ++++ src/duv.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/duktape.cmake b/duktape.cmake index 3e78baf..66d7f04 100644 --- a/duktape.cmake +++ b/duktape.cmake @@ -1,13 +1,17 @@ set(DUKTAPEDIR ${CMAKE_CURRENT_LIST_DIR}/lib/duktape) if(EXISTS ${DUKTAPEDIR}/extras/logging/duk_logging.c) +# Duktape 2.x: assume both logging provider and duk-v1-compat exists. +# The duk-v1-compat transition helpers are needed for duk_put_function_list(). include_directories( ${DUKTAPEDIR}/src ${DUKTAPEDIR}/extras/logging + ${DUKTAPEDIR}/extras/duk-v1-compat ) add_library(duktape STATIC ${DUKTAPEDIR}/src/duktape.c ${DUKTAPEDIR}/extras/logging/duk_logging.c + ${DUKTAPEDIR}/extras/duk-v1-compat/duk_v1_compat.c ) else() include_directories( diff --git a/src/duv.h b/src/duv.h index cba9411..c7de45d 100644 --- a/src/duv.h +++ b/src/duv.h @@ -3,6 +3,9 @@ #include "uv.h" #include "duktape.h" +#if DUK_VERSION >= 19999 +#include "duk_v1_compat.h" +#endif #include #if !defined(_WIN32)