Notes /
DuktapeThis page contains notes about issues that came up while developing the Duktape Host. This page is useful for tracking down errors. See Duktape Host for how to use the Duktape host. Todo itemstestCommon.js fails because of 'this'Under Duktape and Node.js, testCommon.js fails because testSpontaneous.js has a missing The this issue is fixed. 4/15/2015 testCommon.js fails because of setIntervalbash-3.2$ ./duktape/duktape/duk duktape/test/testCommon.js loading module: duktape/duktapeHost loading module: duktape/duktapeHost.js loaded Ecmascript: duktape/duktapeHost.js loading module: common/commonHost loading module: common/commonHost.js loaded Ecmascript: common/commonHost.js loading module: common/modules/util.js loading module: common/modules/util.js loaded Ecmascript: common/modules/util.js loading module: common/modules/events.js loading module: common/modules/events.js loaded Ecmascript: common/modules/events.js loading module: duktape/duktape/examples/eventloop/ecma_eventloop loading module: duktape/duktape/examples/eventloop/ecma_eventloop.js loaded Ecmascript: duktape/duktape/examples/eventloop/ecma_eventloop.js loading module: common/test/testCommon loading module: common/test/testCommon.js loaded Ecmascript: common/test/testCommon.js testCommon.js: pathName: ./test/TestAccessor.js testCommon.js: pathName: ../test/TestAccessor.js testCommon.js: returning contents of ../test/TestAccessor.js loading module: common/commonHost.js loading module: common/commonHost.js loaded Ecmascript: common/commonHost.js Instance of TestAccessor: %j Tests: [object Object] Test passed: TestAccessor: getParameter Test passed: TestAccessor: setParameter Test passed: TestAccessor: get Test passed: TestAccessor: get with undefined Test passed: TestAccessor: get with undefined Test passed: TestAccessor: provideInput() TestAccessor.fire() invoked. Test passed: TestAccessor: react, send, and latestOutput testCommon.js: pathName: ./test/TestComposite.js testCommon.js: pathName: ../test/TestComposite.js testCommon.js: returning contents of ../test/TestComposite.js testCommon.js: pathName: ./test/TestGain.js testCommon.js: pathName: ../test/TestGain.js testCommon.js: returning contents of ../test/TestGain.js testCommon.js: pathName: ./test/TestAdder.js testCommon.js: pathName: ../test/TestAdder.js testCommon.js: returning contents of ../test/TestAdder.js Test passed: TestComposite: priority number of destination is higher than source Test passed: TestComposite: composite accessor with manual scheduling Test passed: TestComposite: composite accessor with automatic scheduling testCommon.js: pathName: ./test/TestSpontaneous.js testCommon.js: pathName: ../test/TestSpontaneous.js testCommon.js: returning contents of ../test/TestSpontaneous.js ReferenceError: identifier 'setInterval' undefined duk_js_var.c:1258 anon compile:48 preventsyield call native strict preventsyield anon common/commonHost.js:495 strict anon common/test/testCommon:151 preventsyield require native strict preventsyield global duktape/test/testCommon.js:89 preventsyield error in executing file duktape/test/testCommon.js bash-3.2$ In commonHost.js, line 495 is marked with if (typeof this.exports.initialize === 'function') { // Call with 'this' being the accessor instance, not the exports // property. ----> this.exports.initialize.call(this); }
setInterval and setTimeout duplicate definitionshosts/duktape/duktapeHost.js defines We should be able to properly export these. If clearInterval = ecma_eventloop.clearInterval; setInterval = ecma_eventloop.setInterval; setTimeout = ecma_eventloop.setTimeout; Then we don't get as far: bash-3.2$ ./duktape/duktape/duk duktape/test/testCommon.js loading module: duktape/duktapeHost loading module: duktape/duktapeHost.js loaded Ecmascript: duktape/duktapeHost.js loading module: common/commonHost loading module: common/commonHost.js loaded Ecmascript: common/commonHost.js loading module: common/modules/util.js loading module: common/modules/util.js loaded Ecmascript: common/modules/util.js loading module: common/modules/events.js loading module: common/modules/events.js loaded Ecmascript: common/modules/events.js loading module: duktape/duktape/examples/eventloop/ecma_eventloop loading module: duktape/duktape/examples/eventloop/ecma_eventloop.js loaded Ecmascript: duktape/duktape/examples/eventloop/ecma_eventloop.js loading module: common/test/testCommon loading module: common/test/testCommon.js loaded Ecmascript: common/test/testCommon.js testCommon.js: pathName: ./test/TestAccessor.js testCommon.js: pathName: ../test/TestAccessor.js testCommon.js: returning contents of ../test/TestAccessor.js loading module: common/commonHost.js loading module: common/commonHost.js loaded Ecmascript: common/commonHost.js Instance of TestAccessor: %j Tests: [object Object] Test passed: TestAccessor: getParameter Test passed: TestAccessor: setParameter Test passed: TestAccessor: get Test passed: TestAccessor: get with undefined Test passed: TestAccessor: get with undefined Test passed: TestAccessor: provideInput() TestAccessor.fire() invoked. Test passed: TestAccessor: react, send, and latestOutput testCommon.js: pathName: ./test/TestComposite.js testCommon.js: pathName: ../test/TestComposite.js testCommon.js: returning contents of ../test/TestComposite.js testCommon.js: pathName: ./test/TestGain.js testCommon.js: pathName: ../test/TestGain.js testCommon.js: returning contents of ../test/TestGain.js testCommon.js: pathName: ./test/TestAdder.js testCommon.js: pathName: ../test/TestAdder.js testCommon.js: returning contents of ../test/TestAdder.js Test passed: TestComposite: priority number of destination is higher than source TypeError: undefined not callable duk_js_call.c:776 anon common/commonHost.js:1421 strict anon common/commonHost.js:1229 strict anon common/commonHost.js:1242 strict anon common/test/testCommon:134 preventsyield require native strict preventsyield global duktape/test/testCommon.js:89 preventsyield error in executing file duktape/test/testCommon.js bash-3.2$ In Accessor.prototype.scheduleEvent = function(accessor) { var thiz = this.root; var queue = thiz.eventQueue; // If we haven't already scheduled a react() since the last react(), // schedule it now. if (!thiz.reactRequestedAlready) { thiz.reactRequestedAlready = true; ----> setTimeout(function() { thiz.react(); }, 0); } So, it seems like if setTimeout() is defined in Fixed! The near term solution was to modify ecma_eventloop.js so that the declarations of function setTimeout(func, delay) { became setTimeout = function(func, delay) { The same was done for Also, the fprintf(stderr, "calling EventLoop.run()\n"); fflush(stderr); duk_eval_string(ctx, "EventLoop.run();"); duk_pop(ctx); The modSearch() definition is needed in each file to be loaded.
Possibilities:
In Progress
The idea here is to use the Unix To do this, duktapeHost.h: ../duktapeHost.js xxd -i ../duktapeHost.js duktapeHost.h The top of the unsigned char ___duktapeHost_js[] = { 0x2f, 0x2f, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, to get rid of compile-time warnings, remove the In // duktapeHost.h is created by running // xxd -i ../duktapeHost.js duktapeHost.h fprintf(stderr, "Loading C verison of duktapeHost\n"); duk_eval_string(ctx, ___duktapeHost_js); duk_pop(ctx); fprintf(stderr, "Done loading C verison of duktapeHost\n"); Now, if var testCommon = require("common/test/testCommon"); console.log("duktape/test/testCommon.js: end"); and the following command is run from the Port modules to DuktapeWe should start porting modules to Duktape. Generate JUnit XML Output for the tests.If we could generate JUnit-compatibile output from the Duktape tests, then we could include this in the nightly build. This is lower priority, but it would be helpful require() in DuktapeDuktape supports JavaScript The solution was to modify Duktape's Below is the patch to diff -rc tmp/duktape-1.4.0/examples/cmdline/duk_cmdline.c duktape/duktape/examples/cmdline/duk_cmdline.c *** tmp/duktape-1.4.0/examples/cmdline/duk_cmdline.c 2016-01-09 17:18:06.000000000 -0800 --- duktape/duktape/examples/cmdline/duk_cmdline.c 2016-02-24 18:55:22.000000000 -0800 *************** *** 60,65 **** --- 60,69 ---- #endif #include "duktape.h" + // cxh + extern void fileio_register(duk_context *ctx); + + #if defined(DUK_CMDLINE_AJSHEAP) /* Defined in duk_cmdline_ajduk.c or alljoyn.js headers. */ void ajsheap_init(void); *************** *** 750,755 **** --- 754,761 ---- } #endif + // cxh + fileio_register(ctx); return ctx; } In addition, Also, diff -rc tmp/duktape-1.4.0/Makefile.cmdline duktape/duktape/Makefile.cmdline *** tmp/duktape-1.4.0/Makefile.cmdline 2016-01-09 17:18:06.000000000 -0800 --- duktape/duktape/Makefile.cmdline 2016-02-24 18:54:15.000000000 -0800 *************** *** 6,12 **** DUKTAPE_SOURCES = src/duktape.c DUKTAPE_CMDLINE_SOURCES = \ ! examples/cmdline/duk_cmdline.c CC = gcc CCOPTS = -Os -pedantic -std=c99 -Wall -fstrict-aliasing -fomit-frame-pointer --- 6,13 ---- DUKTAPE_SOURCES = src/duktape.c DUKTAPE_CMDLINE_SOURCES = \ ! examples/cmdline/duk_cmdline.c \ ! examples/eventloop/fileio.c CC = gcc CCOPTS = -Os -pedantic -std=c99 -Wall -fstrict-aliasing -fomit-frame-pointer All of the above changes were checked in to the Accessors repo. The JavaScript side is based on code from http://wiki.duktape.org/HowtoModules.html Below is the version in duktapeHost.js: // The modSearch function is based on code from http://wiki.duktape.org/HowtoModules.html // The license is at https://github.com/svaarala/duktape-wiki, which refers to // https://github.com/svaarala/duktape/blob/master/LICENSE.txt, which is reproduced below // =============== // Duktape license // =============== // (http://opensource.org/licenses/MIT) // Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst) // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE // FIXME: Move the Duktape code elsewhere so as to avoid copyright issues. Duktape.modSearch = function (id, require, exports, module) { /* readFile(): as above. * loadAndInitDll(): load DLL, call its init function, return true/false. */ var name; var src; var found = false; print('loading module:', id); /* DLL check. DLL init function is platform specific. It gets 'exports' * but also 'require' so that it can require further modules if necessary. */ // name = '/modules/' + id + '.so'; // if (loadAndInitDll(name, require, exports, module)) { // print('loaded DLL:', name); // found = true; // } /* Ecmascript check. */ //name = 'modules/' + id + '.js'; name = id + '.js'; print('loading module:', name); src = FileIo.readfile(name); //print('readFile returned', src); print('src is of type', typeof src); if (typeof src === 'string') { print('loaded Ecmascript:', name); return src; } if (typeof src === 'buffer') { print('loaded Ecmascript:', name); return src.toString(); } /* Must find either a DLL or an Ecmascript file (or both) */ if (!found) { throw new Error('module not found: ' + id); } /* For pure C modules, 'src' may be undefined which is OK. */ return src; } require(): cannot resolve module idWhile in var commonHost = require("../common/commonHost"); Results in bash-3.2$ duktape/duk duktapeHost.js TypeError: cannot resolve module id: ../common/commonHost duk_bi_global.c:988 require native strict preventsyield global duktapeHost.js:75 preventsyield error in executing file duktapeHost.js bash-3.2$ The error comes from /* * CommonJS require() and modules support */ #if defined(DUK_USE_COMMONJS_MODULES) DUK_LOCAL void duk__bi_global_resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) { ... resolve_error: DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "cannot resolve module id: %s", (const char *) req_id); } #endif /* DUK_USE_COMMONJS_MODULES */ Adding the following to #define DUK_USE_DEBUG 1 #define DUK_USE_DDPRINT 1 Rerunning the command produces a lot of debugging including: [DD] duk_bi_global.c:932 (duk__bi_global_resolve_module_id): resolve error: term was '..' but nothing to backtrack which comes from if (c == '.' && *p == '/') { /* Term was '..', backtrack resolved name by one component. * q[-1] = previous slash (or beyond start of buffer) * q[-2] = last char of previous component (or beyond start of buffer) */ p++; /* eat (first) input slash */ DUK_ASSERT(q >= buf_out); if (q == buf_out) { DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack")); goto resolve_error; } Solution: Running the command from the directory above and making the paths relative seems to help. Loading util.js failsThe duktape host is failing: (:source lang=bash:) bash-3.2$ pwd /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/hosts bash-3.2$ duktape/duktape/duk duktape/test/testComposite.js loading module: duktape/duktapeHost loading module: duktape/duktapeHost.js loaded Ecmascript: duktape/duktapeHost.js loading module: common/commonHost loading module: common/commonHost.js loaded Ecmascript: common/commonHost.js loading module: util loading module: util.js Error: error error (rc -100) anon native strict preventsyield anon duktape/duktapeHost:58 preventsyield anon native strict preventsyield anon common/commonHost:205 strict preventsyield anon native strict preventsyield anon duktape/duktapeHost:80 preventsyield require native strict preventsyield global duktape/test/testComposite.js:85 preventsyield error in executing file duktape/test/testComposite.js bash-3.2$ Line 205 of commonHost.js is: var util = require('util'); So, the issue here is that we don't have a util module. The solution is covered in Require Discussion. Basically, under Duktape, we require cannot resolve module id: ../commonHost.jsAfter modifying duk_cmdline.c so that it loads in a C version of duktapeHost.js (see The modSearch() definition is needed in each file to be loaded.), then trying to load common/test/testCommon.js fails: bash-3.2$ pwd /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/hosts bash-3.2$ ./duktape/duktape/duk common/test/testCommon.js Loading C verison of duktapeHost loading module: common/commonHost loading module: common/commonHost.js loaded Ecmascript: common/commonHost.js loading module: common/modules/util.js loading module: common/modules/util.js loaded Ecmascript: common/modules/util.js loading module: common/modules/events.js loading module: common/modules/events.js loaded Ecmascript: common/modules/events.js loading module: duktape/duktape/examples/eventloop/ecma_eventloop loading module: duktape/duktape/examples/eventloop/ecma_eventloop.js loaded Ecmascript: duktape/duktape/examples/eventloop/ecma_eventloop.js Loaded duktapeHost.js Done loading C verison of duktapeHost testCommon.js: pathName: ./test/TestAccessor.js testCommon.js: pathName: ../test/TestAccessor.js testCommon.js: returning contents of ../test/TestAccessor.js TypeError: cannot resolve module id: ../commonHost.js duk_bi_global.c:988 require native strict preventsyield global common/test/testCommon.js:68 preventsyield error in executing file common/test/testCommon.js bash-3.2$ Enabling the debugging by editing [DD] duk_bi_global.c:932 (duk__bi_global_resolve_module_id): resolve error: term was '..' but nothing to backtrack which is similar to require(): cannot resolve module id. Because the output is so voluminous, I disabled the debug output. One idea is to try running in different directories, such as the Editing (gdb) r test/testCommon.js Starting program: /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/hosts/duktape/duktape/d\ uk test/testCommon.js Loading C verison of duktapeHost loading module: common/commonHost loading module: common/commonHost.js FATAL 56: uncaught error PANIC 56: uncaught error (calling abort) Program received signal SIGABRT, Aborted. 0x00007fff99058f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib (gdb) where #0 0x00007fff99058f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib #1 0x00007fff84c504ec in pthread_kill () from /usr/lib/system/libsystem_pthread.dylib #2 0x00007fff8acd86e7 in abort () from /usr/lib/system/libsystem_c.dylib #3 0x000000010001fe8e in duk_default_panic_handler (code=56, msg=0x10007903d "uncaught error") at duk_error_macros.c:152 #4 0x0000000000000000 in ?? () (gdb) quit That's not much help, so instead, enabling the debugging by editing loading module: common/commonHost.js [DD] duk_js_call.c:2402 (duk_handle_ecma_call_setup): handle_ecma_call_setup: thr=0x7fec4bc083b0, num_stack_args=1, call_flags=0x00000000 (resume=0, tailcall=0), idx_func=8, idx_args=10, entry_valstack_bottom_index=18 [DD] duk_js_call.c:1201 (duk__handle_call_inner): duk__handle_call_inner: num_stack_args=1, call_flags=0x00000000, top=11 [DD] duk_js_call.c:1247 (duk__handle_call_inner): duk__handle_call_inner: thr=0x7fec4bc083b0, num_stack_args=1, call_flags=0x00000000 (ignorerec=0, constructor=0), valstack_top=11, idx_func=8, idx_args=10, rec_depth=3/1000, entry_valstack_bottom_index=18, entry_callstack_top=3, entry_catchstack_top=0, entry_call_recursion_depth=3, entry_curr_thread=0x7fec4bc083b0, entry_thread_state=2 [DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 0x7fec4bd00880 props (0 -> 50 bytes), from {p=NULL,e_size=0,e_next=0,a_size=0,h_size=0} to {p=0x7fec4bd00940,e_size=2,e_next=0,a_size=0,h_size=0}, abandon_array=0, unadjusted new_e_size=2 [DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 0x7fec4bd00980 props (0 -> 50 bytes), from {p=NULL,e_size=0,e_next=0,a_size=0,h_size=0} to {p=0x7fec4bd009c0,e_size=2,e_next=0,a_size=0,h_size=0}, abandon_array=0, unadjusted new_e_size=2 [DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 0x7fec4bd00980 props (50 -> 82 bytes), from {p=0x7fec4bd009c0,e_size=2,e_next=1,a_size=0,h_size=0} to {p=0x7fec4bd00a00,e_size=2,e_next=1,a_size=2,h_size=0}, abandon_array=0, unadjusted new_e_size=2 [DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 0x7fec4bd00980 props (82 -> 114 bytes), from {p=0x7fec4bd00a00,e_size=2,e_next=1,a_size=2,h_size=0} to {p=0x7fec4bd00a60,e_size=2,e_next=1,a_size=4,h_size=0}, abandon_array=0, unadjusted new_e_size=2 [DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 0x7fec4bd00980 props (114 -> 146 bytes), from {p=0x7fec4bd00a60,e_size=2,e_next=1,a_size=4,h_size=0} to {p=0x7fec4bd009c0,e_size=2,e_next=1,a_size=6,h_size=0}, abandon_array=0, unadjusted new_e_size=2 [DD] duk_hobject_props.c:867 (duk__realloc_props): resized hobject 0x7fec4bd00980 props (146 -> 178 bytes), from {p=0x7fec4bd009c0,e_size=2,e_next=1,a_size=6,h_size=0} to {p=0x7fec4bd00ae0,e_size=2,e_next=1,a_size=8,h_size=0}, abandon_array=0, unadjusted new_e_size=2 [DD] duk_error_augment.c:104 (duk__err_augment_user): error handler does not exist or is not a plain value: NULL [DD] duk_error_augment.c:104 (duk__err_augment_user): error handler does not exist or is not a plain value: NULL [DD] duk_js_executor.c:867 (duk__handle_longjmp): handling longjmp: type=1, value1={message/10:"error error (rc -100)"/1}, value2=undefined, iserror=0 [DD] duk_error_augment.c:104 (duk__err_augment_user): error handler does not exist or is not a plain value: NULL So, the problem here is that we have no error handler. http://duktape.org/guide.html#error-handling is useful. Solution: use // Use duk_peval_string_noresult() and avoid interning the string. Good // for low memoroy, see // http://duktape.org/api.html#duk_peval_string_noresult if (duk_peval_string_noresult(ctx, ___duktapeHost_js) != 0) { printf("%s:%d: Loading C version of duktapeHost failed\n", __FILE__, __LINE__); } else { printf("%s: Loading C version of duktapeHost worked\n", __FILE__); } Now, we get a better error message: bash-3.2$ cd common/ bash-3.2$ ../duktape/duktape/duk test/testCommon.js examples/cmdline/duk_cmdline.c Loading C verison of duktapeHost loading module: common/commonHost loading module: common/commonHost.js examples/cmdline/duk_cmdline.c:960: Loading C version of duktapeHost failed testCommon.js: pathName: ./test/TestAccessor.js testCommon.js: pathName: ../test/TestAccessor.js testCommon.js: pathName: ../../test/TestAccessor.js testCommon.js: returning contents of ../../test/TestAccessor.js TypeError: cannot resolve module id: ../commonHost.js duk_bi_global.c:988 require native strict preventsyield global test/testCommon.js:68 preventsyield error in executing file test/testCommon.js bash-3.2$ The problem is that duktapeHost contains var commonHost = require("common/commonHost"); when we run the
|