svaarala / duktape Goto Github PK
View Code? Open in Web Editor NEWDuktape - embeddable Javascript engine with a focus on portability and compact footprint
License: MIT License
Duktape - embeddable Javascript engine with a focus on portability and compact footprint
License: MIT License
Hello.
I'm looking for a compact, JavaScript-compatible regular expression parser written in C, and Duktape has one!
Any thoughts regarding what it would take for me to extract the regular expression parsing into its own library? My assumption would be that it's likely tightly coupled to Duktape internals. Before I go slicing and dicing code, I was wondering if you might have any pointers.
Motivation (long-winded):
I work in the Web API space. I focus a lot on what's called hypermedia APIs, a technology heavily based on the way the Web works today. As part of this effort, I've been thinking about API servers providing API clients with regular expressions for the purpose of input field validation (much like HTML forms today). Unfortunately, every programming language has its own version of regular expression syntax, and therefore, every client would need a common ground syntax/parser for sharing regular expressions. I would like that common ground to be the JavaScript implementation of regular expressions. This would mean all Web browsers would Just Work.
To accomplish this, my thought was to have an independent JavaScript-compatible regular expression parser written in C. This would allow me to plug in to different language runtimes and platforms (including iOS and Android).
I'd love to be able to get more milage off the hard work you've already done implementing this feature for Duktape.
Overall, I think this project is really awesome, and I'll be keeping an eye on it either way.
Cheers!
The indirect types (such as duk_int_t
) map in a straightforward way to basic types on C99 platforms.
Since most developers work with such platforms, it's probably less confusing to use these concrete types (e.g. int
instead of duk_int_t
) in the public documentation, and provide separate documentation for platforms where this is not the case. The API hover hints could still refer to the internal typing.
Support a named property handler & a indexed property handler like V8.
(http://izs.me/v8-docs/classv8_1_1ObjectTemplate.html)
Although Object dont have some property, SHOULD process this property.
for example,
var obj = {age:20}
var name = obj.name;
// When call name which don't register a property, Duktape should call named property handler which is a function.
I think some API.
like this one.
...(push target object) ...
.. (push get function object) ...
.. (push set function object) ...
duk_set_named_property(ctx,-3);
or
duk_set_indexed_property(ctx,-3);
Hi! I have a simple idea:
Why not making the error strings of duk_require_xxx functions a little more verbose by including the stack index.
For example, when doing duk_require_int(ctx, 0) in place of "not a number" we would have "stack id 0: not a number"
(In duktape.c, "not a number" will become "stack id %d: not a number")
Thanks :)
Hi again!
I think it will nice to also have at least the function name in a c function object.
You say that it will be memory consuming in the guide. It could be true for embeded envs but not for desktop (some more bytes for each c function isn't so big).
What if this behaviour could be activated at compile time with a macro?
Thanks again :)
var a = !enabled;
always returns false from my virtual proxy object 'enabled', where I implemented function valueOf, and I duk_push_boolean in that handler, and whether I return false or true, makes no difference. likely because valueOf is not triggered/trapped/invoked. Hypothesis: it thinks we are testing for 'not null' or 'not undefined'.
Q. is it impossible to emulate an ecma primitive in this case by over-riding valueOf?
Thanks,
-Doug
According to the duktape docs (and JS modules in general afaik) require('./something')
should prefix the ID with the current module ID minus the last component
so, as according to the docs:
// foo/bar.js
var text = 'Hello world!'; // not visible outside the module
var quux = require('./quux'); // loads foo/quux
exports.hello = function () {
print(text);
};
Should invoke modSearch with foo/quux
That seems not to be the case though :-(
From debug log:
[DDD] duk_bi_global.c:947 (duk_bi_global_object_require): resolve module id: requested="./quux"/3, currentmodule="foo/bar"/8
[DDD] duk_bi_global.c:832 (duk__bi_global_resolve_module_id): input module id: 'foo/bar/./quux'
[DDD] duk_bi_global.c:846 (duk__bi_global_resolve_module_id): resolve loop top: p -> 'foo/bar/./quux', q=0x7fff726f3d70, buf_out=0x7fff726f3d70
[DDD] duk_bi_global.c:846 (duk__bi_global_resolve_module_id): resolve loop top: p -> 'bar/./quux', q=0x7fff726f3d74, buf_out=0x7fff726f3d70
[DDD] duk_bi_global.c:846 (duk__bi_global_resolve_module_id): resolve loop top: p -> './quux', q=0x7fff726f3d78, buf_out=0x7fff726f3d70
[DDD] duk_bi_global.c:846 (duk__bi_global_resolve_module_id): resolve loop top: p -> 'quux', q=0x7fff726f3d78, buf_out=0x7fff726f3d70
[DDD] duk_alloc_default.c:15 (duk_default_alloc_function): default alloc function: 45 -> 0x2278a50
[DDD] duk_heap_stringtable.c:70 (duk__alloc_init_hstring): interned string, hash=0x5e5435f1, blen=12, clen=12, has_arridx=0
[DDD] duk_heap_stringtable.c:113 (duk__insert_hstring): insert hit (null): 567
[DDD] duk_bi_global.c:954 (duk_bi_global_object_require): resolved module id: requested="./quux"/3, currentmodule="foo/bar"/8, result="foo/bar/quux"/1
I would expect the result on the last line to be foo/quux
?
Hello! Thank you for this great lib!
What do you think of making all data outputed from print, alert and error handlers be redirected to a user-defined callback?
It will be something like: void outputCallback (duk_context* ctx, const char* data, size_t data_size, int data_type, void* user_data)
Thanks
Various cleanups to be implemented in 0.12.0 stabilization release or 1.0.0 release at the latest.
API cleanups and additions:
duk_xcopy_top()
and duk_xmove_top()
Portability and other fixes:
__declspec(dllexport)
and __declspec(dllimport)
duk_peval_file()
fix: throws an error if file does not existFile and directory reorganization, to improve merges after release:
duk_api*
filesWebsite documentation:
Because 0.11.0 has been in production use by multiple parties by now, major changes such as the following will be avoided:
duk_js_compiler.c
and duk_hobject_props.c
): postponed because there are multiple work branches that would need awkward rebasingDetailed issues are tracked with Ditz.
This code
var g = {};
Duktape.fin(g, function(o) {print('fin')});
new Proxy(g, {});
Outputs 'fin' twice which seems wrong to me.
Hi again!
I think it will nice to also have at least the function name in a c function object.
You say that it will be memory consuming in the guide. It could be true for embeded envs but not for desktop (some more bytes for each c function isn't so big).
What if this behaviour could be activated at compile time with a macro?
Thanks again :)
It would be cool, when someone can make a CMake file for this project to simplify win/macosx and linux build :)
Currently duk_features.h.in
detects all platforms Duktape works on, which is non-modular and becomes progressively more difficult to maintain over time. In addition to standard platforms (C99 or close) there are exotic platforms which require much more hackery than others, and closed platforms which may never get support in the mainline as the toolchain may not be publicly available. At the moment several users need to maintain a patch for Duktape to get the feature detection come out right.
The user should be able to provide a custom header which would cause Duktape to skip all platform detection and rely on the user header for platform feature detection, inclusion of system headers, etc. This allows more exotic and closed platforms to be supported without making the mainline source more difficult to maintain.
On a related note, it would be nice to be able to provide the necessary functions to support the Date built-in outside of the master branch. Date built-in is a major component which often needs platform modifications, and collecting all the variants in the mainline is awkward in the longer term.
Q. How to do the following js from the C API:
var proxy = new Proxy(target,handler);
and do it more directly than using eval_string:
duk_eval_string(ctx,"var proxy = new Proxy(target,handler);");
Thanks,
-Doug
more .. I tried the following in C
// iglobal = + index of global object: target and handler are defined there
// assume Proxy is defined in the global object
duk_push_object(ctx); //to get the 'new'?
rc = duk_get_prop_string(ctx,iglobal,"Proxy");
rc = duk_get_prop_string(ctx,iglobal,"target");
rc = duk_get_prop_string(ctx,iglobal,"handler");
//duk_call_method(ctx,2); //bombs
duk_call(ctx,2); //bombs
duk_put_prop_string(ctx,-1,"proxy");
Hi, :) I have some questions.
Q) How to Implement the Inheritance for Duktape?
for example,
Like Spider monkey,
has API named "JSObject * JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent);".
When to create object, Spider monkey inserts a proto into API(JS_NewObject).
Thanks for duktape.
duk_bi_global_object_require
uses the function duk_eval
(duk_bi_global.c:1079) to compile the source returned by the modSearch function. Since duk_eval is defined as,
#define duk_eval(ctx) \
((void) duk_push_string((ctx), __FILE__), \
(void) duk_eval_raw((ctx), NULL, 0, DUK_COMPILE_EVAL))
the stack frames for functions loaded through require(...)
will show the source file as duk_bi_global.c.
I came up with the following fix (replace duk_bi_global.c:1079) but I don't know if this is the "right" solution or not:
duk_dup(ctx, 3);
duk_eval_raw(ctx, NULL, 0, DUK_COMPILE_EVAL);
This uses the resolved module ID as the filename for duk_eval_raw instead.
Hello,
We are tripping an "Invalid decimal escape" with this code (from rainbow.js)
'pattern': /(\(|\s|\[|\=|:|\+|\.)(('|")([^\\\1]|\\.)*?(\3))/gm
I am not super up on all the ins and out of js regex, but this seems to parse in Chrome. Do you have any ideas? Here's the relevant parser code:
} else if (DUK__ISDIGIT(x)) {
/* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */
if (x == 0 && !DUK__ISDIGIT(DUK__L0())) {
ch = 0x0000;
} else {
DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
"invalid decimal escape");
}
}
On release build I have:
duk_bi_math.c(207): error C2099: initializer is not a constant
/* order must match constants in genbuiltins.py */
static const duk__one_arg_func duk__one_arg_funcs[] = {
DUK_FABS,
DUK_ACOS,
DUK_ASIN,
DUK_ATAN,
DUK_CEIL,
DUK_COS,
DUK_EXP,
DUK_FLOOR,
DUK_LOG,
duk__round_fixed,
DUK_SIN,
DUK_SQRT,
DUK_TAN
};
Debug build works.
When i change the compiler settings to "/fp:strict" then it builds. But I don't have analysed the reason.
VS2013 help:
http://msdn.microsoft.com/query/dev12.query?appId=Dev12IDEF1&l=EN-US&k=k(C2099);k(vs.output)&rd=true
Duktape's current module support is very minimal, mainly to keep the default code/memory footprint low, and to minimize any platform portability issues. Duktape's built-in require()
handles the usual tasks of module name resolution and normalization, and presents modSearch()
with a normalized, absolute module ID. The user implements modSearch()
in a platform specific manner, and these is no standard loader.
One obvious need would to include a standard loader with Duktape, which would provide out-of-the-box module loading functionality that would be similar to Lua's or Node's. In other words: support for search paths, support for loading Ecmascript code from files, support for DLLs (including a convention on DLL init function naming and initialization), etc. This would be quite useful so that C files (modules) written by different people would work nicely together and it would be possible to add modules simply by dropping in DLLs, and perhaps approach something like npm.
Adding this support to the core Duktape code is somewhat awkward: Duktape needs to work on systems with wildly different DLL models (or no DLL support at all), and some systems don't even have a traditional file system. Adding module loader features narrows the range of platforms it works on, and vice versa, so there might be some pull on what features to include or exclude. (This problem already exists for the Duktape API calls which load data from files or write to stdout
, some people want that disabled.)
The best compromise I've come up so far would be to write a "standard" loader for major platforms (Linux, Windows, OSX), along with DLL conventions, search path functionality etc, and ship that loader as an optional part in the end user distributable. It can be endorsed as being the strongly preferred default loader, but won't cause portability issues for those custom low end platforms.
See #60 for proposed changes to the current modSearch()
model, prototyped with Dukluv.
OS: Ubuntu 12.04
gcc: 4.6.3 and 4.8.2
gcc -o duk.raw -pedantic -ansi -std=c99 -Wall -fstrict-aliasing -Wextra -I./dist/src -DDUK_OPT_SEGFAULT_ON_PANIC -DDUK_OPT_DPRINT_COLORS -DDUK_OPT_SELF_TESTS -DDUK_OPT_DEBUG_BUFSIZE=512 -Os -fomit-frame-pointer -g -ggdb dist/src/duktape.c dist/examples/cmdline/duk_cmdline.c -lm -lreadline -lncurses
duk_builtins.c:297:39: warning: ISO C forbids empty initializer braces [-Wpedantic]
duk_builtins.c:297:19: error: zero or negative size array ‘duk_initjs_data’
make: *** [duk.raw] Error 1
Works fine with clang and pedantic removed.
Q. how do I get my custom proxy target attributes when the proxy is on the RHS in a setter (ie I don't have a this pointer on the stack as in a get handler)?
Thanks,
-Doug
more..
I set attributes on my proxy target during construction:
duk_eval_string(ctx,"Proxy");
duk_push_this(ctx); //this
duk_push_int(ctx,itype); //my custom attribute
duk_put_prop_string(ctx,-2,"fwItype"); //and its name put on this (proxy target)
duk_eval_string(ctx,"handler");
duk_new(ctx,2); /* [ global Proxy target handler ] -> [ global result ] */
and I can retrieve them in a get handler when the proxy is on the LHS (left hand side):
duk_get_prop_string(ctx,0,"fwItype");
itype = duk_get_int(ctx,-1);
duk_pop(ctx);
where they seem to be on the 'this' object in the get handler.
But how do I get those attributes when I'm not in a handler for the Proxy - for example when the proxy object is on the RHS in an accessor?
duk_get_prop_string(ctx,0,"fwItype");
printf(duk_type_to_string(duk_get_type(ctx, -1))); //UNDEFINED
itypeRHS = duk_to_int(ctx,-1); //0
duk_pop(ctx);
We're looking into integration Duktape, and one thing we want to make sure we have is debugging support, at least in the future.
At a basic level, if there were even just mechanisms to set breakpoints, that would be sufficient. We would just the existing facilities to "inspect" the current stack, etc.
Is this something that is on the roadmap, or that you would be agreeable to if somebody added it?
The crash occurs in duk_hthread_create_builtin_objects() at
DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
and might be a result of a bogus return value from
ret = DUK_TVAL_GET_HEAPHDR(tv);
in duk_get_tagged_heaphdr_raw().
The return value reads "0xfff6000006b942c0" which looks like half of a value address (other values in the debugger read "0x0000000006b92550" etc.) Makes me suspect a 64-bit issue...?
Stack trace (partial) follows. I have duktape.lib linked into a C++ DLL.
osgdb_osgearth_scriptengine_javascriptd.dll!duk_hthread_create_builtin_objects(duk_hthread * thr) Line 39660 + 0x8 bytes C
osgdb_osgearth_scriptengine_javascriptd.dll!duk__init_heap_thread(duk_heap * heap) Line 30170 C
osgdb_osgearth_scriptengine_javascriptd.dll!duk_heap_alloc(void * (void _, unsigned _int64) alloc_func, void * (void _, void *, unsigned _int64) realloc_func, void (void , void *) free_func, void * alloc_udata, void (void , int, const char *) fatal_func) Line 30425 + 0xa bytes C
osgdb_osgearth_scriptengine_javascriptd.dll!duk_create_heap(void * (void _, unsigned _int64) alloc_func, void * (void _, void *, unsigned _int64) realloc_func, void (void , void *) free_func, void * alloc_udata, void (void , int, const char *) fatal_handler) Line 13768 + 0x23 bytes C
Thanks.
NOTE: this emscripten test is incomplete (compiles hello_world.cpp and tries to run it, no checks yet)
emscripten/emcc -s USE_TYPED_ARRAYS=0 emscripten/tests/hello_world.cpp -o /tmp/duk-emcc-test.js
ERROR root: Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended, see https://github.com/kripken/emscripten/wiki/LLVM-Backend
Traceback (most recent call last):
File "emscripten/emcc", line 1278, in
raise e
AssertionError: fastcomp assumes ta2
make: *** [emscriptentest] Error 1
Is this a known issue.
Q.is there a duktape API method for setting a C function setter and getter on a property?
Or can you direct me to some sample code if it takes a compound series of API calls?
Or how would I do it in the prototype constructor in js?
Or where would I hack in duktape.c to add one?
Thanks for any tips, links, thoughts.
-Doug
more..
I'm working on a platform port of freewrl.sourceforge.net virtual reality player (like a game engine) to windows 8.1 app store (versus desktoo). freewrl win32 desktop currently uses spidermonkey/libmozjs 185 - lovely, nice Class instancing API, including detailed property definition,
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_Cookbook
/* JSAPI */
if (!JS_DefineProperty(cx, obj, "prop", JSVAL_VOID,
(JSPropertyOp) GetPropFunc, (JSStrictPropertyOp) SetPropFunc,
JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS | JSPROP_ENUMERATE)) {
return JS_FALSE;
}
which includes giving non-default C getters/setters on properties, Porting SM or V8 is more than I want to do, and I don't see scripting engines available for the platform -ms js engine appears to be unavailable. Windows app store 8.1 API breaks a lot of opensource libraries. I've worked through them all for freewrl except the javascript engine..
more..
Duktape / ecma5.1 is perhaps sufficient for what we need -I'm going through now to see how to port from SM to duktape. For our case all js is run from one thread -like a game engine looping, at one point in the loop we go through all the script contexts running functions one at a time. Each function is defined at the top level in the context, and the scene/.js author has to name their function the same as their variable defined outside the function, so we know what function to run.
http://www.web3d.org/files/specifications/19775-1/V3.3/Part01/components/scripting.html#Script
At least on OS X (and perhaps elsewhere), use of setjmp
incurs approximately a two times slow down of Duktape, compared to using _setjmp
or sigsetjmp(..., 0)
(as measured using e.g. the fib.js example program). This is because setjmp
and longjmp
save and restore the signal mask, which seems to be unnecessary for duktape. You might like to consider making use of sigsetjmp
/siglongjmp
a build time option. It also requires changing the jmpbuf
in duk_jmpbuf
to a sigjmpbuf
. (It's worth noting that on higher optimisation levels with the Yosemite clang compiler sigsetjmp
results in segfaults; I didn't do an in depth investigation as to the cause).
it looks like i cannot fix via JS so I've tried and failed via C script.
I had to fix it manually in JS via
with ({reassign: function (original) {
var
base = [null],
slice = base.slice
;
return function (cb, delay) {
return original(
arguments.length < 3 ?
cb :
cb.bind.apply(cb, base.concat(slice.call(arguments, 2))),
delay || 0
);
};
}}) {
setTimeout = reassign(setTimeout);
setInterval = reassign(setInterval);
}
otherwise any attempt to do this will miserably fail
setTimeout(function (str) { print(str) }, 1000, 'something');
// or just …
setTimeout(print, 1000, 'something');
I have proxy objects. I have a get handler for them. Some of my proxy object represent array-like objects. If I go
myscalar = myproxy[1]; //panic alert/bombs, my get handler never sees it
If I go:
myscalar = myproxy['1']; //my get handler gets "1" key
But my application is to support an opensource file format, and that means conforming to a large existing body of files, which use the normal array indexing syntax.
Q. have you ever seen this before? What am I supposed to do?
Is there a special getindex handler I need to supply on my proxy object?
Thanks,
Doug
The following program trips into, perhaps two different, issues related to tail calls it seems.
Tested using duktape v0.10.0-198-ga85fa55 (Scroll down to see the actual problems)
#include <stdio.h>
#include "duktape.h"
#define STRINGIFY(A) #A
const char *prog =
STRINGIFY(
function invokator(fun, obj, args)
{
var t = new Duktape.Thread(function() {
fun.apply(obj, args);
return "foobar";
});
var z = Duktape.Thread.resume(t);
return z;
}
function f(x) {
print(x);
}
function y() {
var v = invokator(f,this,[3]);
return v;
}
);
/**
*
*/
void
dump_err(duk_context *ctx)
{
duk_get_prop_string(ctx, -1, "name");
const char *name = duk_get_string(ctx, -1);
duk_get_prop_string(ctx, -2, "message");
const char *message = duk_get_string(ctx, -1);
duk_get_prop_string(ctx, -3, "fileName");
const char *filename = duk_get_string(ctx, -1);
duk_get_prop_string(ctx, -4, "lineNumber");
int line_no = duk_get_int(ctx, -1);
duk_get_prop_string(ctx, -5, "stack");
const char *stack = duk_get_string(ctx, -1);
printf("%s (%s) at %s:%d\n",
name, message, filename, line_no);
printf("STACK DUMP: %s\n", stack);
duk_pop_n(ctx, 5);
}
int
main(void)
{
duk_context *ctx = duk_create_heap_default();
int rc;
printf("%s\n", prog);
if(duk_pcompile_string(ctx, 0, prog)) {
printf("compile fail: %s\n", duk_safe_to_string(ctx, -1));
exit(1);
}
rc = duk_pcall(ctx, 0);
if(rc) {
dump_err(ctx);
exit(1);
}
duk_pop(ctx);
duk_push_global_object(ctx);
duk_get_prop_string(ctx, -1, "y");
rc = duk_pcall(ctx, 0);
if(rc) {
dump_err(ctx);
exit(1);
}
printf("Final result: %s\n", duk_safe_to_string(ctx, -1));
}
The program listing below works as is and outputs
foobar
when run, as expected.
However, changing:
function y() {
var v = invokator(f,this,[3]);
return v;
}
into
function y() {
return invokator(f,this,[3]);
}
results in
...
[DDD] duk_js_call.c:1906 (duk_handle_ecma_call_setup): is tailcall, reusing activation at callstack top, at index 0
PANIC 54: assertion failed: (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0 (duk_js_call.c:1914) (calling abort)
Abort trap: 6
I assume it just shouldn't to tail call optimisation when the current activation is a native call?
Also I discovered another issue when trying to narrow down this.
Changing
var z = Duktape.Thread.resume(t);
return z;
into
return Duktape.Thread.resume(t);
will make the problem output
undefined
No idea if these are related or not, but to me it sounds like some kind of tail call issues as well.
When i try to run the following:
var a = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
then i have the following error:
SyntaxError: invalid regexp escape (line 1)
duk_lexer.c:1787
But this runs on v8.
Here you find the original code:
https://github.com/mbostock/d3/blob/master/src/format/requote.js
I would like to use the idiom
value = myObject['key'];
where the property getter is bound to a C function, i.e. the above code would ultimately invoke something like the C method below. Is there a way to do that in duktape?
void myObjectGetter(duk_context* ctx)
{
void* objPtr = duk_require_pointer(ctx, 0);
const char* key = duk_require_string(ctx, 1);
duk_push_string(ctx, something(objPtr , key));
return 1;
}
stdint.h is a quite simple and common header. These days, even MSVC has it. It's not necessary to have a terrible ifdef orgy that has to be part of the public header.
Instead of reinventing stdint.h in the duktape headers (badly), the public API should just include stdint.h, and use these standard types directly. For systems which don't provide stdint.h, you could easily provide an "emulated" but otherwise standard stdint.h - or just require the user to provide stdint.h somehow. This way you could keep the "portability" kludge out of your headers, and avoid bothering the user with your stdint.h replacements. You also don't annoy the user with the fact that you forgot some parts of stdint.h and inttypes.h, like exact printf format specifiers.
When it comes to portability, it's generally better to use standard C and POSIX features first, and then provide separate emulation of them for other systems. Look how bloated and buggy OpenSSL became because they did the opposite (making up their own abstractions for portability).
(I bet there aren't many real systems where stdint.h is really missing.)
As for things like duk_int_t, I believe you could avoid having it in the public API. Either drop support for bcc (and assume int is always at least 32 bit), or use the type long. The docs say duk_int_t is needed to get a "fast" at least 32 bit type, but whatever speed difference there may be, it's probably not important for the public API. Rather, it would be desirable to reduce possible sources of bugs in user programs by not forcing them to use typedefs mapped to unknown types.
There's a mention of this in the documentation in the section on differences vs. Lua, but it doesn't say whether this capability is planned?
It would be immensely useful to have some kind of 'magic' value paired with pointer values so the native code can perform checks that it's an expected type that's passed (or even act differently on different internal objects that's being pointed to).
I'm not sure if this can be made to fit within duk_tval or not.
The other option is of course that all native objects exposed to duktape start with some kind of class or vtable pointer so the native code can figure out what's what. I'm fine with this option as well but before starting to implement that I would just want to know if the pointer magic is something you've considered implementing.
Hello,
i try to use duktape from julia (http://julialang.org/), actually i'm trying to write a language binding. The interface uses something like dlopen so the library is expected as .so.
So simply i go (duktape-0.11.0) to src and run manually (flags copied from Makefile.example)
lobi@maroon:~/juliarepo/duktape-0.11.0/src$ gcc -Os -pedantic -std=c99 -Wall -fstrict-aliasing -fomit-frame-pointer -fPIC -c duktape.c
get a duktape.o which unfortunately misses a duk_eval_string
lobi@maroon:~/juliarepo/duktape-0.11.0/src$ nm duktape.o | grep eval_
00028ddd T duk_eval_raw
00002981 t duk__get_timeval_from_dparts
000185b8 t duk__push_this_get_timeval_tzoffset
0001e50f t duk__set_this_timeval_from_dparts
000016c5 t duk__timeval_to_parts
Wishing a happy day,
Andreas
In the Callback function.
static int sample_callback(duk_context *ctx) {
duk_push_this(ctx);
duk_get_prop(ctx,-1);
}
If call duk_get_prop function, pop this object into the stack.
stack result.
//(property)
But i guess that correct result
//(this object)(property)
The current internal property approach is not ideal for sandboxing untrusted code. The sandbox must prevent user code from creating or using buffer values, because a buffer value can be used to construct a non-UTF-8 string which can then be used to access internal properties of objects. Depending on the writability of the internal properties, this may or may not be a sandboxing security issue.
This limitation is OK for sandboxing standard Ecmascript code which needs no access to buffer values at all. But there are also sandboxed environments where buffer values need to be available.
Not sure what's the best fix for this. A few possibilities:
undefined
and attempt to write would throw an error).Somewhat unrelated, an alternative to using a \xFF
prefix would be to add a new non-standard "hidden" attribute to object properties. A hidden property would behave like an internal property does now, but would not need to have a special form. This cannot be implemented as a duk_hstring
flag because a certain property name may be a hidden property in one object but not in another.
When using duk_dump_context_stdout() i stumbled on a bug. The following program crashes (only when compiled with -O2 though)
#include "duktape.h"
int
main(void)
{
duk_context *ctx = duk_create_heap_default();
duk_push_sprintf(ctx, "%4000.s", "");
printf("%s\n", duk_safe_to_string(ctx, -1));
duk_push_context_dump(ctx);
printf("%s\n", duk_safe_to_string(ctx, -1));
return 0;
}
AFAIK re-using a va_list again (like duk_push_vsprintf() does) is not safe. It needs to be copied first. Funny enough it does not crash during the first duk_push_sprintf() but only when called via duk_push_context_dump(). I suppose that's due to some inline effect.
The following patch fixes the crash. va_copy() is C99 though so I suppose it can't be accepted as-is. One option would perhaps be to use va_copy() if available (C99 or C++11 i think) and if not available, either revert to a simple value copy or not doing any copy at all. Not sure.
diff --git a/src/duk_api.c b/src/duk_api.c
index ffdcfd8..f856546 100644
--- a/src/duk_api.c
+++ b/src/duk_api.c
@@ -2657,6 +2657,7 @@ const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
void *buf;
int len;
const char *res;
+ va_list copy;
DUK_ASSERT(ctx != NULL);
@@ -2678,7 +2679,9 @@ const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
buf = duk_push_dynamic_buffer(ctx, sz);
for (;;) {
- len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap);
+ va_copy(copy, ap);
+ len = duk__try_push_vsprintf(ctx, buf, sz, fmt, copy);
+ va_end(copy);
if (len >= 0) {
break;
}
var x = Browser.getSomething(44);
My Browser is a lazy/uncached proxy wrapping static C content, and in the proxy I have c handlers for get and set, and they seem to be working for accessor properties, and I know what to return for those.
In my c get handler I also see my 'getSomething' come in as the key.
Q1. is get: the right proxy handler for method calls, or is there some other apply: or Invoke: handler I'm supposed to be using/over-riding for methods?
Q2. what kind of object should I be returning here - my parameter ie 44 doesn't seem to be on the stack, so am I right that it's not attempting the method call here, but rather looking for something like a function object or function proxy to be returned?
Thanks, Doug
These constructs currently prevent yielding a coroutine:
Function.prototype.call()
or Function.prototype.apply()
Will these restriction loosen in the future? Do you have a timeframe? For me the most important are the ones in bold above, as they can occur in third-party code.
I finally started writing libuv bindings to duktape and hid a pretty hard wall. Libuv is callback based. One function like uv_timer_start
will accept a C struct uv_timer_t
and a C function pointer and return without blocking. Then later on while the process is blocked inside uv_run
it will call the C function with the struct as context. I am able to store the duk_context
just fine inside the uv_timer_t
since it has a void*
data property. The problem is I can't seem to store the ecmascript function anywhere in C and call it later.
In lua, I use luaL_ref
and luaL_unref
. Now there is no reason this can't be done in userspace (meaning my app and not internal to duktape). The luaL_*
functions all use the public lua APIs and simply provide sugar. The general idea is to store the object as a property of some global array and track which integer offsets are being used.
I'll post my implementation here when done.
Duktape main repository development Makefile is Linux oriented, but supports Cygwin minimally (you can make dist
with Cygwin, provided you have JDK and ant
installed). This Makefile is used for developing Duktape itself, and is not a portable end-user Makefile.
There is no official Makefile or build script in the distributable. This is intentional: it would be quite a maintenance hassle to provide one for every platform and toolchain where Duktape is used.
However, it would be nice if the distributable package included example build files for various environments and toolchains.
Add an API call to get a borrowed void *
typed reference to an internal duk_hobject *
. This reference could then be stored in native C structs etc, provided that the Duktape object remains reachable at all times. This might be a more convenient model for state maintenance than just using the stash objects with string keys.
Borrowed references are a bit error prone though. But note that the current duk_context
pointer is a borrowed reference to a thread, which must remain reachable at all times.
See discussion in #43.
Q. For proxies do I need to assign more handlers -like has,get,set,deleteProperty- for Object.keys, Object.iterator (over keys for enumeration?), hasOwnProperty(s), or would these come into my get handler and I would return something from there? (for example push_array to return a list of keys?)
Thanks,
Doug
Hi!
I am not sure if I just missed something or did something wrong when I tried, but is it currently possible to add a property to a Duktape/C function object? Here some example code:
duk_context * context = duk_create_heap_default();
duk_idx_t objIndex = duk_push_object(context);
duk_idx_t funcIndex = duk_push_c_function(context, myFunction, 0);
duk_push_int(context, 42);
duk_dump_context_stderr(context); // ctx: top=3, stack=[{},{_func:true},42]
duk_put_prop_string(context, funcIndex, "property");
duk_dump_context_stderr(m_context); // ctx: top=2, stack=[{},{_func:true}]
There the integer just "disappeared", instead of becoming a property of the function object.
However, if I'd assign it to an object instead of the function object:
duk_context * context = duk_create_heap_default();
duk_idx_t objIndex = duk_push_object(context);
duk_idx_t funcIndex = duk_push_c_function(context, myFunction, 0);
duk_push_int(context, 42);
duk_dump_context_stderr(context); // ctx: top=3, stack=[{},{_func:true},42]
duk_put_prop_string(context, objIndex, "property");
duk_dump_context_stderr(m_context); // ctx: top=2, stack=[{property:42},{_func:true}]
everything works like expected. Any hints for this, what I missed here? Or is it just not supposed to be possible to add a property to a Duktape/C function object?
I really enjoyed working with the library so far by the way, great work!!
Some thing i'd really like to have is a helper to dump the current stack to stdout. Would be helpful during development just to verify that you havent screwed up layout of the stack or so.
duk_push_int(ctx, 123);
duk_push_int(ctx, 456);
duk_push_string(ctx, "foobar");
duk_print_context(ctx);
would print
[123, 456, "foobar"]
to stdout.
In Duktape 1.0 there is no mechanism for defining an accessor from C code directly. The current workaround is documented in #13.
Somewhat related, there is currently no way to control property attributes (writability, enumerability, configurability) from C code. Duktape has an internal primitive to define properties but it's not currently exposed as it bypasses normal Ecmascript semantics (being an internal primitive). It also doesn't have accessor support right now, there's very little need for it internally.
One alternative to adding an accessor API would be to implement a general C binding for Object.defineProperty()
with accessor support. The primitive could obey the Ecmascript property attribute semantics by default, but could have a flag for bypassing them so that the same primitive could be used internally.
Stuff to work out:
duk_define_property()
is nice and explicit but it differs from the other property call names. Using duk_def_prop()
would be logical but that's already used internally; this could be fixed with a rename internally. There are currently no convenience variants (like duk_put_prop_string()
for duk_put_prop()
). => Renamed to duk_def_prop()
.Object.defineProperty()
which is of course slow. Rework duk_define_property()
, Object.defineProperty()
, and Object.defineProperties()
so that the implementation is more direct and remove some existing overlap.DUK_DEFPROP_FORCE
) for forcing changes to non-extensible objects or non-configurable properties. Still cannot change virtual properties because they have no storage.The API call will be marked experimental, i.e. it may get incompatible changes in Duktape 1.2, in case adjustments are needed based on feedback. Improvements for Duktape 1.2 are tracked in #98.
I recently moved dukluv to use fixed buffer to expose libuv structs to scripts. I like the VM handling the memory.
The biggest blocker I have is the default string conversion for buffers tries to render the struct as UTF-8 data. Also I need a way to ensure that the right type of struct is passed to my C functions before I use the void*.
Maybe we could use the 16 bits of free space to enable 2^16 different "metatables" that specify both the type of the value and some of the prototype like the toString coercion.
I did write a nice pretty printer for dukluv.
Here it is in 256 color mode: http://showterm.io/727fbb50c8fbcc0331dbd
And here in 16 color mode that should work in less capable terminals: http://showterm.io/8d9981708d97bea3e34ab
https://github.com/creationix/dukluv/blob/master/modules/utils.js
Hi again!
It will be nice if we could tell duk_json_encode to use JX or JC to produce more eye-friendly output.
Thanks
I'm curious whether you have any actual benchmark results against a V8 or SpiderMonkey-type engine on a well known suite. I realize that performance is not the goal of Duktape (per the documentation), but I just want to know if we're talking a 2x dropoff, 10x, something else. Every benchmark is flawed in some way, but I'm really just looking for orders of magnitude here.
Finally, as a side note - it would be great if there was a mailing list for Duktape (I could not find one). Some of these questions would (like this one) would be better suited for there.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.