void CallConnectSignal(duk_context* ctx, void* signal) { int numArgs = duk_get_top(ctx); duk_push_number(ctx, (size_t)signal); duk_insert(ctx, 0); duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "_ConnectSignal"); duk_remove(ctx, -2); // Global object duk_insert(ctx, 0); duk_pcall(ctx, numArgs + 1); duk_pop(ctx); }
static void duk__call_errhandler(duk_hthread *thr) { int call_flags; int rc; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); if (!thr->heap->lj.errhandler) { DUK_DDDPRINT("no errhandler, return"); return; } /* FIXME: assert/require for valstack space */ /* [ ... errval ] */ DUK_DDDPRINT("errhandler is %p", (void *) thr->heap->lj.errhandler); DUK_DDDPRINT("errhandler dump: %!O", (duk_heaphdr *) thr->heap->lj.errhandler); duk_push_hobject((duk_context *) thr, thr->heap->lj.errhandler); duk_insert((duk_context *) thr, -2); /* -> [ ... errhandler errval ] */ duk_push_undefined((duk_context *) thr); duk_insert((duk_context *) thr, -2); /* -> [ ... errhandler undefined(= this) errval ] */ /* [ ... errhandler undefined errval ] */ /* * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C * recursion depth limit (and won't increase it either). This is * dangerous, but useful because it allows an errhandler to run even * if the original error is caused by C recursion depth limit. Because * errhandler is NULL in the errhandler call, the errhandler call * can't cause the same situation to occur again. * * We ignore errors now: a success return and an error value both * replace the original error value. (This would be easy to change.) */ call_flags = DUK_CALL_FLAG_PROTECTED | DUK_CALL_FLAG_IGNORE_RECLIMIT; /* protected, ignore reclimit, not constructor */ rc = duk_handle_call(thr, 1, /* num args */ call_flags, /* call_flags */ NULL); /* errhandler */ DUK_UNREF(rc); /* no need to check now: both success and error are OK */ /* [ ... errval ] */ }
/* Shared helper to implement Object.getPrototypeOf and the ES6 * Object.prototype.__proto__ getter. * * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-get-object.prototype.__proto__ */ duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) { duk_hobject *h; /* magic: 0=getter call, 1=Object.getPrototypeOf */ if (duk_get_current_magic(ctx) == 0) { duk_push_this_coercible_to_object(ctx); duk_insert(ctx, 0); } h = duk_require_hobject(ctx, 0); DUK_ASSERT(h != NULL); /* XXX: should the API call handle this directly, i.e. attempt * to duk_push_hobject(ctx, null) would push a null instead? * (On the other hand 'undefined' would be just as logical, but * not wanted here.) */ if (h->prototype) { duk_push_hobject(ctx, h->prototype); } else { duk_push_null(ctx); } return 1; }
static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_name) { duk_idx_t i, n; n = duk_get_top(ctx); duk_get_global_string(ctx, "console"); duk_get_prop_string(ctx, -1, "format"); for (i = 0; i < n; i++) { if (duk_check_type_mask(ctx, i, DUK_TYPE_MASK_OBJECT)) { /* Slow path formatting. */ duk_dup(ctx, -1); /* console.format */ duk_dup(ctx, i); duk_call(ctx, 1); duk_replace(ctx, i); /* arg[i] = console.format(arg[i]); */ } } duk_pop_2(ctx); duk_push_string(ctx, " "); duk_insert(ctx, 0); duk_join(ctx, n); if (error_name) { duk_push_error_object(ctx, DUK_ERR_ERROR, "%s", duk_require_string(ctx, -1)); duk_push_string(ctx, "name"); duk_push_string(ctx, error_name); duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE); /* to get e.g. 'Trace: 1 2 3' */ duk_get_prop_string(ctx, -1, "stack"); } printf("%s\n", duk_to_string(ctx, -1)); return 0; }
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) { duk_idx_t nargs; /* Step 1 is not necessary because duk_call_method() will take * care of it. */ /* vararg function, thisArg needs special handling */ nargs = duk_get_top(ctx); /* = 1 + arg count */ if (nargs == 0) { duk_push_undefined(ctx); nargs++; } DUK_ASSERT(nargs >= 1); /* [ thisArg arg1 ... argN ] */ duk_push_this(ctx); /* 'func' in the algorithm */ duk_insert(ctx, 0); /* [ func thisArg arg1 ... argN ] */ DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld", (duk_tval *) duk_get_tval(ctx, 0), (duk_tval *) duk_get_tval(ctx, 1), (long) (nargs - 1), (long) duk_get_top(ctx))); duk_call_method(ctx, nargs - 1); return 1; }
/* Shared helper to implement ES6 Object.setPrototypeOf and * Object.prototype.__proto__ setter. * * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-get-object.prototype.__proto__ * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.setprototypeof */ duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h_obj; duk_hobject *h_new_proto; duk_hobject *h_curr; duk_ret_t ret_success = 1; /* retval for success path */ /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4); * magic: 0=setter call, 1=Object.setPrototypeOf */ if (duk_get_current_magic(ctx) == 0) { duk_push_this_check_object_coercible(ctx); duk_insert(ctx, 0); if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) { return 0; } /* __proto__ setter returns 'undefined' on success unlike the * setPrototypeOf() call which returns the target object. */ ret_success = 0; } else { duk_require_object_coercible(ctx, 0); duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT); } h_obj = duk_get_hobject(ctx, 0); if (!h_obj) { goto skip; } h_new_proto = duk_get_hobject(ctx, 1); DUK_ASSERT(h_obj != NULL); /* h_new_proto may be NULL */ /* [[SetPrototypeOf]] standard behavior, E6 9.1.2 */ /* NOTE: steps 7-8 seem to be a cut-paste bug in the E6 draft */ /* TODO: implement Proxy object support here */ if (h_new_proto == h_obj->prototype) { goto skip; } if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) { goto fail_nonextensible; } for (h_curr = h_new_proto; h_curr != NULL; h_curr = h_curr->prototype) { /* Loop prevention */ if (h_curr == h_obj) { goto fail_loop; } } DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto); /* fall thru */ skip: duk_set_top(ctx, 1); return ret_success; fail_nonextensible: fail_loop: return DUK_RET_TYPE_ERROR; }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) { (void) duk_push_this_coercible_to_object(ctx); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN); /* [ ... this func ] */ if (!duk_is_callable(ctx, -1)) { /* Fall back to the initial (original) Object.toString(). We don't * currently have pointers to the built-in functions, only the top * level global objects (like "Array") so this is now done in a bit * of a hacky manner. It would be cleaner to push the (original) * function and use duk_call_method(). */ /* XXX: 'this' will be ToObject() coerced twice, which is incorrect * but should have no visible side effects. */ DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString")); duk_set_top(ctx, 0); return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */ } /* [ ... this func ] */ duk_insert(ctx, -2); /* [ ... func this ] */ DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT", (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); duk_call_method(ctx, 0); return 1; }
static duk_ret_t my_print(duk_context *ctx) { duk_push_string(ctx, " "); duk_insert(ctx, 0); duk_join(ctx, duk_get_top(ctx) - 1); printf("%s\n", duk_safe_to_string(ctx, -1)); return 0; }
/* Shared helper to implement Object.getPrototypeOf and the ES6 * Object.prototype.__proto__ getter. * * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-get-object.prototype.__proto__ */ DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) { duk_hobject *h; duk_hobject *proto; /* magic: 0=getter call, 1=Object.getPrototypeOf */ if (duk_get_current_magic(ctx) == 0) { duk_push_this_coercible_to_object(ctx); duk_insert(ctx, 0); } h = duk_require_hobject_or_lfunc(ctx, 0); /* h is NULL for lightfunc */ /* XXX: should the API call handle this directly, i.e. attempt * to duk_push_hobject(ctx, null) would push a null instead? * (On the other hand 'undefined' would be just as logical, but * not wanted here.) */ if (h == NULL) { duk_push_hobject_bidx(ctx, DUK_BIDX_FUNCTION_PROTOTYPE); } else { proto = DUK_HOBJECT_GET_PROTOTYPE(h); if (proto) { duk_push_hobject(ctx, proto); } else { duk_push_null(ctx); } } return 1; }
// Given a module and js code, compile the code and execute as CJS module // return the result of the compiled code ran as a function. static duk_ret_t duv_mod_compile(duk_context *ctx) { // Check the args const duv_schema_entry schema[] = { { "code", dschema_is_data }, { NULL, NULL } }; dschema_check(ctx, schema); duk_to_string(ctx, 0); duk_push_this(ctx); duk_get_prop_string(ctx, -1, "id"); // Wrap the code duk_push_string(ctx, "function(){var module=this,exports=this.exports,require=this.require.bind(this);"); duk_dup(ctx, 0); duk_push_string(ctx, "}"); duk_concat(ctx, 3); duk_insert(ctx, -2); // Compile to a function duk_compile(ctx, DUK_COMPILE_FUNCTION); duk_push_this(ctx); duk_call_method(ctx, 0); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx) { /* duk_concat() coerces arguments with ToString() in correct order */ (void) duk_push_this_coercible_to_string(ctx); duk_insert(ctx, 0); /* this is relatively expensive */ duk_concat(ctx, duk_get_top(ctx)); return 1; }
/* Prepare value stack for a method call through an object property. * May currently throw an error e.g. when getting the property. */ DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_idx, duk_idx_t nargs) { DUK_ASSERT_CTX_VALID(ctx); DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld", (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(ctx))); /* [... key arg1 ... argN] */ /* duplicate key */ duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */ duk_get_prop(ctx, normalized_obj_idx); DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1))); /* [... key arg1 ... argN func] */ duk_replace(ctx, -nargs - 2); /* [... func arg1 ... argN] */ duk_dup(ctx, normalized_obj_idx); duk_insert(ctx, -nargs - 1); /* [... func this arg1 ... argN] */ }
// Assumes nargs are the top of the stack. Rest comes from request // Return value is not left on the stack. void duv_resolve(uv_req_t* req, int nargs) { duk_context *ctx = req->data; duv_push_handle(ctx, req); // stack: args... obj duk_get_prop_string(ctx, -1, "\xff""uv-callback"); // stack: args... obj callback duk_del_prop_string(ctx, -2, "\xff""uv-callback"); // stack: args... obj callback if (!duk_is_function(ctx, -1)) { // stack: args... obj callback duk_pop_n(ctx, 2 + nargs); return; } duk_remove(ctx, -2); // stack: args... callback duk_insert(ctx, -(nargs + 1)); // stack: callback args... duk_call(ctx, nargs); // stack: result duk_pop(ctx); // Remove the request from the GC roots duv_remove_handle(ctx, req); }
duk_ret_t duv_setup_request(duk_context *ctx, uv_req_t* req, int callback) { // Create a new container object for the request with request methods duk_push_object(ctx); duk_push_heap_stash(ctx); duk_get_prop_string(ctx, -1, "req-prototype"); duk_remove(ctx, -2); duk_set_prototype(ctx, -2); // Set buffer as uv-data internal property. duk_insert(ctx, -2); duk_put_prop_string(ctx, -2, "\xff""uv-data"); // Store the request type. duk_push_int(ctx, req->type); duk_put_prop_string(ctx, -2, "\xff""req-type"); // Store a reference to the lua callback duk_dup(ctx, callback); duk_put_prop_string(ctx, -2, "\xff""uv-callback"); // Store this object in the heap stack keyed by the request's pointer address. // This will prevent it from being garbage collected and allow us to find // it with nothing more than the request's address. duv_store_handle(ctx, req); // Store the context in the handle so it can use duktape APIs. req->data = ctx; // TODO: is this still on the stack? return 1; }
DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t call_flags; duk_idx_t idx_func; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; if (idx_func < 0 || nargs < 0) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } /* XXX: awkward; we assume there is space for this, overwrite * directly instead? */ duk_push_undefined(ctx); duk_insert(ctx, idx_func + 1); call_flags = 0; /* not protected, respect reclimit, not constructor */ duk_handle_call_unprotected(thr, /* thread */ nargs, /* num_stack_args */ call_flags); /* call_flags */ }
void CallDisconnectSignal(duk_context* ctx, void* signal) { int numArgs = duk_get_top(ctx); duk_push_number(ctx, (size_t)signal); duk_insert(ctx, 0); duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "_DisconnectSignal"); duk_remove(ctx, -2); // Global object duk_insert(ctx, 0); duk_pcall(ctx, numArgs + 1); if (duk_get_boolean(ctx, -1)) // Last receiver disconnected { HashMap<void*, SharedPtr<SignalReceiver> >& signalReceivers = JavaScriptInstance::InstanceFromContext(ctx)->SignalReceivers(); signalReceivers.Erase(signal); } duk_pop(ctx); // Result }
/* * Fulfill a libuv request. */ void mn_fulfill_req(duk_context *ctx, uv_req_t *req, int nargs) { mn_req_t *data = req->data; if (data->callback_ref) { mn_push_ref(ctx, data->callback_ref); if (nargs) { duk_insert(ctx, -1 - nargs); } mn_push_ref(ctx, data->context); if (nargs) { duk_insert(ctx, -1 - nargs); } duk_call_method(ctx, nargs); duk_pop(ctx); } else if (nargs) { duk_pop_n(ctx, nargs); } }
DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) { duk_hobject *h; duk_push_this(thr); h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP); DUK_ASSERT(h != NULL); DUK_UNREF(h); duk_insert(thr, 0); /* prepend regexp to valstack 0 index */ }
// Default Duktape.modLoad implementation // return Duktape.modCompile.call(module, loadFile(module.id)); // or load shared libraries using Duktape.loadlib. static duk_ret_t duv_mod_load(duk_context *ctx) { const char* id; const char* ext; const duv_schema_entry schema[] = { { NULL, NULL } }; dschema_check(ctx, schema); duk_get_global_string(ctx, "Duktape"); duk_push_this(ctx); duk_get_prop_string(ctx, -1, "id"); id = duk_get_string(ctx, -1); if (!id) { duk_error(ctx, DUK_ERR_ERROR, "Missing id in module"); return 0; } // calculate the extension to know which compiler to use. ext = id + strlen(id); while (ext > id && ext[0] != '/' && ext[0] != '.') { --ext; } if (strcmp(ext, ".js") != 0) { duk_pop(ctx); std::string s = std::string(id) + ".js"; duk_push_string(ctx, s.c_str()); } // Stack: [Duktape, this, id] duk_push_c_function(ctx, duv_loadfile, 1); // Stack: [Duktape, this, id, loadfile] duk_insert(ctx, -2); // Stack: [Duktape, this, loadfile, id] duk_call(ctx, 1); // Stack: [Duktape, this, data] duk_get_prop_string(ctx, -3, "modCompile"); // Stack: [Duktape, this, data, modCompile] duk_insert(ctx, -3); // Stack: [Duktape, modCompile, this, data] duk_call_method(ctx, 1); // Stack: [Duktape, exports] return 1; }
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) { duk_idx_t len; duk_idx_t i; DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */ duk_push_this(ctx); if (!duk_is_callable(ctx, -1)) { DUK_DDD(DUK_DDDPRINT("func is not callable")); goto type_error; } duk_insert(ctx, 0); DUK_ASSERT_TOP(ctx, 3); DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT", (duk_tval *) duk_get_tval(ctx, 0), (duk_tval *) duk_get_tval(ctx, 1), (duk_tval *) duk_get_tval(ctx, 2))); /* [ func thisArg argArray ] */ if (duk_is_null_or_undefined(ctx, 2)) { DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args")); len = 0; } else if (!duk_is_object(ctx, 2)) { goto type_error; } else { DUK_DDD(DUK_DDDPRINT("argArray is an object")); /* XXX: make this an internal helper */ duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH); len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */ duk_pop(ctx); duk_require_stack(ctx, len); DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len)); for (i = 0; i < len; i++) { duk_get_prop_index(ctx, 2, i); } } duk_remove(ctx, 2); DUK_ASSERT_TOP(ctx, 2 + len); /* [ func thisArg arg1 ... argN ] */ DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld", (duk_tval *) duk_get_tval(ctx, 0), (duk_tval *) duk_get_tval(ctx, 1), (long) len)); duk_call_method(ctx, len); return 1; type_error: return DUK_RET_TYPE_ERROR; }
void* duv_require_this_handle(duk_context *ctx, duv_type_mask_t mask) { duk_push_this(ctx); if (!duv_is_handle_of(ctx, -1, mask)) { duk_pop(ctx); duk_error(ctx, DUK_ERR_TYPE_ERROR, "this must be %s", duv_mask_to_string(mask)); } void *handle = duv_get_handle(ctx, -1); duk_insert(ctx, 0); return handle; }
void duv_emit(uv_handle_t* handle, const char* key, int nargs, int cleanup) { duk_context *ctx = handle->data; duv_push_handle(ctx, handle); // stack: args... this duk_get_prop_string(ctx, -1, key); // stack: args... this fn if (cleanup) duk_del_prop_string(ctx, -2, key); // stack: args... this fn if (!duk_is_function(ctx, -1)) { duk_pop_n(ctx, 2 + nargs); return; } duk_insert(ctx, -(nargs + 2)); // stack: fn args... this duk_insert(ctx, -(nargs + 1)); // stack: fn this args... duk_call_method(ctx, nargs); // stack: result duk_pop(ctx); }
int duk_bi_error_prototype_to_string(duk_context *ctx) { /* FIXME: optimize with more direct internal access */ duk_push_this(ctx); if (!duk_is_object(ctx, -1)) { goto type_error; } /* [ ... this ] */ duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); duk_push_string(ctx, "Error"); } else { duk_to_string(ctx, -1); } /* [ ... this name ] */ /* FIXME: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by * accident or are they actually needed? The first ToString() * could conceivably return 'undefined'. */ duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); duk_push_string(ctx, ""); } else { duk_to_string(ctx, -1); } /* [ ... this name message ] */ if (duk_get_length(ctx, -2) == 0) { /* name is empty -> return message */ return 1; } if (duk_get_length(ctx, -1) == 0) { /* message is empty -> return name */ duk_pop(ctx); return 1; } duk_push_string(ctx, ": "); duk_insert(ctx, -2); /* ... name ': ' message */ duk_concat(ctx, 3); return 1; type_error: return DUK_RET_TYPE_ERROR; }
void mn_emit_event( duk_context *ctx, mn_handle_t *data, mn_cb_id_t type, int nargs ) { int fn_ref = data->callbacks[type]; if (fn_ref) { mn_push_ref(ctx, fn_ref); if (nargs) { duk_insert(ctx, -1 - nargs); } mn_push_ref(ctx, data->context); if (nargs) { duk_insert(ctx, -1 - nargs); } duk_call_method(ctx, nargs); duk_pop(ctx); } else if (nargs) { duk_pop_n(ctx, nargs); } }
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_hthread *thr) { duk_push_this(thr); duk_insert(thr, 0); duk_to_object(thr, 0); duk_require_callable(thr, 2); /* [ ToObject(this) key getter/setter ] */ /* ToPropertyKey() coercion is not needed, duk_def_prop() does it. */ duk_def_prop(thr, 0, DUK_DEFPROP_SET_ENUMERABLE | DUK_DEFPROP_SET_CONFIGURABLE | (duk_get_current_magic(thr) ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER)); return 0; }
DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) { duk_context *ctx = (duk_context *) thr; duk_hobject *h; duk_hstring *h_bc; duk_small_int_t re_flags; /* [ ... escape_source bytecode ] */ h_bc = duk_get_hstring(ctx, -1); DUK_ASSERT(h_bc != NULL); DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1); /* always at least the header */ DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1); DUK_ASSERT((duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80); /* flags always encodes to 1 byte */ re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* [ ... escaped_source bytecode ] */ duk_push_object(ctx); h = duk_get_hobject(ctx, -1); DUK_ASSERT(h != NULL); duk_insert(ctx, -3); /* [ ... regexp_object escaped_source bytecode ] */ DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]); duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE); /* [ ... regexp_object escaped_source ] */ duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_SOURCE, DUK_PROPDESC_FLAGS_NONE); /* [ ... regexp_object ] */ duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_GLOBAL)); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_GLOBAL, DUK_PROPDESC_FLAGS_NONE); duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_IGNORE_CASE)); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_IGNORE_CASE, DUK_PROPDESC_FLAGS_NONE); duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_MULTILINE)); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MULTILINE, DUK_PROPDESC_FLAGS_NONE); duk_push_int(ctx, 0); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W); /* [ ... regexp_object ] */ }
DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) { duk_hthread *thr = (duk_hthread *) ctx; duk_bool_t ret; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); /* XXX: direct implementation */ duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]); duk_insert(ctx, -2); ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */ duk_pop(ctx); return ret; }
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) { /* XXX: optimize with more direct internal access */ duk_push_this(ctx); (void) duk_require_hobject_promote_mask(ctx, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); /* [ ... this ] */ duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); duk_push_string(ctx, "Error"); } else { duk_to_string(ctx, -1); } /* [ ... this name ] */ /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by * accident or are they actually needed? The first ToString() * could conceivably return 'undefined'. */ duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE); if (duk_is_undefined(ctx, -1)) { duk_pop(ctx); duk_push_string(ctx, ""); } else { duk_to_string(ctx, -1); } /* [ ... this name message ] */ if (duk_get_length(ctx, -2) == 0) { /* name is empty -> return message */ return 1; } if (duk_get_length(ctx, -1) == 0) { /* message is empty -> return name */ duk_pop(ctx); return 1; } duk_push_string(ctx, ": "); duk_insert(ctx, -2); /* ... name ': ' message */ duk_concat(ctx, 3); return 1; }
DUK_EXTERNAL int sjs_vm_eval_code(const sjs_vm_t* vm, const char* filename, const char* code, size_t len, FILE* foutput, FILE* ferror, bool use_strict) { int r; assert(vm); duk_context* ctx = vm->ctx; duk_push_boolean(ctx, use_strict); duk_push_pointer(ctx, (void *) code); duk_push_uint(ctx, len); duk_push_string(ctx, filename); r = duk_safe_call(ctx, sjs__compile_execute, 4 /*nargs*/, 1 /*nret*/); if (r != DUK_EXEC_SUCCESS) { if (ferror) { duk_safe_call(ctx, sjs__get_error_stack, 1 /*nargs*/, 1 /*nrets*/); fprintf(ferror, "%s\n", duk_safe_to_string(ctx, -1)); fflush(ferror); } } else { if (foutput) { /* TODO: make this optional with a parameter? */ /* beautify output */ duk_eval_string(ctx, "(function (v) {\n" " try {\n" " return Duktape.enc('jx', v, null, 4);\n" " } catch (e) {\n" " return String(v);\n" " }\n" "})"); duk_insert(ctx, -2); duk_call(ctx, 1); fprintf(foutput, "= %s\n", duk_safe_to_string(ctx, -1)); fflush(foutput); } } duk_pop(ctx); return r; }
int invoke_java_method_call(duk_context *ctx) { int num = duk_get_top(ctx); const char * method = duk_to_string(ctx, 0); DEBUG_LOG("ScriptEngine","invoke_java_method call, method name %s args num %d", method, (num - 1)); duk_push_this(ctx); if(duk_get_prop_string(ctx, -1, JAVA_OBJECT_MARK)){ jobject ref = duk_to_pointer(ctx, -1); JNIEnv* env = get_java_jni_env(); DEBUG_LOG("ScriptEngine","invoke_java_method call, method new String %s", method); jstring methodName = (*env)->NewStringUTF(env, method); jobjectArray args = duk_to_java_object_array(ctx, 1, num-1, env); DEBUG_LOG("ScriptEngine","invoke_java_method call, with args %p %p", java_api_class, java_function_method); jobject value = (*env)->CallStaticObjectMethod(env, java_api_class, java_function_method, ref, methodName, args); jthrowable exp = ( *env)->ExceptionOccurred(env); if(exp != NULL){ ( *env)->ExceptionClear(env); jstring exceptionMessage = (*env)->CallStaticObjectMethod(env, java_api_class, java_exception_get_stack_trace_method, exp); jboolean isCopy = JNI_FALSE; const char* cstrMessage = (*env)->GetStringUTFChars(env, exceptionMessage, &isCopy); duk_push_error_object(ctx, DUK_ERR_EVAL_ERROR, "invoke java method %s exception \n %s", method, cstrMessage); (*env)->ReleaseStringUTFChars(env, exceptionMessage, cstrMessage); ( *env)->DeleteLocalRef(env , exceptionMessage); (*env)->DeleteLocalRef(env, args); (*env)->DeleteLocalRef(env, methodName); duk_throw(ctx); return 0; } duk_push_java_object(ctx, env, value); (*env)->DeleteLocalRef(env, value); (*env)->DeleteLocalRef(env, args); (*env)->DeleteLocalRef(env, methodName); DEBUG_LOG("ScriptEngine","invoke_java_method call with args success "); return 1; }else{ duk_pop(ctx); duk_insert(ctx, 0); DEBUG_LOG("ScriptEngine","invoke_script_prop call, with args num %d ", duk_get_top(ctx)); if(duk_pcall_prop(ctx, 0, num - 1) != DUK_EXEC_SUCCESS){ LOGE("ScriptEngine","ScriptEngine call %s method %s error %s", duk_to_string(ctx, 0), method, duk_js_error_to_string(ctx, -1)); duk_pop(ctx); duk_push_null(ctx); } DEBUG_LOG("ScriptEngine","invoke_script_prop call, duk_get_prop_string with args num %d ", duk_get_top(ctx)); return 1; } }