static Box * PrivatePush( duk_context * ctx, const size_t class_index, const size_t object_size, finalizer_t finalizer ) { duk_push_global_object( ctx ); duk_get_prop_string( ctx, -1, "Proxy" ); duk_remove( ctx, -2 ); duk_push_object( ctx ); size_t require_size = sizeof( Box ) + object_size; Box * box = reinterpret_cast<Box*>( duk_push_fixed_buffer( ctx, require_size ) ); box->ClassIndex = class_index; box->Finalizer = finalizer; duk_put_prop_string( ctx, -2, "\xFF" "Box" ); duk_push_c_function( ctx, &internal::ClassFinalizer, 1 ); duk_set_finalizer( ctx, -2 ); duk_push_heap_stash( ctx ); duk_get_prop_string( ctx, -1, "InstanceHandler" ); duk_remove( ctx, -2 ); duk_new( ctx, 2 ); return box; }
void duk_push_sphere_bytearray(duk_context* ctx, bytearray_t* array) { duk_push_object(ctx); duk_push_string(ctx, "bytearray"); duk_put_prop_string(ctx, -2, "\xFF" "sphere_type"); duk_push_pointer(ctx, array); duk_put_prop_string(ctx, -2, "\xFF" "ptr"); duk_push_c_function(ctx, js_ByteArray_finalize, DUK_VARARGS); duk_set_finalizer(ctx, -2); duk_push_c_function(ctx, js_ByteArray_toString, DUK_VARARGS); duk_put_prop_string(ctx, -2, "toString"); duk_push_c_function(ctx, js_ByteArray_concat, DUK_VARARGS); duk_put_prop_string(ctx, -2, "concat"); duk_push_c_function(ctx, js_ByteArray_slice, DUK_VARARGS); duk_put_prop_string(ctx, -2, "slice"); duk_push_string(ctx, "length"); duk_push_int(ctx, array->size); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_CONFIGURABLE | 0 | DUK_DEFPROP_HAVE_WRITABLE | 0 | DUK_DEFPROP_HAVE_VALUE); // return proxy object so we can catch array accesses duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "Proxy"); duk_dup(ctx, -3); duk_push_object(ctx); duk_push_c_function(ctx, js_ByteArray_getProp, DUK_VARARGS); duk_put_prop_string(ctx, -2, "get"); duk_push_c_function(ctx, js_ByteArray_setProp, DUK_VARARGS); duk_put_prop_string(ctx, -2, "set"); duk_new(ctx, 2); duk_remove(ctx, -2); duk_remove(ctx, -2); }
void PushWeakObject(duk_context* ctx, Object* object) { if (!object) { duk_push_null(ctx); return; } duk_push_heap_stash(ctx); // Check if the wrapper for the object already exists in stash // This is required so that comparisons of object references (e.g. against the me property) work properly if (duk_has_prop_index(ctx, -1, (size_t)object)) { duk_get_prop_index(ctx, -1, (size_t)object); WeakPtr<Object>* oldPtr = GetWeakPtr(ctx, -1); if (oldPtr && oldPtr->Get() == object) { duk_remove(ctx, -2); // Remove stash return; } else duk_pop(ctx); // Valid existing wrapper not found } duk_push_object(ctx); WeakPtr<Object>* ptr = new WeakPtr<Object>(object); duk_push_pointer(ctx, ptr); duk_put_prop_string(ctx, -2, "\xff""weak"); duk_push_c_function(ctx, WeakPtr_Finalizer, 1); duk_set_finalizer(ctx, -2); // Set prototype. If not found, use base class prototype (e.g. IComponent) duk_get_global_string(ctx, object->GetTypeName().CString()); if (!duk_is_object(ctx, -1)) { duk_pop(ctx); duk_get_global_string(ctx, object->GetTypeInfo()->GetBaseTypeInfo()->GetTypeName().CString()); } duk_get_prop_string(ctx, -1, "prototype"); duk_set_prototype(ctx, -3); duk_pop(ctx); // Proxied property access handling for scene, entity & component if (object->GetType() == Scene::GetTypeStatic()) SetupProxy(ctx, SceneProxyFunctions); if (object->GetType() == Entity::GetTypeStatic()) SetupProxy(ctx, EntityProxyFunctions); else if (dynamic_cast<IComponent*>(object)) SetupProxy(ctx, ComponentProxyFunctions); // Store to stash duk_dup(ctx, -1); duk_put_prop_index(ctx, -3, (size_t)object); duk_remove(ctx, -2); // Remove stash }
static duk_ret_t test_3(duk_context *ctx) { prep(ctx); duk_remove(ctx, 0); /* -> [ 234 345 ] (legal) */ printf("remove at 0 ok\n"); duk_remove(ctx, -2); /* -> [ 345 ] (legal) */ printf("remove at -2 ok\n"); duk_remove(ctx, -2); /* (illegal) */ printf("remove at -2 ok\n"); return 0; }
static duk_ret_t test_2(duk_context *ctx) { prep(ctx); duk_remove(ctx, 2); /* -> [ 123 234 ] (legal) */ printf("remove at 2 ok\n"); duk_remove(ctx, -1); /* -> [ 123 ] (legal) */ printf("remove at -1 ok\n"); duk_remove(ctx, 1); /* (illegal) */ printf("remove at 1 ok\n"); return 0; }
void SetupProxy(duk_context* ctx, const duk_function_list_entry* funcs) { duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "Proxy"); duk_dup(ctx, -3); // Duplicate target at stack top duk_remove(ctx, -4); // Remove original target duk_push_object(ctx); // Handler duk_put_function_list(ctx, -1, funcs); duk_new(ctx, 2); // Create proxy duk_remove(ctx, -2); // Remove global object }
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; } }
void mn_push_ref(duk_context *ctx, int ref) { if (!ref) { duk_push_undefined(ctx); return; } /* Get the "refs" array in the heap stash */ duk_push_heap_stash(ctx); duk_get_prop_string(ctx, -1, "refs"); duk_remove(ctx, -2); duk_get_prop_index(ctx, -1, ref); duk_remove(ctx, -2); }
// 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; }
static duk_double_t duk__push_this_number_plain(duk_context *ctx) { duk_hobject *h; /* Number built-in accepts a plain number or a Number object (whose * internal value is operated on). Other types cause TypeError. */ duk_push_this(ctx); if (duk_is_number(ctx, -1)) { DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1))); goto done; } h = duk_get_hobject(ctx, -1); if (!h || (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) { DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1))); DUK_ERROR((duk_hthread *) ctx, DUK_ERR_TYPE_ERROR, "expected a number"); } duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); DUK_ASSERT(duk_is_number(ctx, -1)); DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T", (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); duk_remove(ctx, -2); done: return duk_get_number(ctx, -1); }
bool StyleContext::evalFunction(FunctionID id) { // Get all functions (array) in context if (!duk_get_global_string(m_ctx, FUNC_ID)) { LOGE("EvalFilterFn - functions array not initialized"); duk_pop(m_ctx); // pop [undefined] sitting at stack top return false; } // Get function at index `id` from functions array, put it at stack top if (!duk_get_prop_index(m_ctx, -1, id)) { LOGE("EvalFilterFn - function %d not set", id); duk_pop(m_ctx); // pop "undefined" sitting at stack top duk_pop(m_ctx); // pop functions (array) now sitting at stack top return false; } // pop fns array duk_remove(m_ctx, -2); // call popped function (sitting at stack top), evaluated value is put on stack top if (duk_pcall(m_ctx, 0) != 0) { LOGE("EvalFilterFn: %s", duk_safe_to_string(m_ctx, -1)); duk_pop(m_ctx); return false; } return true; }
DUK_EXTERNAL void duk_dump_function(duk_context *ctx) { duk_hthread *thr; duk_hcompiledfunction *func; duk_bufwriter_ctx bw_ctx_alloc; duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc; duk_uint8_t *p; DUK_ASSERT(ctx != NULL); thr = (duk_hthread *) ctx; /* Bound functions don't have all properties so we'd either need to * lookup the non-bound target function or reject bound functions. * For now, bound functions are rejected. */ func = duk_require_hcompiledfunction(ctx, -1); DUK_ASSERT(func != NULL); DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj)); /* Estimating the result size beforehand would be costly, so * start with a reasonable size and extend as needed. */ DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC); p = DUK_BW_GET_PTR(thr, bw_ctx); *p++ = DUK__SER_MARKER; *p++ = DUK__SER_VERSION; p = duk__dump_func(ctx, func, bw_ctx, p); DUK_BW_SET_PTR(thr, bw_ctx, p); DUK_BW_COMPACT(thr, bw_ctx); DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1))); duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */ }
void OnSignal(Entity * param0, Entity * param1, const float3 & param2, const float3 & param3, float param4, float param5, bool param6) { duk_context* ctx = ctx_; duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "_OnSignal"); duk_remove(ctx, -2); duk_push_number(ctx, (size_t)key_); duk_push_array(ctx); PushWeakObject(ctx, param0); duk_put_prop_index(ctx, -2, 0); PushWeakObject(ctx, param1); duk_put_prop_index(ctx, -2, 1); PushValueObjectCopy<float3>(ctx, param2, float3_ID, float3_Finalizer); duk_put_prop_index(ctx, -2, 2); PushValueObjectCopy<float3>(ctx, param3, float3_ID, float3_Finalizer); duk_put_prop_index(ctx, -2, 3); duk_push_number(ctx, param4); duk_put_prop_index(ctx, -2, 4); duk_push_number(ctx, param5); duk_put_prop_index(ctx, -2, 5); duk_push_boolean(ctx, param6); duk_put_prop_index(ctx, -2, 6); bool success = duk_pcall(ctx, 2) == 0; if (!success) LogError("[JavaScript] OnSignal: " + GetErrorString(ctx)); duk_pop(ctx); }
/* * Called with a service object on the top of the stack. Returns with a message object on top of * the stack replacing the service object. */ static void MessageSetup(duk_context* ctx, const char* iface, const char* member, const char* path, uint8_t msgType) { AJ_Status status; AJ_MsgHeader hdr; AJ_Message msg; AJS_MsgInfo* msgInfo; const char* dest; uint8_t secure; size_t dlen; duk_idx_t objIdx = duk_push_object(ctx); /* * Get the destination from the service object */ duk_get_prop_string(ctx, -2, "dest"); dest = duk_get_lstring(ctx, -1, &dlen); duk_pop(ctx); /* * If this is not a broadcast message make sure the destination peer is still connected */ if (dlen) { CheckPeerIsAlive(ctx, dest); } /* * Initialize a message struct so we can lookup the message id. We do this now because it is * alot more efficient if the method object we are creating is used multiple times. */ memset(&msg, 0, sizeof(AJ_Message)); memset(&hdr, 0, sizeof(AJ_MsgHeader)); msg.hdr = &hdr; msg.signature = "*"; msg.member = member; msg.iface = iface; msg.objPath = path ? path : AJS_GetStringProp(ctx, -2, "path"); /* * This allows us to use one object table entry for all messages */ AJS_SetObjectPath(msg.objPath); hdr.msgType = msgType; status = AJ_LookupMessageId(&msg, &secure); if (status != AJ_OK) { duk_error(ctx, DUK_ERR_REFERENCE_ERROR, "Unknown %s %s", path ? "SIGNAL" : "METHOD", member); } /* * Buffer to caching message information stored in the "info" property on the method object */ msgInfo = duk_push_fixed_buffer(ctx, sizeof(AJS_MsgInfo) + dlen + 1); msgInfo->secure = secure; msgInfo->session = AJS_GetIntProp(ctx, -2, "session"); msgInfo->msgId = msg.msgId; memcpy(msgInfo->dest, dest, dlen); msgInfo->dest[dlen] = 0; duk_put_prop_string(ctx, objIdx, "info"); AJ_ASSERT(duk_get_top_index(ctx) == objIdx); /* * Remove sessions object and leave the message object on the top of the stack */ duk_remove(ctx, -2); }
void duk_push_java_object(duk_context *ctx, JNIEnv *env, jobject object){ if(object == NULL){ duk_push_null(ctx); return; } if((*env)->IsInstanceOf(env, object, js_ref_class)){ jint ref = (*env)->CallIntMethod(env, object, js_ref_get_ref_method); duk_push_js_ref(ctx, ref); return; } if((*env)->IsInstanceOf(env, object, java_number_class)){ jdouble num = (*env)->CallDoubleMethod(env, object, java_number_get_double_value_method); duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "Number"); duk_push_number(ctx, num); duk_new(ctx, 1); duk_mark_jsobject_to_java_object(ctx, -1, env, object); duk_remove(ctx, -2); return; } if((*env)->IsInstanceOf(env, object, java_boolean_class)){ jboolean value = (*env)->CallBooleanMethod(env, object, java_boolean_get_boolean_value_method); if(value){ duk_push_true(ctx); }else{ duk_push_false(ctx); } return; } duk_push_object(ctx); //empty target duk_mark_jsobject_to_java_object(ctx, -1, env, object); }
static duk_ret_t test_4(duk_context *ctx, void *udata) { (void) udata; prep(ctx); duk_remove(ctx, DUK_INVALID_INDEX); /* (illegal) */ printf("remove at DUK_INVALID_INDEX ok\n"); return 0; }
static duk_ret_t js_Font_get_colorMask(duk_context* ctx) { duk_push_this(ctx); duk_get_prop_string(ctx, -1, "\xFF" "color_mask"); duk_remove(ctx, -2); return 1; }
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 int GetStackRaw(duk_context *ctx) { if (!duk_is_object(ctx, -1) || !duk_has_prop_string(ctx, -1, "stack") || !duk_is_error(ctx, -1)) return 1; duk_get_prop_string(ctx, -1, "stack"); duk_remove(ctx, -2); 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 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 duk_ret_t test_1(duk_context *ctx) { duk_idx_t i, n; prep(ctx); duk_remove(ctx, -2); /* -> [ 123 345 ] */ n = duk_get_top(ctx); for (i = 0; i < n; i++) { printf("%ld: %s\n", (long) i, duk_to_string(ctx, i)); } return 0; }
void OnSignal() { duk_context* ctx = ctx_; duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "_OnSignal"); duk_remove(ctx, -2); duk_push_number(ctx, (size_t)key_); duk_push_array(ctx); bool success = duk_pcall(ctx, 2) == 0; if (!success) LogError("[JavaScript] OnSignal: " + GetErrorString(ctx)); duk_pop(ctx); }
/* * If there is a callback registered for this interface pushes the function onto the stack */ static int PushServiceCallback(duk_context* ctx, const char* iface) { AJS_GetGlobalStashObject(ctx, "serviceCB"); duk_get_prop_string(ctx, -1, iface); duk_remove(ctx, -2); if (duk_is_callable(ctx, -1)) { return 1; } else { duk_pop(ctx); return 0; } }
DUK_EXTERNAL duk_bool_t duk_get_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]); ret = duk_get_prop_string(ctx, -1, key); duk_remove(ctx, -2); return ret; }
static int get_stack_raw(duk_context *ctx) { if (!duk_is_object(ctx, -1)) { return 1; } if (!duk_has_prop_string(ctx, -1, "stack")) { return 1; } if (!duk_is_error(ctx, -1)) { /* Not an Error instance, don't read "stack". */ return 1; } duk_get_prop_string(ctx, -1, "stack"); /* caller coerces */ duk_remove(ctx, -2); return 1; }
void OnSignal(IAssetTransfer * param0, String param1) { duk_context* ctx = ctx_; duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "_OnSignal"); duk_remove(ctx, -2); duk_push_number(ctx, (size_t)key_); duk_push_array(ctx); PushWeakObject(ctx, param0); duk_put_prop_index(ctx, -2, 0); duk_push_string(ctx, param1.CString()); duk_put_prop_index(ctx, -2, 1); bool success = duk_pcall(ctx, 2) == 0; if (!success) LogError("[JavaScript] OnSignal: " + GetErrorString(ctx)); duk_pop(ctx); }
static int get_stack_raw(duk_context *ctx) { if (!duk_is_object(ctx, -1)) { return 1; } if (!duk_has_prop_string(ctx, -1, "stack")) { return 1; } /* XXX: should check here that object is an Error instance too, * i.e. 'stack' is special. */ duk_get_prop_string(ctx, -1, "stack"); /* caller coerces */ duk_remove(ctx, -2); return 1; }
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 }