static duk_ret_t test_pop_3a(duk_context *ctx, void *udata) { (void) udata; duk_pop_3(ctx); PRINTTOP(); duk_pop_3(ctx); PRINTTOP(); return 0; }
static duk_ret_t test_pop_3b(duk_context *ctx, void *udata) { (void) udata; duk_pop_3(ctx); PRINTTOP(); duk_pop_3(ctx); PRINTTOP(); /* no more entries, causes error */ duk_pop_3(ctx); PRINTTOP(); return 0; }
DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) { /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */ static const duk_uint16_t stridx_logfunc[6] = { DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO, DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL }; DUK_ASSERT_CTX_VALID(ctx); if (level < 0) { level = 0; } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) { level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1; } duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG); duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]); duk_dup(ctx, -2); /* [ ... Logger clog logfunc clog ] */ duk_push_vsprintf(ctx, fmt, ap); /* [ ... Logger clog logfunc clog(=this) msg ] */ duk_call_method(ctx, 1 /*nargs*/); /* [ ... Logger clog res ] */ duk_pop_3(ctx); }
void JSEventDispatcher::EndSendEvent(Context* context, Object* sender, StringHash eventType, VariantMap& eventData) { if (!jsEvents_.Contains(eventType)) return; JSVM* vm = JSVM::GetJSVM(NULL); if (!vm) return; duk_context* ctx = vm->GetJSContext(); 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 this issue is addressed, revisit this to simply remove // the variantmap object from the cache, if the user explicitly // keeps the event object alive in a local closure, that is allowed // (though, will keep object properties from being GC'd) // https://github.com/svaarala/duktape/issues/229 // Ok, this is unfortunate, in an event callback it is possible // to capture the Proxy object which represents the event VariantMap // in a function() {} closure, which will keep the event data alive // until the function happens to be gc'd (it is a member of the eventhandler) // which will leave things like scenes up if there was a P_SCENE event data // member, etc // So, we need to check if we have an object in the variant map cache // and thense call it's delete property method on the Proxy, which will clear // all the data (the proxy can still be alive as a captured local, though // the members won't be held // This all makes it that much more important that the pointer to eventData // is consistent across entire event, otherwise references may be held // see note above about: https://github.com/svaarala/duktape/issues/229 if (duk_is_object(ctx, -1)) { // deletes all properties, thus freeing references, even if // the variant map object is held onto by script (it will be invalid, post // event send) // see JSAPI.cpp variantmap_property_deleteproperty duk_del_prop_index(ctx, -1, 0); duk_push_pointer(ctx, (void*) &eventData); duk_push_undefined(ctx); // clear the variant map object from the cache duk_put_prop(ctx, -4); } duk_pop_3(ctx); }
static duk_bool_t duk__get_cached_module(duk_context *ctx, const char *id) { duk_push_global_stash(ctx); (void) duk_get_prop_string(ctx, -1, "\xff" "requireCache"); if (duk_get_prop_string(ctx, -1, id)) { duk_remove(ctx, -2); duk_remove(ctx, -2); return 1; } else { duk_pop_3(ctx); return 0; } }
int w_LocalStorage_prototype_getItem(duk_context *ctx) { const char *key = duk_require_string(ctx, 0); duk_push_this(ctx); /* this */ duk_get_prop_string(ctx, -1, "__MURAL_DATA__"); /* this, __MURAL_DATA__ */ duk_get_prop_string(ctx, -1, key); /* this, __MURAL_DATA__, value */ const char *value = duk_to_string(ctx, -1); /* this, __MURAL_DATA__, string(value) */ duk_pop_3(ctx); duk_push_string(ctx, value); return 1; }
/* Place a `module` object on the top of the value stack into the require cache * based on its `.id` property. As a convenience to the caller, leave the * object on top of the value stack afterwards. */ static void duk__put_cached_module(duk_context *ctx) { /* [ ... module ] */ duk_push_global_stash(ctx); (void) duk_get_prop_string(ctx, -1, "\xff" "requireCache"); duk_dup(ctx, -3); /* [ ... module stash req_cache module ] */ (void) duk_get_prop_string(ctx, -1, "id"); duk_dup(ctx, -2); duk_put_prop(ctx, -4); duk_pop_3(ctx); /* [ ... module ] */ }
AJ_Status AJS_HandleJoinSessionReply(duk_context* ctx, AJ_Message* msg) { const char* peer = NULL; SessionInfo* sessionInfo = NULL; uint32_t replySerial = msg->replySerial; uint8_t joined = FALSE; AJS_GetGlobalStashObject(ctx, "sessions"); duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); while (duk_next(ctx, -1, 1)) { peer = duk_get_string(ctx, -2); AJ_ASSERT(duk_is_object(ctx, -1)); duk_get_prop_string(ctx, -1, "info"); sessionInfo = duk_get_buffer(ctx, -1, NULL); AJ_ASSERT(sessionInfo); duk_pop_3(ctx); if (sessionInfo->replySerial == replySerial) { uint32_t sessionId; uint32_t replyStatus; /* * Check if the join was successful */ AJ_UnmarshalArgs(msg, "uu", &replyStatus, &sessionId); if (replyStatus == AJ_JOINSESSION_REPLY_SUCCESS) { /* * TODO - if we have a well-known name send a ping to get the unique name */ sessionInfo->sessionId = sessionId; joined = TRUE; } sessionInfo->replySerial = 0; break; } } duk_pop(ctx); /* Pop the enum */ if (joined) { /* * TODO - we may need to initiate authentication with the remote peer */ AnnouncementCallbacks(ctx, peer, sessionInfo); } /* Pop "sessions" */ duk_pop(ctx); return AJ_OK; }
/* * Delete session info object pointed to by sessionId. If sessionId * is zero then delete all session info objects. */ static AJ_Status RemoveSessions(duk_context* ctx, uint32_t sessionId) { AJ_Status status = AJ_OK; AJS_GetGlobalStashObject(ctx, "sessions"); duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); while (duk_next(ctx, -1, 1)) { SessionInfo* sessionInfo; const char* peer = duk_get_string(ctx, -2); duk_get_prop_string(ctx, -1, "info"); sessionInfo = duk_get_buffer(ctx, -1, NULL); duk_pop_3(ctx); if (sessionId == 0) { AJ_InfoPrintf(("RemoveSessions(): Leaving session: %u\n", sessionInfo->sessionId)); status = AJ_BusLeaveSession(AJS_GetBusAttachment(), sessionInfo->sessionId); } else if (sessionInfo->sessionId == sessionId) { status = AJ_BusLeaveSession(AJS_GetBusAttachment(), sessionInfo->sessionId); duk_del_prop_string(ctx, -2, peer); break; } } duk_pop_2(ctx); /* * TODO - this is not all that useful because it only indicates that a peer has gone away * without being able to specify exactly which services are affected. The problem is we cannot * hold a reference to the service object because we a relying on the service object finalizer * to clean up sessions that are no longer in use. If we hold a reference the finalizer will * never get called. */ if (sessionId != 0) { AJS_GetAllJoynProperty(ctx, "onPeerDisconnected"); if (duk_is_callable(ctx, -1)) { if (duk_pcall(ctx, 0) != DUK_EXEC_SUCCESS) { AJS_ConsoleSignalError(ctx); } } duk_pop(ctx); } else { AJS_ClearGlobalStashObject(ctx, "sessions"); } return status; }
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; }
/*----------------------------------------------------------------------------*/ void kbjs_register_PinIds(duk_context *context) { /* Get kb.rpi2 object */ /* STACK: [global] */ duk_push_global_object(context); /* STACK: [global, kb] */ duk_get_prop_string(context, (duk_idx_t)-1, "kb"); /* STACK: [global, kb, rpi] */ duk_get_prop_string(context, (duk_idx_t)-1, "rpi2"); /* Create storage for enums on heap_stash */ /* STACK: [global, kb, rpi, stash] */ duk_push_heap_stash(context); /* STACK: [global, kb, rpi, stash, {} */ duk_push_object(context); /* STACK: [global, kb, rpi, stash */ duk_put_prop_string(context, (duk_idx_t)-2, kbjs_PIN_ID_PROTO_STASH_KEY); /* STACK: [global, kb, rpi */ duk_pop(context); /* Create PinId enums */ #define CREATE_ENUM_(INDEX) \ kbjs_PIN_IDS[kb_rpi2_PIN##INDEX] = (kbjs_PinId){kb_rpi2_PIN##INDEX, \ "kb.rpi2.PIN" #INDEX, \ context, \ ""}; \ kbjs_get_stash_key(KBJS_TYPES_STASH_KEY_LENGTH, \ kbjs_PIN_IDS[kb_rpi2_PIN##INDEX].js_stash_key); \ /* STACK: [global, kb, rpi, "PIN*"] */ \ duk_push_string(context, "PIN" #INDEX); \ /* STACK: [global, kb, rpi, "PIN*", {}] */ \ duk_push_object(context); \ /* STACK: [global, kb, rpi, "PIN*", {}, "instance_ptr"] */ \ duk_push_string(context, KBJS_INSTANCE_PTR); \ /* STACK: [global, kb, rpi, "PIN*", {}, "instance_ptr", void*] */ \ duk_push_pointer(context, kbjs_PIN_IDS + kb_rpi2_PIN##INDEX); \ /* STACK: [global, kb, rpi, "PIN*", {}] */ \ duk_put_prop(context, (duk_idx_t)-3); \ /* STACK: [global, kb, rpi, "PIN*", {}, "toString"] */ \ duk_push_string(context, "toString"); \ /* STACK: [global, kb, rpi, "PIN*", {}, "toString", function] */ \ duk_push_c_function(context, kbjs_PinId_str, (duk_idx_t)0); \ /* STACK: [global, kb, rpi, "PIN*", {}] */ \ duk_put_prop(context, (duk_idx_t)-3); \ /* STACK: [global, kb, rpi, "PIN*", {}, "INDEX"] */ \ duk_push_string(context, #INDEX); \ /* STACK: [global, kb, rpi, "PIN*", {}] */ \ duk_put_prop_string(context, (duk_idx_t)-2, kbjs_PIN_ID_VALUE_KEY); \ /* STACK: [global, kb, rpi, "PIN*", {}, stash] */ \ duk_push_heap_stash(context); \ /* STACK: [global, kb, rpi, "PIN*", {}, stash, {}] */ \ duk_get_prop_string(context, \ (duk_idx_t)-1, \ kbjs_PIN_ID_PROTO_STASH_KEY); \ /* STACK: [global, kb, rpi, "PIN*", {}, stash, {}, {}] */ \ duk_dup(context, (duk_idx_t)-3); \ /* STACK: [global, kb, rpi, "PIN*", {}, stash, {} */ \ duk_put_prop_string(context, (duk_idx_t)-2, #INDEX); \ /* STACK: [global, kb, rpi, "PIN*", {} */ \ duk_pop_2(context); \ /* STACK: [global, kb, rpi] */ \ duk_put_prop(context, (duk_idx_t)-3); #define CREATE_ENUM(PREFIX1, PREFIX2) \ CREATE_ENUM_(PREFIX1##1) \ CREATE_ENUM_(PREFIX1##2) \ CREATE_ENUM_(PREFIX1##3) \ CREATE_ENUM_(PREFIX1##4) \ CREATE_ENUM_(PREFIX1##5) \ CREATE_ENUM_(PREFIX1##6) \ CREATE_ENUM_(PREFIX1##7) \ CREATE_ENUM_(PREFIX1##8) \ CREATE_ENUM_(PREFIX1##9) \ CREATE_ENUM_(PREFIX2##0) CREATE_ENUM( , 1) CREATE_ENUM(1, 2) CREATE_ENUM(2, 3) CREATE_ENUM(3, 4) #undef CREATE_ENUM_ #undef CREATE_ENUM /* Clean up */ /* STACK: [] */ duk_pop_3(context); }
//void duk_pop_3(duk_context *ctx); void aperl_duk_pop_3(duk_context *ctx) { duk_pop_3(ctx); }
DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { duk_context *ctx = (duk_context *) thr; duk_bitdecoder_ctx bd_ctx; duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */ duk_hobject *h; duk_small_uint_t i, j; DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS)); DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx)); bd->data = (const duk_uint8_t *) duk_builtins_data; bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH; /* * First create all built-in bare objects on the empty valstack. * * Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value * stack indices matching their eventual thr->builtins[] index. * * Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS] * will exist on the value stack during init but won't be placed * into thr->builtins[]. These are objects referenced in some way * from thr->builtins[] roots but which don't need to be indexed by * Duktape through thr->builtins[] (e.g. user custom objects). */ duk_require_stack(ctx, DUK_NUM_ALL_BUILTINS); DUK_DD(DUK_DDPRINT("create empty built-ins")); DUK_ASSERT_TOP(ctx, 0); for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { duk_small_uint_t class_num; duk_small_int_t len = -1; /* must be signed */ class_num = (duk_small_uint_t) duk_bd_decode(bd, DUK__CLASS_BITS); len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { duk_small_uint_t natidx; duk_int_t c_nargs; /* must hold DUK_VARARGS */ duk_c_function c_func; duk_int16_t magic; DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len)); DUK_ASSERT(len >= 0); natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS); c_func = duk_bi_native_functions[natidx]; c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } /* XXX: set magic directly here? (it could share the c_nargs arg) */ duk_push_c_function_noexotic(ctx, c_func, c_nargs); h = duk_require_hobject(ctx, -1); DUK_ASSERT(h != NULL); /* Currently all built-in native functions are strict. * duk_push_c_function() now sets strict flag, so * assert for it. */ DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h)); /* XXX: function properties */ /* Built-in 'name' is not writable by default. Function '.name' * is writable to allow user code to set a '.name' on a native * function. */ duk__push_stridx_or_string(ctx, bd); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, (i == DUK_BIDX_FUNCTION_PROTOTYPE) ? DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE); /* Almost all global level Function objects are constructable * but not all: Function.prototype is a non-constructable, * callable Function. */ if (duk_bd_decode_flag(bd)) { DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h)); } else { DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h); } /* Cast converts magic to 16-bit signed value */ magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/); ((duk_hnatfunc *) h)->magic = magic; } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) { duk_push_array(ctx); } else { duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE, -1); /* no prototype or class yet */ } h = duk_require_hobject(ctx, -1); DUK_ASSERT(h != NULL); DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num); if (i < DUK_NUM_BUILTINS) { thr->builtins[i] = h; DUK_HOBJECT_INCREF(thr, &h->hdr); } if (len >= 0) { /* * For top-level objects, 'length' property has the following * default attributes: non-writable, non-enumerable, non-configurable * (E5 Section 15). * * However, 'length' property for Array.prototype has attributes * expected of an Array instance which are different: writable, * non-enumerable, non-configurable (E5 Section 15.4.5.2). * * Because Array .length is virtual, it's not encoded in the init * data separately. */ DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY); /* .length is virtual */ duk_push_int(ctx, len); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); } /* enable exotic behaviors last */ if (class_num == DUK_HOBJECT_CLASS_ARRAY) { DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)); /* set by duk_push_array() */ } if (class_num == DUK_HOBJECT_CLASS_STRING) { DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h); } /* some assertions */ DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h)); /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h)); /* DUK_HOBJECT_FLAG_NATFUNC varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY); /* DUK_HOBJECT_FLAG_STRICT varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */ DUK_HOBJECT_HAS_NEWENV(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h)); /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */ /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */ DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)); DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len)); } /* * Then decode the builtins init data (see genbuiltins.py) to * init objects */ DUK_DD(DUK_DDPRINT("initialize built-in object properties")); for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { duk_small_uint_t t; duk_small_uint_t num; DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i)); h = duk_require_hobject(ctx, i); DUK_ASSERT(h != NULL); t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t)); DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_require_hobject(ctx, t)); } t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { /* 'prototype' property for all built-in objects (which have it) has attributes: * [[Writable]] = false, * [[Enumerable]] = false, * [[Configurable]] = false */ DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t)); duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE); } t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS); if (t != DUK__NO_BIDX_MARKER) { /* 'constructor' property for all built-in objects (which have it) has attributes: * [[Writable]] = true, * [[Enumerable]] = false, * [[Configurable]] = true */ DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t)); duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC); } /* normal valued properties */ num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS); DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num)); for (j = 0; j < num; j++) { duk_small_uint_t prop_flags; duk__push_stridx_or_string(ctx, bd); /* * Property attribute defaults are defined in E5 Section 15 (first * few pages); there is a default for all properties and a special * default for 'length' properties. Variation from the defaults is * signaled using a single flag bit in the bitstream. */ if (duk_bd_decode_flag(bd)) { prop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS); } else { prop_flags = DUK_PROPDESC_FLAGS_WC; } t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS); DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld", (long) i, (long) j, duk_get_tval(ctx, -1), (unsigned long) prop_flags, (long) t)); switch (t) { case DUK__PROP_TYPE_DOUBLE: { duk__push_double(ctx, bd); break; } case DUK__PROP_TYPE_STRING: { duk__push_string(ctx, bd); break; } case DUK__PROP_TYPE_STRIDX: { duk__push_stridx(ctx, bd); break; } case DUK__PROP_TYPE_BUILTIN: { duk_small_uint_t bidx; bidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS); DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER); duk_dup(ctx, (duk_idx_t) bidx); break; } case DUK__PROP_TYPE_UNDEFINED: { duk_push_undefined(ctx); break; } case DUK__PROP_TYPE_BOOLEAN_TRUE: { duk_push_true(ctx); break; } case DUK__PROP_TYPE_BOOLEAN_FALSE: { duk_push_false(ctx); break; } case DUK__PROP_TYPE_ACCESSOR: { duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS); duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS); duk_c_function c_func_getter; duk_c_function c_func_setter; /* XXX: this is a bit awkward because there is no exposed helper * in the API style, only this internal helper. */ DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx", (long) i, duk_get_tval(ctx, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags)); c_func_getter = duk_bi_native_functions[natidx_getter]; c_func_setter = duk_bi_native_functions[natidx_setter]; duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */ duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */ /* XXX: magic for getter/setter? use duk_def_prop()? */ DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */ prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */ duk_hobject_define_accessor_internal(thr, duk_require_hobject(ctx, i), duk_get_hstring(ctx, -3), duk_require_hobject(ctx, -2), duk_require_hobject(ctx, -1), prop_flags); duk_pop_3(ctx); /* key, getter and setter, now reachable through object */ goto skip_value; } default: { /* exhaustive */ DUK_UNREACHABLE(); } } DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0); duk_xdef_prop(ctx, i, prop_flags); skip_value: continue; /* avoid empty label at the end of a compound statement */ } /* native function properties */ num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS); DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num)); for (j = 0; j < num; j++) { duk_hstring *h_key; duk_small_uint_t natidx; duk_int_t c_nargs; /* must hold DUK_VARARGS */ duk_small_uint_t c_length; duk_int16_t magic; duk_c_function c_func; duk_hnatfunc *h_func; #if defined(DUK_USE_LIGHTFUNC_BUILTINS) duk_small_int_t lightfunc_eligible; #endif duk__push_stridx_or_string(ctx, bd); h_key = duk_get_hstring(ctx, -1); DUK_ASSERT(h_key != NULL); DUK_UNREF(h_key); natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS); c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS); c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/); if (c_nargs == DUK__NARGS_VARARGS_MARKER) { c_nargs = DUK_VARARGS; } c_func = duk_bi_native_functions[natidx]; DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld", (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length, (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs))); /* Cast converts magic to 16-bit signed value */ magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0); #if defined(DUK_USE_LIGHTFUNC_BUILTINS) lightfunc_eligible = ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) && (c_length <= DUK_LFUNC_LENGTH_MAX) && (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX); if (h_key == DUK_HTHREAD_STRING_EVAL(thr) || h_key == DUK_HTHREAD_STRING_YIELD(thr) || h_key == DUK_HTHREAD_STRING_RESUME(thr)) { /* These functions have trouble working as lightfuncs. * Some of them have specific asserts and some may have * additional properties (e.g. 'require.id' may be written). */ DUK_D(DUK_DPRINT("reject as lightfunc: key=%!O, i=%d, j=%d", (duk_heaphdr *) h_key, (int) i, (int) j)); lightfunc_eligible = 0; } if (lightfunc_eligible) { duk_tval tv_lfunc; duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs); duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs); DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags); duk_push_tval(ctx, &tv_lfunc); DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(ctx, -1))); goto lightfunc_skip; } DUK_D(DUK_DPRINT("built-in function NOT ELIGIBLE as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic)); #endif /* DUK_USE_LIGHTFUNC_BUILTINS */ /* [ (builtin objects) name ] */ duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs); h_func = duk_require_hnatfunc(ctx, -1); DUK_UNREF(h_func); /* Currently all built-in native functions are strict. * This doesn't matter for many functions, but e.g. * String.prototype.charAt (and other string functions) * rely on being strict so that their 'this' binding is * not automatically coerced. */ DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func); /* No built-in functions are constructable except the top * level ones (Number, etc). */ DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func)); /* XXX: any way to avoid decoding magic bit; there are quite * many function properties and relatively few with magic values. */ h_func->magic = magic; /* [ (builtin objects) name func ] */ duk_push_int(ctx, c_length); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); duk_dup(ctx, -2); duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* XXX: other properties of function instances; 'arguments', 'caller'. */ DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T", (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1))); /* [ (builtin objects) name func ] */ /* * The default property attributes are correct for all * function valued properties of built-in objects now. */ #if defined(DUK_USE_LIGHTFUNC_BUILTINS) lightfunc_skip: #endif duk_xdef_prop(ctx, i, DUK_PROPDESC_FLAGS_WC); /* [ (builtin objects) ] */ } } /* * Special post-tweaks, for cases not covered by the init data format. * * - Set Date.prototype.toGMTString to Date.prototype.toUTCString. * toGMTString is required to have the same Function object as * toUTCString in E5 Section B.2.6. Note that while Smjs respects * this, V8 does not (the Function objects are distinct). * * - Make DoubleError non-extensible. * * - Add info about most important effective compile options to Duktape. * * - Possibly remove some properties (values or methods) which are not * desirable with current feature options but are not currently * conditional in init data. */ duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING); duk_xdef_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC); h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR); DUK_ASSERT(h != NULL); DUK_HOBJECT_CLEAR_EXTENSIBLE(h); #if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY) DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features")); (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW); #endif #if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF) DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features")); (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW); #endif /* XXX: relocate */ duk_push_string(ctx, /* Endianness indicator */ #if defined(DUK_USE_INTEGER_LE) "l" #elif defined(DUK_USE_INTEGER_BE) "b" #elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */ "m" #else "?" #endif #if defined(DUK_USE_DOUBLE_LE) "l" #elif defined(DUK_USE_DOUBLE_BE) "b" #elif defined(DUK_USE_DOUBLE_ME) "m" #else "?" #endif " " /* Packed or unpacked tval */ #if defined(DUK_USE_PACKED_TVAL) "p" #else "u" #endif #if defined(DUK_USE_FASTINT) "f" #endif " " /* Low memory options */ #if defined(DUK_USE_STRTAB_CHAIN) "c" /* chain */ #elif defined(DUK_USE_STRTAB_PROBE) "p" /* probe */ #else "?" #endif #if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16) "n" #endif #if defined(DUK_USE_HEAPPTR16) "h" #endif #if defined(DUK_USE_DATAPTR16) "d" #endif #if defined(DUK_USE_FUNCPTR16) "f" #endif #if defined(DUK_USE_REFCOUNT16) "R" #endif #if defined(DUK_USE_STRHASH16) "H" #endif #if defined(DUK_USE_STRLEN16) "S" #endif #if defined(DUK_USE_BUFLEN16) "B" #endif #if defined(DUK_USE_OBJSIZES16) "O" #endif #if defined(DUK_USE_LIGHTFUNC_BUILTINS) "L" #endif #if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS) /* XXX: This won't be shown in practice now * because this code is not run when builtins * are in ROM. */ "Z" #endif " " /* Object property allocation layout */ #if defined(DUK_USE_HOBJECT_LAYOUT_1) "p1" #elif defined(DUK_USE_HOBJECT_LAYOUT_2) "p2" #elif defined(DUK_USE_HOBJECT_LAYOUT_3) "p3" #else "p?" #endif " " /* Alignment guarantee */ #if (DUK_USE_ALIGN_BY == 4) "a4" #elif (DUK_USE_ALIGN_BY == 8) "a8" #elif (DUK_USE_ALIGN_BY == 1) "a1" #else #error invalid DUK_USE_ALIGN_BY #endif " " /* Architecture, OS, and compiler strings */ DUK_USE_ARCH_STRING " " DUK_USE_OS_STRING " " DUK_USE_COMPILER_STRING); duk_xdef_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC); /* * InitJS code - Ecmascript code evaluated from a built-in source * which provides e.g. backward compatibility. User can also provide * JS code to be evaluated at startup. */ #ifdef DUK_USE_BUILTIN_INITJS /* XXX: compression */ DUK_DD(DUK_DDPRINT("running built-in initjs")); duk_eval_string(ctx, (const char *) duk_initjs_data); /* initjs data is NUL terminated */ duk_pop(ctx); #endif /* DUK_USE_BUILTIN_INITJS */ #ifdef DUK_USE_USER_INITJS /* XXX: compression (as an option) */ DUK_DD(DUK_DDPRINT("running user initjs")); duk_eval_string_noresult(ctx, (const char *) DUK_USE_USER_INITJS); #endif /* DUK_USE_USER_INITJS */ /* * Since built-ins are not often extended, compact them. */ DUK_DD(DUK_DDPRINT("compact built-ins")); for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { duk_hobject_compact_props(thr, duk_require_hobject(ctx, i)); } DUK_D(DUK_DPRINT("INITBUILTINS END")); #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO", (long) i, (duk_heaphdr *) duk_require_hobject(ctx, i))); } #endif /* * Pop built-ins from stack: they are now INCREF'd and * reachable from the builtins[] array or indirectly * through builtins[]. */ duk_set_top(ctx, 0); DUK_ASSERT_TOP(ctx, 0); }
DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) { duk_hthread *thr = (duk_hthread *) ctx; duk_idx_t idx_td; duk_small_int_t i; /* traceback depth fits into 16 bits */ duk_small_int_t t; /* stack type fits into 16 bits */ duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */ const char *str_tailcall = " tailcall"; const char *str_strict = " strict"; const char *str_construct = " construct"; const char *str_prevyield = " preventsyield"; const char *str_directeval = " directeval"; const char *str_empty = ""; DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */ DUK_UNREF(thr); duk_push_this(ctx); duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TRACEDATA); idx_td = duk_get_top_index(ctx); duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE); duk_push_this(ctx); /* [ ... this tracedata sep this ] */ /* XXX: skip null filename? */ if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) { /* Current tracedata contains 2 entries per callstack entry. */ for (i = 0; ; i += 2) { duk_int_t pc; duk_int_t line; duk_int_t flags; duk_double_t d; const char *funcname; const char *filename; duk_hobject *h_func; duk_hstring *h_name; duk_require_stack(ctx, 5); duk_get_prop_index(ctx, idx_td, i); duk_get_prop_index(ctx, idx_td, i + 1); d = duk_to_number_m1(ctx); pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32); flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32); t = (duk_small_int_t) duk_get_type(ctx, -2); if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) { /* * Ecmascript/native function call or lightfunc call */ count_func++; /* [ ... v1(func) v2(pc+flags) ] */ h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */ /* These may be systematically omitted by Duktape * with certain config options, but allow user to * set them on a case-by-case basis. */ duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME); duk_get_prop_stridx_short(ctx, -3, DUK_STRIDX_FILE_NAME); #if defined(DUK_USE_PC2LINE) line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc); #else line = 0; #endif /* [ ... v1 v2 name filename ] */ /* When looking for .fileName/.lineNumber, blame first * function which has a .fileName. */ if (duk_is_string_notsymbol(ctx, -1)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { duk_push_int(ctx, line); return 1; } } /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */ /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */ h_name = duk_get_hstring_notsymbol(ctx, -2); /* may be NULL */ funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ? "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name); filename = duk_get_string_notsymbol(ctx, -1); filename = filename ? filename : ""; DUK_ASSERT(funcname != NULL); DUK_ASSERT(filename != NULL); if (h_func == NULL) { duk_push_sprintf(ctx, "at %s light%s%s%s%s%s", (const char *) funcname, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) { duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s", (const char *) funcname, (const char *) filename, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } else { duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s", (const char *) funcname, (const char *) filename, (long) line, (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); } duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */ duk_pop_3(ctx); /* -> [ ... str ] */ } else if (t == DUK_TYPE_STRING) { const char *str_file; /* * __FILE__ / __LINE__ entry, here 'pc' is line number directly. * Sometimes __FILE__ / __LINE__ is reported as the source for * the error (fileName, lineNumber), sometimes not. */ /* [ ... v1(filename) v2(line+flags) ] */ /* When looking for .fileName/.lineNumber, blame compilation * or C call site unless flagged not to do so. */ if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) { if (output_type == DUK__OUTPUT_TYPE_FILENAME) { duk_pop(ctx); return 1; } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { duk_push_int(ctx, pc); return 1; } } /* Tracedata is trusted but avoid any risk of using a NULL * for %s format because it has undefined behavior. Symbols * don't need to be explicitly rejected as they pose no memory * safety issues. */ str_file = (const char *) duk_get_string(ctx, -2); duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal", (const char *) (str_file ? str_file : "null"), (long) pc); duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */ duk_pop(ctx); /* -> [ ... str ] */ } else { /* unknown, ignore */ duk_pop_2(ctx); break; } } if (count_func >= DUK_USE_TRACEBACK_DEPTH) { /* Possibly truncated; there is no explicit truncation * marker so this is the best we can do. */ duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS); } } /* [ ... this tracedata sep this str1 ... strN ] */ if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) { return 0; } else { /* The 'this' after 'sep' will get ToString() coerced by * duk_join() automatically. We don't want to do that * coercion when providing .fileName or .lineNumber (GH-254). */ duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/); return 1; } }
JavaScriptObject::JavaScriptObject(JavaTypeMap& typeMap, JNIEnv* env, duk_context* context, jstring name, jobjectArray methods) : m_name(JString(env, name).str()) , m_context(context) , m_instance(nullptr) , m_nextFinalizer(nullptr) { CHECK_STACK(m_context); duk_push_global_object(m_context); if (!duk_get_prop_string(m_context, -1, m_name.c_str())) { duk_pop_2(m_context); throw std::invalid_argument("A global JavaScript object called " + m_name + " was not found"); } m_instance = duk_get_heapptr(m_context, -1); if (m_instance == nullptr) { duk_pop_2(m_context); throw std::invalid_argument("JavaScript global called " + m_name + " is not an object"); } // Make sure that the object has all of the methods we want. jmethodID getName = nullptr; const jsize numArgs = env->GetArrayLength(methods); for (jsize i = 0; i < numArgs; ++i) { auto method = env->GetObjectArrayElement(methods, i); if (getName == nullptr) { jclass methodClass = env->GetObjectClass(method); getName = env->GetMethodID(methodClass, "getName", "()Ljava/lang/String;"); } // Sanity check that as of right now, the object we're proxying has a function with this name. const JString methodName(env, static_cast<jstring>(env->CallObjectMethod(method, getName))); if (!duk_get_prop_string(m_context, -1, methodName)) { duk_pop_3(m_context); throw std::runtime_error("JavaScript global " + m_name + " has no method called " + methodName.str()); } else if (!duk_is_callable(m_context, -1)) { duk_pop_3(m_context); throw std::runtime_error("JavaScript property " + m_name + "." + methodName.str() + " not callable"); } try { // Build a call wrapper that handles marshalling the arguments and return value. m_methods.emplace(std::make_pair(env->FromReflectedMethod(method), buildMethodBody(typeMap, env, method, methodName.str()))); } catch (const std::invalid_argument& e) { duk_pop_3(m_context); throw std::invalid_argument("In proxied method \"" + m_name + "." + methodName.str() + "\": " + e.what()); } // Pop the method property. duk_pop(m_context); } // Keep track of any previously registered finalizer. duk_get_finalizer(m_context, -1); m_nextFinalizer = duk_is_c_function(m_context, -1) ? duk_get_c_function(m_context, -1) : nullptr; duk_pop(m_context); duk_push_c_function(m_context, JavaScriptObject::finalizer, 1); duk_set_finalizer(m_context, -2); // Add 'this' to the list of pointers attached to the proxied instance. // TODO: don't use an array here, just use a separate hidden property for each proxy. if (!duk_has_prop_string(m_context, -1, WRAPPER_THIS_PROP_NAME)) { duk_push_array(m_context); } else { duk_get_prop_string(m_context, -1, WRAPPER_THIS_PROP_NAME); } const duk_size_t length = duk_get_length(m_context, -1); duk_push_pointer(m_context, this); duk_put_prop_index(m_context, -2, static_cast<duk_uarridx_t>(length)); // Add the array (back) to the instance. duk_put_prop_string(m_context, -2, WRAPPER_THIS_PROP_NAME); // Pop the global and our instance. duk_pop_2(m_context); }
AJ_Status AJS_FoundAdvertisedName(duk_context* ctx, AJ_Message* msg) { AJ_Status status; SessionInfo* sessionInfo; const char* name; const char* prefix; uint16_t port; uint16_t mask; duk_idx_t fnmeIdx; duk_idx_t sessIdx; AJ_UnmarshalArgs(msg, "sqs", &name, &mask, &prefix); AJ_InfoPrintf(("AJS_FoundAdvertisedName %s %s\n", prefix, name)); AJS_GetGlobalStashObject(ctx, "sessions"); sessIdx = duk_get_top_index(ctx); /* * If the name is already listed we can ignore this signal */ if (duk_get_prop_string(ctx, -1, name)) { duk_pop_2(ctx); return AJ_OK; } /* * Check if there is a callback registered for this name (actually the prefix) */ AJS_GetGlobalStashObject(ctx, "findName"); duk_get_prop_string(ctx, -1, prefix); if (duk_is_undefined(ctx, -1)) { duk_pop_3(ctx); return AJ_OK; } fnmeIdx = duk_get_top_index(ctx); /* * From here on we make it look like we received an announcement */ port = AJS_GetIntProp(ctx, fnmeIdx, "port"); status = AJ_BusJoinSession(msg->bus, name, port, NULL); if (status == AJ_OK) { duk_idx_t anIdx; duk_idx_t svcIdx; /* * Create service object and add it to the sessions array */ svcIdx = duk_push_object(ctx); /* * Set the "info" and "anno" properties on the service object */ sessionInfo = duk_push_fixed_buffer(ctx, sizeof(SessionInfo)); sessionInfo->port = port; duk_put_prop_string(ctx, svcIdx, "info"); anIdx = duk_push_array(ctx); /* * Push array of interfaces */ duk_get_prop_string(ctx, fnmeIdx, "interfaces"); /* * Set the callback to be called when the JOIN_SESSION reply is received */ AJS_GetGlobalStashObject(ctx, "serviceCB"); duk_get_prop_index(ctx, -2, 0); /* key - first interface in "interfaces" array */ duk_get_prop_string(ctx, fnmeIdx, "cb"); /* val - callback function */ duk_put_prop(ctx, -3); duk_pop(ctx); /* Interfaces array is at the top of the stack */ AddServiceObject(ctx, sessionInfo, AJS_GetStringProp(ctx, fnmeIdx, "path"), name); /* * Append service object to the announcements array for processing later */ duk_put_prop_index(ctx, anIdx, duk_get_length(ctx, anIdx)); AJ_ASSERT(duk_get_top_index(ctx) == anIdx); duk_put_prop_string(ctx, svcIdx, "anno"); AJ_ASSERT(duk_get_top_index(ctx) == svcIdx); duk_put_prop_string(ctx, sessIdx, name); /* * Store the reply serial number for the JOIN_SESSION reply */ sessionInfo->replySerial = msg->bus->serial - 1; } else { duk_del_prop_string(ctx, sessIdx, prefix); } /* Clean up the stack */ duk_pop_n(ctx, 4); return status; }