/** * * performance tips * https://www.ibm.com/developerworks/library/j-jni/ * */ jobject duk_to_java_object(duk_context *ctx, JNIEnv* env, int i){ int type = duk_get_type(ctx, i); if(type == DUK_TYPE_BOOLEAN){ jboolean value = duk_to_boolean(ctx, i); DEBUG_LOG("ScriptEngine","invoke_java_method call, convert %d args to boolean %d", i, value); jmethodID methodID = (*env)->GetMethodID(env, java_boolean_class, "<init>", "(Z)V"); jobject booleanObject = (*env)->NewObject(env, java_boolean_class, methodID, value); return booleanObject; }else if(type == DUK_TYPE_NUMBER){ jdouble value = duk_to_number(ctx, i); jclass doubleClass = (*env)->FindClass(env, "java/lang/Double"); jmethodID methodID = (*env)->GetMethodID(env, doubleClass, "<init>", "(D)V"); jobject numberObject = (*env)->NewObject(env, doubleClass, methodID, value); (*env)->DeleteLocalRef(env, doubleClass); DEBUG_LOG("ScriptEngine","invoke_java_method call, convert %d args to number %f", i, value); return numberObject; }else if(type == DUK_TYPE_STRING){ const char* chs = duk_to_string(ctx, i); DEBUG_LOG("ScriptEngine","invoke_java_method call, convert %d args to string %s", i, chs); return (*env)->NewStringUTF(env, chs); }else if(type == DUK_TYPE_OBJECT){ if(duk_get_prop_string(ctx, i, JAVA_OBJECT_MARK)){ DEBUG_LOG("ScriptEngine","invoke_java_method call, convert %d args to java object", i); jobject value = duk_to_pointer(ctx, -1); duk_pop(ctx); return (*env)->NewLocalRef(env, value); }else{ duk_pop(ctx); if(duk_get_prop_string(ctx, i, JS_REF_MARK)){ DEBUG_LOG("ScriptEngine","reuse javascript object's JSRef"); jweak weakRef = duk_to_pointer(ctx, -1); jobject jsRefObject = (*env)->NewLocalRef(env, weakRef); duk_pop(ctx); if(jsRefObject != NULL){ return jsRefObject; } }else{ duk_pop(ctx); } duk_dup(ctx, i); jint ref = duk_js_ref(ctx); if(ref != 0){ DEBUG_LOG("ScriptEngine","convert javascript object to JSRef Ref Value %d ", ref); jobject engine = get_engine_from_context(ctx); DEBUG_LOG("ScriptEngine","convert javascript object to JSRef Ref Value"); jobject jsRefObject = (*env)->NewObject(env, js_ref_class, js_ref_new_method, engine, ref); jweak jsWeakRef = (*env)->NewWeakGlobalRef(env, jsRefObject); duk_dup(ctx, i); duk_push_pointer(ctx, jsWeakRef); duk_put_prop_string(ctx, -2, JS_REF_MARK); duk_pop(ctx); DEBUG_LOG("ScriptEngine","convert javascript object to JSRef Ref Value Success"); return jsRefObject; } return NULL; } } DEBUG_LOG("ScriptEngine","invoke_java_method call, unhandled type convert %d args to null %s", i, duk_to_string(ctx, i)); return NULL; }
static duk_ret_t duk_font(duk_context* duk) { tic_mem* memory = (tic_mem*)getDukMachine(duk); const char* text = duk_to_string(duk, 0); s32 x = duk_to_int(duk, 1); s32 y = duk_to_int(duk, 2); u8 chromakey = duk_to_int(duk, 3); s32 width = duk_is_null_or_undefined(duk, 4) ? TIC_SPRITESIZE : duk_to_int(duk, 4); s32 height = duk_is_null_or_undefined(duk, 5) ? TIC_SPRITESIZE : duk_to_int(duk, 5); bool fixed = duk_is_null_or_undefined(duk, 6) ? false : duk_to_boolean(duk, 6); s32 scale = duk_is_null_or_undefined(duk, 7) ? 1 : duk_to_int(duk, 7); if(scale == 0) { duk_push_int(duk, 0); return 1; } s32 size = drawText(memory, text, x, y, width, height, chromakey, scale, fixed ? drawSpriteFont : drawFixedSpriteFont); duk_push_int(duk, size); return 1; }
static int FileSystem_ScanDir(duk_context* ctx) { duk_push_this(ctx); FileSystem* fs = js_to_class_instance<FileSystem>(ctx, -1, 0); if ( !duk_is_string(ctx, 0) || !duk_is_string(ctx, 1) || !duk_is_number(ctx, 2) || !duk_is_boolean(ctx, 3)) { duk_push_string(ctx, "FileSystem::ScanDir bad args"); duk_throw(ctx); } const char* pathName = duk_to_string(ctx, 0); const char* filter = duk_to_string(ctx, 1); unsigned flags = duk_to_number(ctx, 2); bool recursive = duk_to_boolean(ctx, 3) ? true : false; Vector<String> result; fs->ScanDir(result, pathName, filter, flags, recursive); duk_push_array(ctx); for (unsigned i = 0; i < result.Size(); i++) { duk_push_string(ctx, result[i].CString()); duk_put_prop_index(ctx, -2, i); } return 1; }
static duk_ret_t test_1(duk_context *ctx, void *udata) { duk_idx_t i, n; (void) udata; duk_set_top(ctx, 0); duk_push_undefined(ctx); duk_push_null(ctx); duk_push_true(ctx); duk_push_false(ctx); duk_push_int(ctx, 0); duk_push_int(ctx, 1); duk_push_nan(ctx); duk_push_number(ctx, INFINITY); duk_push_string(ctx, ""); duk_push_string(ctx, "foo"); duk_push_object(ctx); duk_push_thread(ctx); duk_push_fixed_buffer(ctx, 0); duk_push_fixed_buffer(ctx, 1024); duk_push_dynamic_buffer(ctx, 0); duk_push_dynamic_buffer(ctx, 1024); duk_push_pointer(ctx, (void *) NULL); duk_push_pointer(ctx, (void *) 0xdeadbeefUL); n = duk_get_top(ctx); printf("top: %ld\n", (long) n); for (i = 0; i < n; i++) { printf("index %ld, boolean: %d\n", (long) i, (int) duk_to_boolean(ctx, i)); } return 0; }
static duk_ret_t handle_assert(duk_context *ctx) { if (duk_to_boolean(ctx, 0)) { return 0; } duk_error(ctx, DUK_ERR_ERROR, "assertion failed: %s", duk_safe_to_string(ctx, 1)); return 0; }
static duk_ret_t duk__console_assert(duk_context *ctx) { if (duk_to_boolean(ctx, 0)) { return 0; } duk_remove(ctx, 0); return duk__console_log_helper(ctx, "AssertionError"); }
static duk_ret_t test_3(duk_context *ctx, void *udata) { (void) udata; duk_set_top(ctx, 0); duk_to_boolean(ctx, DUK_INVALID_INDEX); printf("index DUK_INVALID_INDEX OK\n"); return 0; }
static duk_ret_t test_2(duk_context *ctx, void *udata) { (void) udata; duk_set_top(ctx, 0); duk_to_boolean(ctx, 3); printf("index 3 OK\n"); return 0; }
bool jsplugin_load(JSVM* vm, const String& pluginLibrary) { String errorMsg; atomic_plugin_validate_function validatefunc; duk_c_function initfunc; duk_context* ctx = vm->GetJSContext(); LOGINFOF("Loading Native Plugin: %s", pluginLibrary.CString()); if (!jsplugin_get_entry_points(pluginLibrary, &validatefunc, &initfunc, errorMsg)) { LOGERRORF("%s", errorMsg.CString()); return false; } int version = ATOMIC_JSPLUGIN_VERSION; if (!validatefunc(version, &gJSVMExports, sizeof(JSVMImports))) { LOGERRORF("Native Plugin: atomic_plugin_validate failed: %s", pluginLibrary.CString()); return false; } // just to verify that we're not doing anything funky with the stack int top = duk_get_top(ctx); // the import function is a standard duktape c function, neat duk_push_c_function(ctx, initfunc, 1); // requires exports to be at index 2 duk_dup(ctx, 2); bool success = true; if (duk_pcall(ctx, 1) != DUK_EXEC_SUCCESS) { success = false; LOGERRORF("Native Plugin: error calling atomic_plugin_init %s", pluginLibrary.CString()); } else { if (!duk_is_boolean(ctx, -1) || !duk_to_boolean(ctx, -1)) { success = false; LOGERRORF("Native Plugin: error calling atomic_plugin_init, didn't return true %s", pluginLibrary.CString()); } } duk_pop(ctx); assert(top == duk_get_top(ctx)); return success; }
static duk_ret_t duk_sync(duk_context* duk) { tic_mem* memory = (tic_mem*)getDukMachine(duk); u32 mask = duk_is_null_or_undefined(duk, 0) ? 0 : duk_to_int(duk, 0); s32 bank = duk_is_null_or_undefined(duk, 1) ? 0 : duk_to_int(duk, 1); bool toCart = duk_is_null_or_undefined(duk, 2) ? false : duk_to_boolean(duk, 2); if(bank >= 0 && bank < TIC_BANKS) memory->api.sync(memory, mask, bank, toCart); else return duk_error(duk, DUK_ERR_ERROR, "sync() error, invalid bank"); return 0; }
DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop) { duk_bool_t rc; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT_DISABLE(stridx >= 0); DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); rc = duk_get_prop_stridx(ctx, obj_index, stridx); if (out_has_prop) { *out_has_prop = rc; } rc = duk_to_boolean(ctx, -1); DUK_ASSERT(rc == 0 || rc == 1); duk_pop(ctx); return rc; }
static duk_ret_t duk_print(duk_context* duk) { tic_mem* memory = (tic_mem*)getDukMachine(duk); const char* text = duk_is_null_or_undefined(duk, 0) ? "" : duk_to_string(duk, 0); s32 x = duk_is_null_or_undefined(duk, 1) ? 0 : duk_to_int(duk, 1); s32 y = duk_is_null_or_undefined(duk, 2) ? 0 : duk_to_int(duk, 2); s32 color = duk_is_null_or_undefined(duk, 3) ? (TIC_PALETTE_SIZE-1) : duk_to_int(duk, 3); bool fixed = duk_is_null_or_undefined(duk, 4) ? false : duk_to_boolean(duk, 4); s32 scale = duk_is_null_or_undefined(duk, 5) ? 1 : duk_to_int(duk, 5); s32 size = memory->api.text_ex(memory, text ? text : "nil", x, y, color, fixed, scale); duk_push_uint(duk, size); return 1; }
static duk_ret_t duk_music(duk_context* duk) { tic_mem* memory = (tic_mem*)getDukMachine(duk); s32 track = duk_is_null_or_undefined(duk, 0) ? -1 : duk_to_int(duk, 0); memory->api.music(memory, -1, 0, 0, false); if(track >= 0) { s32 frame = duk_is_null_or_undefined(duk, 1) ? -1 : duk_to_int(duk, 1); s32 row = duk_is_null_or_undefined(duk, 2) ? -1 : duk_to_int(duk, 2); bool loop = duk_is_null_or_undefined(duk, 3) ? true : duk_to_boolean(duk, 3); memory->api.music(memory, track, frame, row, loop); } return 0; }
duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) { duk_hobject *h_this; duk_to_boolean(ctx, 0); if (duk_is_constructor_call(ctx)) { /* FIXME: helper; rely on Boolean.prototype as being non-writable, non-configurable */ duk_push_this(ctx); h_this = duk_get_hobject(ctx, -1); DUK_ASSERT(h_this != NULL); DUK_ASSERT(h_this->prototype == ((duk_hthread *) ctx)->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]); DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN); duk_dup(ctx, 0); /* -> [ val obj val ] */ duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* FIXME: proper flags? */ } /* unbalanced stack */ return 1; }
// the destructor duk_ret_t js_myPlugin_dtor(duk_context *ctx) { // The object to delete is passed as first argument instead duk_get_prop_string(ctx, 0, "\xff""\xff""deleted"); bool deleted = duk_to_boolean(ctx, -1); duk_pop(ctx); // Get the pointer and free it if (!deleted) { duk_get_prop_string(ctx, 0, "\xff""\xff""data"); void *freePtr = duk_to_pointer(ctx, -1); free(freePtr); duk_pop(ctx); // Mark as deleted duk_push_boolean(ctx, true); duk_put_prop_string(ctx, 0, "\xff""\xff""deleted"); } return 0; }
static duk_ret_t duk_textri(duk_context* duk) { float pt[12]; for (s32 i = 0; i < COUNT_OF(pt); i++) pt[i] = (float)duk_to_number(duk, i); tic_mem* memory = (tic_mem*)getDukMachine(duk); bool use_map = duk_is_null_or_undefined(duk, 12) ? false : duk_to_boolean(duk, 12); u8 chroma = duk_is_null_or_undefined(duk, 13) ? 0xff : duk_to_int(duk, 13); memory->api.textri(memory, pt[0], pt[1], // xy 1 pt[2], pt[3], // xy 2 pt[4], pt[5], // xy 3 pt[6], pt[7], // uv 1 pt[8], pt[9], // uv 2 pt[10], pt[11],// uv 3 use_map, // usemap chroma); // chroma return 0; }
CEJsValue js_to_cejs_value(duk_context* ctx, int index) { if (duk_is_number(ctx, index)) return JS_NUMBER(duk_to_number(ctx, index)); if (duk_is_boolean(ctx, index)) return JS_BOOL(duk_to_boolean(ctx, index)); if (duk_is_string(ctx, index)) return JS_STRING(duk_to_string(ctx, index)); if (duk_is_array(ctx, index)) return JS_STRING(duk_json_encode(ctx, index)); if (duk_is_object(ctx, index)) return JS_STRING(duk_json_encode(ctx, index)); if (duk_is_undefined(ctx, index)) { return JS_UNDEFINED; } return JS_NULL; }
int test_3(duk_context *ctx) { duk_set_top(ctx, 0); duk_to_boolean(ctx, 3); printf("index 3 OK\n"); return 0; }
int test_4(duk_context *ctx) { duk_set_top(ctx, 0); duk_to_boolean(ctx, DUK_INVALID_INDEX); printf("index DUK_INVALID_INDEX OK\n"); return 0; }
int duk_bi_array_prototype_iter_shared(duk_context *ctx) { int len; int i; int k; int bval; int iter_type = duk_get_magic(ctx); duk_uint32_t res_length = 0; /* each call this helper serves has nargs==2 */ DUK_ASSERT_TOP(ctx, 2); len = duk__push_this_obj_len_u32(ctx); if (!duk_is_callable(ctx, 0)) { goto type_error; } /* if thisArg not supplied, behave as if undefined was supplied */ if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) { duk_push_array(ctx); } else { duk_push_undefined(ctx); } /* stack[0] = callback * stack[1] = thisArg * stack[2] = object * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop) * stack[4] = result array (or undefined) */ k = 0; /* result index for filter() */ for (i = 0; i < len; i++) { DUK_ASSERT_TOP(ctx, 5); if (!duk_get_prop_index(ctx, 2, i)) { duk_pop(ctx); continue; } /* The original value needs to be preserved for filter(), hence * this funny order. We can't re-get the value because of side * effects. */ duk_dup(ctx, 0); duk_dup(ctx, 1); duk_dup(ctx, -3); duk_push_int(ctx, i); duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */ duk_call_method(ctx, 3); /* -> [ ... val retval ] */ switch (iter_type) { case DUK__ITER_EVERY: bval = duk_to_boolean(ctx, -1); if (!bval) { /* stack top contains 'false' */ return 1; } break; case DUK__ITER_SOME: bval = duk_to_boolean(ctx, -1); if (bval) { /* stack top contains 'true' */ return 1; } break; case DUK__ITER_FOREACH: /* nop */ break; case DUK__ITER_MAP: duk_dup(ctx, -1); duk_def_prop_index(ctx, 4, i, DUK_PROPDESC_FLAGS_WEC); /* retval to result[i] */ res_length = i + 1; break; case DUK__ITER_FILTER: bval = duk_to_boolean(ctx, -1); if (bval) { duk_dup(ctx, -2); /* orig value */ duk_def_prop_index(ctx, 4, k, DUK_PROPDESC_FLAGS_WEC); k++; res_length = k; } break; default: DUK_UNREACHABLE(); break; } duk_pop_2(ctx); DUK_ASSERT_TOP(ctx, 5); } switch (iter_type) { case DUK__ITER_EVERY: duk_push_true(ctx); break; case DUK__ITER_SOME: duk_push_false(ctx); break; case DUK__ITER_FOREACH: duk_push_undefined(ctx); break; case DUK__ITER_MAP: case DUK__ITER_FILTER: DUK_ASSERT_TOP(ctx, 5); DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */ duk_push_number(ctx, (double) res_length); /* FIXME */ duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); break; default: DUK_UNREACHABLE(); break; } return 1; type_error: return DUK_RET_TYPE_ERROR; }
static duk_ret_t test_func(duk_context *ctx, void *udata) { (void) udata; if (ctx) { printf("dummy - return here\n"); fflush(stdout); return 0; } /* Up-to-date for Duktape 1.3.0, alphabetical order: * $ cd website/api; ls *.yaml */ (void) duk_alloc_raw(ctx, 0); (void) duk_alloc(ctx, 0); (void) duk_base64_decode(ctx, 0); (void) duk_base64_encode(ctx, 0); (void) duk_buffer_to_string(ctx, 0); (void) duk_call_method(ctx, 0); (void) duk_call_prop(ctx, 0, 0); (void) duk_call(ctx, 0); (void) duk_char_code_at(ctx, 0, 0); (void) duk_check_stack_top(ctx, 0); (void) duk_check_stack(ctx, 0); (void) duk_check_type_mask(ctx, 0, 0); (void) duk_check_type(ctx, 0, 0); (void) duk_compact(ctx, 0); (void) duk_compile_lstring_filename(ctx, 0, "dummy", 0); (void) duk_compile_lstring(ctx, 0, "dummy", 0); (void) duk_compile_string_filename(ctx, 0, "dummy"); (void) duk_compile_string(ctx, 0, "dummy"); (void) duk_compile(ctx, 0); (void) duk_concat(ctx, 0); (void) duk_config_buffer(ctx, 0, NULL, 0); (void) duk_copy(ctx, 0, 0); (void) duk_create_heap_default(); (void) duk_create_heap(NULL, NULL, NULL, NULL, NULL); (void) duk_debugger_attach(ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); (void) duk_debugger_cooperate(ctx); (void) duk_debugger_detach(ctx); (void) duk_debugger_notify(ctx, 0); (void) duk_debugger_pause(ctx); (void) duk_decode_string(ctx, 0, NULL, NULL); (void) duk_def_prop(ctx, 0, 0); (void) duk_del_prop_index(ctx, 0, 0); (void) duk_del_prop_string(ctx, 0, "dummy"); (void) duk_del_prop(ctx, 0); (void) duk_destroy_heap(ctx); (void) duk_dump_function(ctx); (void) duk_dup_top(ctx); (void) duk_dup(ctx, 0); (void) duk_enum(ctx, 0, 0); (void) duk_equals(ctx, 0, 0); duk_error_va(ctx, 0, NULL, NULL); duk_error(ctx, 0, "dummy"); /* (void) cast won't work without variadic macros */ (void) duk_eval_lstring_noresult(ctx, "dummy", 0); (void) duk_eval_lstring(ctx, "dummy", 0); (void) duk_eval_noresult(ctx); (void) duk_eval_string_noresult(ctx, "dummy"); (void) duk_eval_string(ctx, "dummy"); (void) duk_eval(ctx); (void) duk_fatal(ctx, "dummy"); (void) duk_free_raw(ctx, NULL); (void) duk_free(ctx, NULL); (void) duk_gc(ctx, 0); (void) duk_get_boolean(ctx, 0); (void) duk_get_buffer_data(ctx, 0, NULL); (void) duk_get_buffer(ctx, 0, NULL); (void) duk_get_c_function(ctx, 0); (void) duk_get_context(ctx, 0); (void) duk_get_current_magic(ctx); (void) duk_get_error_code(ctx, 0); (void) duk_get_finalizer(ctx, 0); (void) duk_get_global_string(ctx, 0); (void) duk_get_heapptr(ctx, 0); (void) duk_get_int(ctx, 0); (void) duk_get_length(ctx, 0); (void) duk_get_lstring(ctx, 0, NULL); (void) duk_get_magic(ctx, 0); (void) duk_get_memory_functions(ctx, NULL); (void) duk_get_number(ctx, 0); (void) duk_get_pointer(ctx, 0); (void) duk_get_prop_index(ctx, 0, 0); (void) duk_get_prop_string(ctx, 0, "dummy"); (void) duk_get_prop(ctx, 0); (void) duk_get_prototype(ctx, 0); (void) duk_get_string(ctx, 0); (void) duk_get_top_index(ctx); (void) duk_get_top(ctx); (void) duk_get_type_mask(ctx, 0); (void) duk_get_type(ctx, 0); (void) duk_get_uint(ctx, 0); (void) duk_has_prop_index(ctx, 0, 0); (void) duk_has_prop_string(ctx, 0, "dummy"); (void) duk_has_prop(ctx, 0); (void) duk_hex_decode(ctx, 0); (void) duk_hex_encode(ctx, 0); (void) duk_insert(ctx, 0); (void) duk_instanceof(ctx, 0, 0); (void) duk_is_array(ctx, 0); (void) duk_is_boolean(ctx, 0); (void) duk_is_bound_function(ctx, 0); (void) duk_is_buffer(ctx, 0); (void) duk_is_callable(ctx, 0); (void) duk_is_c_function(ctx, 0); (void) duk_is_constructor_call(ctx); (void) duk_is_dynamic_buffer(ctx, 0); (void) duk_is_ecmascript_function(ctx, 0); (void) duk_is_error(ctx, 0); (void) duk_is_eval_error(ctx, 0); (void) duk_is_fixed_buffer(ctx, 0); (void) duk_is_function(ctx, 0); (void) duk_is_lightfunc(ctx, 0); (void) duk_is_nan(ctx, 0); (void) duk_is_null_or_undefined(ctx, 0); (void) duk_is_null(ctx, 0); (void) duk_is_number(ctx, 0); (void) duk_is_object_coercible(ctx, 0); (void) duk_is_object(ctx, 0); (void) duk_is_pointer(ctx, 0); (void) duk_is_primitive(ctx, 0); (void) duk_is_range_error(ctx, 0); (void) duk_is_reference_error(ctx, 0); (void) duk_is_strict_call(ctx); (void) duk_is_string(ctx, 0); (void) duk_is_syntax_error(ctx, 0); (void) duk_is_thread(ctx, 0); (void) duk_is_type_error(ctx, 0); (void) duk_is_undefined(ctx, 0); (void) duk_is_uri_error(ctx, 0); (void) duk_is_valid_index(ctx, 0); (void) duk_join(ctx, 0); (void) duk_json_decode(ctx, 0); (void) duk_json_encode(ctx, 0); (void) duk_load_function(ctx); (void) duk_map_string(ctx, 0, NULL, NULL); (void) duk_new(ctx, 0); (void) duk_next(ctx, 0, 0); (void) duk_normalize_index(ctx, 0); (void) duk_pcall_method(ctx, 0); (void) duk_pcall_prop(ctx, 0, 0); (void) duk_pcall(ctx, 0); (void) duk_pcompile_lstring_filename(ctx, 0, "dummy", 0); (void) duk_pcompile_lstring(ctx, 0, "dummy", 0); (void) duk_pcompile_string_filename(ctx, 0, "dummy"); (void) duk_pcompile_string(ctx, 0, "dummy"); (void) duk_pcompile(ctx, 0); (void) duk_peval_lstring_noresult(ctx, "dummy", 0); (void) duk_peval_lstring(ctx, "dummy", 0); (void) duk_peval_noresult(ctx); (void) duk_peval_string_noresult(ctx, "dummy"); (void) duk_peval_string(ctx, "dummy"); (void) duk_peval(ctx); (void) duk_pnew(ctx, 0); (void) duk_pop_2(ctx); (void) duk_pop_3(ctx); (void) duk_pop_n(ctx, 0); (void) duk_pop(ctx); (void) duk_push_array(ctx); (void) duk_push_boolean(ctx, 0); (void) duk_push_buffer_object(ctx, 0, 0, 0, 0); (void) duk_push_buffer(ctx, 0, 0); (void) duk_push_c_function(ctx, NULL, 0); (void) duk_push_c_lightfunc(ctx, NULL, 0, 0, 0); (void) duk_push_context_dump(ctx); (void) duk_push_current_function(ctx); (void) duk_push_current_thread(ctx); (void) duk_push_dynamic_buffer(ctx, 0); (void) duk_push_error_object_va(ctx, 0, NULL, NULL); (void) duk_push_error_object(ctx, 0, "dummy"); (void) duk_push_external_buffer(ctx); (void) duk_push_false(ctx); (void) duk_push_fixed_buffer(ctx, 0); (void) duk_push_global_object(ctx); (void) duk_push_global_stash(ctx); (void) duk_push_heap_stash(ctx); (void) duk_push_heapptr(ctx, NULL); (void) duk_push_int(ctx, 0); (void) duk_push_lstring(ctx, "dummy", 0); (void) duk_push_nan(ctx); (void) duk_push_null(ctx); (void) duk_push_number(ctx, 0.0); (void) duk_push_object(ctx); (void) duk_push_pointer(ctx, NULL); (void) duk_push_sprintf(ctx, "dummy"); (void) duk_push_string(ctx, "dummy"); (void) duk_push_this(ctx); (void) duk_push_thread_new_globalenv(ctx); (void) duk_push_thread_stash(ctx, NULL); (void) duk_push_thread(ctx); (void) duk_push_true(ctx); (void) duk_push_uint(ctx, 0); (void) duk_push_undefined(ctx); (void) duk_push_vsprintf(ctx, "dummy", NULL); (void) duk_put_function_list(ctx, 0, NULL); (void) duk_put_global_string(ctx, NULL); (void) duk_put_number_list(ctx, 0, NULL); (void) duk_put_prop_index(ctx, 0, 0); (void) duk_put_prop_string(ctx, 0, "dummy"); (void) duk_put_prop(ctx, 0); (void) duk_realloc_raw(ctx, NULL, 0); (void) duk_realloc(ctx, NULL, 0); (void) duk_remove(ctx, 0); (void) duk_replace(ctx, 0); (void) duk_require_boolean(ctx, 0); (void) duk_require_buffer_data(ctx, 0, NULL); (void) duk_require_buffer(ctx, 0, NULL); (void) duk_require_c_function(ctx, 0); (void) duk_require_callable(ctx, 0); (void) duk_require_context(ctx, 0); (void) duk_require_function(ctx, 0); (void) duk_require_heapptr(ctx, 0); (void) duk_require_int(ctx, 0); (void) duk_require_lstring(ctx, 0, NULL); (void) duk_require_normalize_index(ctx, 0); (void) duk_require_null(ctx, 0); (void) duk_require_number(ctx, 0); (void) duk_require_object_coercible(ctx, 0); (void) duk_require_pointer(ctx, 0); (void) duk_require_stack_top(ctx, 0); (void) duk_require_stack(ctx, 0); (void) duk_require_string(ctx, 0); (void) duk_require_top_index(ctx); (void) duk_require_type_mask(ctx, 0, 0); (void) duk_require_uint(ctx, 0); (void) duk_require_undefined(ctx, 0); (void) duk_require_valid_index(ctx, 0); (void) duk_resize_buffer(ctx, 0, 0); (void) duk_safe_call(ctx, NULL, NULL, 0, 0); (void) duk_safe_to_lstring(ctx, 0, NULL); (void) duk_safe_to_string(ctx, 0); (void) duk_set_finalizer(ctx, 0); (void) duk_set_global_object(ctx); (void) duk_set_magic(ctx, 0, 0); (void) duk_set_prototype(ctx, 0); (void) duk_set_top(ctx, 0); (void) duk_steal_buffer(ctx, 0, NULL); (void) duk_strict_equals(ctx, 0, 0); (void) duk_substring(ctx, 0, 0, 0); (void) duk_swap_top(ctx, 0); (void) duk_swap(ctx, 0, 0); (void) duk_throw(ctx); (void) duk_to_boolean(ctx, 0); (void) duk_to_buffer(ctx, 0, NULL); (void) duk_to_defaultvalue(ctx, 0, 0); (void) duk_to_dynamic_buffer(ctx, 0, NULL); (void) duk_to_fixed_buffer(ctx, 0, NULL); (void) duk_to_int32(ctx, 0); (void) duk_to_int(ctx, 0); (void) duk_to_lstring(ctx, 0, NULL); (void) duk_to_null(ctx, 0); (void) duk_to_number(ctx, 0); (void) duk_to_object(ctx, 0); (void) duk_to_pointer(ctx, 0); (void) duk_to_primitive(ctx, 0, 0); (void) duk_to_string(ctx, 0); (void) duk_to_uint16(ctx, 0); (void) duk_to_uint32(ctx, 0); (void) duk_to_uint(ctx, 0); (void) duk_to_undefined(ctx, 0); (void) duk_trim(ctx, 0); (void) duk_xcopy_top(ctx, NULL, 0); (void) duk_xmove_top(ctx, NULL, 0); printf("never here\n"); fflush(stdout); return 0; }
duk_ret_t duk_bi_thread_yield(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval tv_tmp; duk_small_int_t is_error; DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T", duk_get_tval(ctx, 0), duk_get_tval(ctx, 1)); DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); DUK_ASSERT(thr->heap->curr_thread == thr); is_error = (duk_small_int_t) duk_to_boolean(ctx, 1); duk_set_top(ctx, 1); /* [ value ] */ /* * Thread state and calling context checks */ if (!thr->resumer) { DUK_DDPRINT("yield state invalid: current thread must have a resumer"); goto state_error; } DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); if (thr->callstack_top < 2) { DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"); goto state_error; } DUK_ASSERT((thr->callstack + thr->callstack_top - 1)->func != NULL); /* us */ DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION((thr->callstack + thr->callstack_top - 1)->func)); DUK_ASSERT((thr->callstack + thr->callstack_top - 2)->func != NULL); /* caller */ if (!DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->callstack + thr->callstack_top - 2)->func)) { DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"); goto state_error; } DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */ if (thr->callstack_preventcount != 1) { /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */ DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %d)", (int) thr->callstack_preventcount); goto state_error; } /* * The error object has been augmented with a traceback and other * info from its creation point -- usually the current thread. * The error handler, however, is called right before throwing * and runs in the yielder's thread. */ #if defined(DUK_USE_AUGMENT_ERROR_THROW) if (is_error) { DUK_ASSERT_TOP(ctx, 1); /* value (error) is at stack top */ duk_err_augment_error_throw(thr); /* in yielder's context */ } #endif #ifdef DUK_USE_DEBUG if (is_error) { DUK_DDDPRINT("YIELD ERROR: value=%!T", duk_get_tval(ctx, 0)); } else { DUK_DDDPRINT("YIELD NORMAL: value=%!T", duk_get_tval(ctx, 0)); } #endif /* * Process yield * * After longjmp(), processing continues in bytecode executor longjmp * handler, which will e.g. update thr->resumer to NULL. */ thr->heap->lj.type = DUK_LJ_TYPE_YIELD; /* lj value1: value */ DUK_ASSERT(thr->valstack_bottom < thr->valstack_top); DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value1); DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, &thr->valstack_bottom[0]); DUK_TVAL_INCREF(thr, &thr->heap->lj.value1); DUK_TVAL_DECREF(thr, &tv_tmp); thr->heap->lj.iserror = is_error; DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */ duk_err_longjmp(thr); /* execution resumes in bytecode executor */ return 0; /* never here */ state_error: DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid state for yield"); return 0; /* never here */ }
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) { duk_uint32_t len; duk_uint32_t i; duk_uarridx_t k; duk_bool_t bval; duk_small_int_t iter_type = duk_get_current_magic(ctx); duk_uint32_t res_length = 0; /* each call this helper serves has nargs==2 */ DUK_ASSERT_TOP(ctx, 2); len = duk__push_this_obj_len_u32(ctx); duk_require_callable(ctx, 0); /* if thisArg not supplied, behave as if undefined was supplied */ if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) { duk_push_array(ctx); } else { duk_push_undefined(ctx); } /* stack[0] = callback * stack[1] = thisArg * stack[2] = object * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop) * stack[4] = result array (or undefined) */ k = 0; /* result index for filter() */ for (i = 0; i < len; i++) { DUK_ASSERT_TOP(ctx, 5); if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) { #if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER) /* Real world behavior for map(): trailing non-existent * elements don't invoke the user callback, but are still * counted towards result 'length'. */ if (iter_type == DUK__ITER_MAP) { res_length = i + 1; } #else /* Standard behavior for map(): trailing non-existent * elements don't invoke the user callback and are not * counted towards result 'length'. */ #endif duk_pop(ctx); continue; } /* The original value needs to be preserved for filter(), hence * this funny order. We can't re-get the value because of side * effects. */ duk_dup(ctx, 0); duk_dup(ctx, 1); duk_dup(ctx, -3); duk_push_u32(ctx, i); duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */ duk_call_method(ctx, 3); /* -> [ ... val retval ] */ switch (iter_type) { case DUK__ITER_EVERY: bval = duk_to_boolean(ctx, -1); if (!bval) { /* stack top contains 'false' */ return 1; } break; case DUK__ITER_SOME: bval = duk_to_boolean(ctx, -1); if (bval) { /* stack top contains 'true' */ return 1; } break; case DUK__ITER_FOREACH: /* nop */ break; case DUK__ITER_MAP: duk_dup(ctx, -1); duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */ res_length = i + 1; break; case DUK__ITER_FILTER: bval = duk_to_boolean(ctx, -1); if (bval) { duk_dup(ctx, -2); /* orig value */ duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k); k++; res_length = k; } break; default: DUK_UNREACHABLE(); break; } duk_pop_2(ctx); DUK_ASSERT_TOP(ctx, 5); } switch (iter_type) { case DUK__ITER_EVERY: duk_push_true(ctx); break; case DUK__ITER_SOME: duk_push_false(ctx); break; case DUK__ITER_FOREACH: duk_push_undefined(ctx); break; case DUK__ITER_MAP: case DUK__ITER_FILTER: DUK_ASSERT_TOP(ctx, 5); DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */ duk_push_u32(ctx, res_length); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); break; default: DUK_UNREACHABLE(); break; } return 1; }
duk_ret_t duk_bi_thread_resume(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hthread *thr_resume; duk_tval tv_tmp; duk_tval *tv; duk_hobject *func; duk_small_int_t is_error; DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T", duk_get_tval(ctx, 0), duk_get_tval(ctx, 1), duk_get_tval(ctx, 2)); DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); DUK_ASSERT(thr->heap->curr_thread == thr); thr_resume = duk_require_hthread(ctx, 0); is_error = (duk_small_int_t) duk_to_boolean(ctx, 2); duk_set_top(ctx, 2); /* [ thread value ] */ /* * Thread state and calling context checks */ if (thr->callstack_top < 2) { DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"); goto state_error; } DUK_ASSERT((thr->callstack + thr->callstack_top - 1)->func != NULL); /* us */ DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION((thr->callstack + thr->callstack_top - 1)->func)); DUK_ASSERT((thr->callstack + thr->callstack_top - 2)->func != NULL); /* caller */ if (!DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->callstack + thr->callstack_top - 2)->func)) { DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"); goto state_error; } /* Note: there is no requirement that: 'thr->callstack_preventcount == 1' * like for yield. */ if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE && thr_resume->state != DUK_HTHREAD_STATE_YIELDED) { DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"); goto state_error; } DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE || thr_resume->state == DUK_HTHREAD_STATE_YIELDED); /* Further state-dependent pre-checks */ if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) { /* no pre-checks now, assume a previous yield() has left things in * tip-top shape (longjmp handler will assert for these). */ } else { DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE); if ((thr_resume->callstack_top != 0) || (thr_resume->valstack_top - thr_resume->valstack != 1)) { goto state_invalid_initial; } tv = &thr_resume->valstack_top[-1]; DUK_ASSERT(tv >= thr_resume->valstack && tv < thr_resume->valstack_top); if (!DUK_TVAL_IS_OBJECT(tv)) { goto state_invalid_initial; } func = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(func != NULL); if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) { /* Note: cannot be a bound function either right now, * this would be easy to relax though. */ goto state_invalid_initial; } } /* * The error object has been augmented with a traceback and other * info from its creation point -- usually another thread. The * error handler is called here right before throwing, but it also * runs in the resumer's thread. It might be nice to get a traceback * from the resumee but this is not the case now. */ #if defined(DUK_USE_AUGMENT_ERROR_THROW) if (is_error) { DUK_ASSERT_TOP(ctx, 2); /* value (error) is at stack top */ duk_err_augment_error_throw(thr); /* in resumer's context */ } #endif #ifdef DUK_USE_DEBUG /* debug logging */ if (is_error) { DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T", duk_get_tval(ctx, 0), duk_get_tval(ctx, 1)); } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) { DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T", duk_get_tval(ctx, 0), duk_get_tval(ctx, 1)); } else { DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T", duk_get_tval(ctx, 0), duk_get_tval(ctx, 1)); } #endif thr->heap->lj.type = DUK_LJ_TYPE_RESUME; /* lj value2: thread */ DUK_ASSERT(thr->valstack_bottom < thr->valstack_top); DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value2); DUK_TVAL_SET_TVAL(&thr->heap->lj.value2, &thr->valstack_bottom[0]); DUK_TVAL_INCREF(thr, &thr->heap->lj.value2); DUK_TVAL_DECREF(thr, &tv_tmp); /* lj value1: value */ DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top); DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value1); DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, &thr->valstack_bottom[1]); DUK_TVAL_INCREF(thr, &thr->heap->lj.value1); DUK_TVAL_DECREF(thr, &tv_tmp); thr->heap->lj.iserror = is_error; DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */ duk_err_longjmp(thr); /* execution resumes in bytecode executor */ return 0; /* never here */ state_invalid_initial: DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid initial thread state/stack"); return 0; /* never here */ state_error: DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid state for resume"); return 0; /* never here */ }
void JSEventHelper::HandleEvent(StringHash eventType, VariantMap& eventData) { if (object_.Null()) return; JSVM* vm = JSVM::GetJSVM(0); duk_context* ctx = vm->GetJSContext(); duk_idx_t top = duk_get_top(ctx); js_push_class_object_instance(ctx, this); duk_get_prop_string(ctx, -1, "__eventHelperFunctions"); assert(duk_is_object(ctx, -1)); duk_get_prop_string(ctx, -1, eventType.ToString().CString()); if (duk_is_function(ctx, -1)) { // look in the variant map cache duk_push_global_stash(ctx); duk_get_prop_index(ctx, -1, JS_GLOBALSTASH_VARIANTMAP_CACHE); duk_push_pointer(ctx, (void*) &eventData); duk_get_prop(ctx, -2); if (!duk_is_object(ctx, -1)) { // pop result duk_pop(ctx); // we need to push a new variant map and store to cache // the cache object will be cleared at the send end in the // global listener above js_push_variantmap(ctx, eventData); duk_push_pointer(ctx, (void*) &eventData); duk_dup(ctx, -2); duk_put_prop(ctx, -4); } duk_remove(ctx, -2); // vmap cache duk_remove(ctx, -2); // global stash if (duk_pcall(ctx, 1) != 0) { vm->SendJSErrorEvent(); } else { // For widget events, need to check return value // and set whether handled if (eventType == E_WIDGETEVENT) { if (duk_is_boolean(ctx, -1)) { if (duk_to_boolean(ctx, -1)) { eventData[WidgetEvent::P_HANDLED] = true; } } } } } duk_set_top(ctx, top); }
//duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index); duk_bool_t aperl_duk_to_boolean(duk_context *ctx, duk_idx_t index) { duk_bool_t ret = duk_to_boolean(ctx, index); return ret; }
bool Context::toBool(index_t i) { return (duk_to_boolean(m_handle, i) ? true: false); }
bool Get( duk_context * ctx, const int index, const bool * ) { dukbind_assert( duk_is_boolean( ctx, index ), "No conversion is allowed in Get methods" ); return duk_to_boolean( ctx, index ); }