From da756d6b7fe8464b7a8ac620d768c47adfa78e21 Mon Sep 17 00:00:00 2001 From: Bryan Roe Date: Thu, 18 Feb 2021 01:51:52 -0800 Subject: [PATCH] Added new reference mode for EventEmitter --- meshcore/agentcore.c | 18 +++- microscript/ILibDuktape_EventEmitter.h | 4 +- microscript/ILibDuktape_Helpers.c | 2 +- microscript/ILibDuktape_Helpers.h | 1 + microscript/ILibDuktape_WritableStream.c | 5 +- microscript/ILibduktape_EventEmitter.c | 114 +++++++++++++++++++---- 6 files changed, 118 insertions(+), 26 deletions(-) diff --git a/meshcore/agentcore.c b/meshcore/agentcore.c index b4dcaba..e6bdad3 100644 --- a/meshcore/agentcore.c +++ b/meshcore/agentcore.c @@ -109,6 +109,7 @@ int ILibDuktape_HECI_Debug = 0; #endif #endif +extern int gEventEmitterReferenceHold; extern int ILibDuktape_ModSearch_ShowNames; char* MeshAgentHost_BatteryInfo_STRINGS[] = { "UNKNOWN", "HIGH_CHARGE", "LOW_CHARGE", "NO_BATTERY", "CRITICAL_CHARGE", "", "", "", "CHARGING" }; JS_ENGINE_CONTEXT MeshAgent_JavaCore_ContextGuid = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; @@ -5095,7 +5096,14 @@ int MeshAgent_AgentMode(MeshAgentHostContainer *agentHost, int paramLen, char ** { duk_eval_string_noresult(agentHost->meshCoreCtx, "process.coreDumpLocation = process.platform=='win32'?(process.execPath.replace('.exe', '.dmp')):(process.execPath + '.dmp');"); } - + if (ILibSimpleDataStore_Get(agentHost->masterDb, "eventemitter-refhold", ILibScratchPad, sizeof(ILibScratchPad)) != 0) + { + gEventEmitterReferenceHold = atoi(ILibScratchPad); + } + if (ILibSimpleDataStore_Get(agentHost->masterDb, "finalizer-messages", ILibScratchPad, sizeof(ILibScratchPad)) != 0) + { + g_displayFinalizerMessages = atoi(ILibScratchPad); + } if (CoreModuleLen > 4) { if (ILibSimpleDataStore_Get(agentHost->masterDb, "noUpdateCoreModule", NULL, 0) != 0) @@ -5518,6 +5526,14 @@ void MeshAgent_ScriptMode(MeshAgentHostContainer *agentHost, int argc, char **ar agentHost->masterDb = ILibSimpleDataStore_Create(MeshAgent_MakeAbsolutePath(agentHost->exePath, ".db")); } } + else if (strncmp(argv[i], "--eventemitter-refhold=", 23) == 0) + { + char *tmp = strstr(argv[i], "="); + if (tmp != NULL) + { + gEventEmitterReferenceHold = atoi(tmp + 1); + } + } else { // Unhandled arguments, passed to JavaScript diff --git a/microscript/ILibDuktape_EventEmitter.h b/microscript/ILibDuktape_EventEmitter.h index d083930..fa023f4 100644 --- a/microscript/ILibDuktape_EventEmitter.h +++ b/microscript/ILibDuktape_EventEmitter.h @@ -21,6 +21,8 @@ limitations under the License. #include "microstack/ILibParsers.h" #define ILibDuktape_EventEmitter_FinalizerDebugMessage "\xFF_FinalizerDebugMessage" +#define ILibDuktape_EventEmitter_InfrastructureEvent "\xFF_EventEmitter_InfrastructureEvent" + typedef enum ILibDuktape_EventEmitter_Types { @@ -36,7 +38,6 @@ typedef struct ILibDuktape_EventEmitter void *table; void *retValTable; void *lastReturnValue; - unsigned int *totalListeners; const char *listenerCountTable; size_t listenerCountTableLength; ILibSpinLock listenerCountTableLock; @@ -71,6 +72,7 @@ int ILibDuktape_EventEmitter_HasListeners2(ILibDuktape_EventEmitter *emitter, ch int ILibDuktape_EventEmitter_AddOn(ILibDuktape_EventEmitter *emitter, char *eventName, void *heapptr); // Add native event handler int ILibDuktape_EventEmitter_AddOnEx(duk_context *ctx, duk_idx_t idx, char *eventName, duk_c_function func); +#define ILibDuktape_EventEmitter_AddOn_Infrastructure(ctx, idx, eventName, func) duk_prepare_method_call(ctx, idx, "on");duk_push_string(ctx, eventName);duk_push_c_function(ctx, func, DUK_VARARGS);duk_push_true(ctx);duk_put_prop_string(ctx, -2, ILibDuktape_EventEmitter_InfrastructureEvent);duk_pcall_method(ctx, 2);duk_pop(ctx); void ILibDuktape_EventEmitter_AddHook(ILibDuktape_EventEmitter *emitter, char *eventName, ILibDuktape_EventEmitter_HookHandler handler); void ILibDuktape_EventEmitter_ClearHook(ILibDuktape_EventEmitter *emitter, char *eventName); diff --git a/microscript/ILibDuktape_Helpers.c b/microscript/ILibDuktape_Helpers.c index 852aee1..a603b5e 100644 --- a/microscript/ILibDuktape_Helpers.c +++ b/microscript/ILibDuktape_Helpers.c @@ -907,7 +907,7 @@ void ILibDuktape_CreateProperty_InstanceMethod(duk_context *ctx, char *methodNam duk_push_c_function(ctx, ILibDuktape_CreateProperty_InstanceMethod_Sink, 1); // [obj][prop][getFunc] duk_push_c_function(ctx, impl, argCount); // [obj][prop][getFunc][func] duk_put_prop_string(ctx, -2, "actualFunc"); // [obj][prop][getFunc] - duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_GETTER); // [obj] + duk_def_prop(ctx, -3, DUK_DEFPROP_SET_ENUMERABLE | DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_GETTER); // [obj] } duk_ret_t ILibDuktape_ReadonlyProperty_Get(duk_context *ctx) diff --git a/microscript/ILibDuktape_Helpers.h b/microscript/ILibDuktape_Helpers.h index f8c4a94..49b99e5 100644 --- a/microscript/ILibDuktape_Helpers.h +++ b/microscript/ILibDuktape_Helpers.h @@ -203,6 +203,7 @@ duk_idx_t duk_push_int_ex(duk_context *ctx, duk_int_t val); void ILibDuktape_CreateProperty_InstanceMethod(duk_context *ctx, char *methodName, duk_c_function impl, duk_idx_t argCount); void ILibDuktape_CreateProperty_InstanceMethodEx(duk_context *ctx, char *methodName, void *funcHeapPtr); +#define ILibDuktape_DeleteReadOnlyProperty(ctx, i, propName) duk_dup(ctx,i);duk_push_string(ctx,propName);duk_def_prop(ctx,-2,DUK_DEFPROP_FORCE|DUK_DEFPROP_SET_CONFIGURABLE);duk_pop(ctx);duk_del_prop_string(ctx,i,propName); #define ILibDuktape_CreateReadonlyProperty(ctx, propName) ILibDuktape_CreateReadonlyProperty_SetEnumerable(ctx, propName, 0) void ILibDuktape_CreateReadonlyProperty_SetEnumerable(duk_context *ctx, char *propName, int enumerable); #define ILibDuktape_CreateReadonlyProperty_int(ctx, propName, propValue) duk_push_int(ctx, propValue);ILibDuktape_CreateReadonlyProperty_SetEnumerable(ctx, propName, 1) diff --git a/microscript/ILibDuktape_WritableStream.c b/microscript/ILibDuktape_WritableStream.c index 7d90ed9..f8ea4c8 100644 --- a/microscript/ILibDuktape_WritableStream.c +++ b/microscript/ILibDuktape_WritableStream.c @@ -339,8 +339,7 @@ ILibDuktape_WritableStream* ILibDuktape_WritableStream_Init(duk_context *ctx, IL ILibDuktape_CreateProperty_InstanceMethod(ctx, "write", ILibDuktape_WritableStream_Write, DUK_VARARGS); ILibDuktape_CreateEventWithGetter(ctx, "end", ILibDuktape_WritableStream_End_Getter); - - ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "pipe", ILibDuktape_WritableStream_PipeSink); - ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "unpipe", ILibDuktape_WritableStream_UnPipeSink); + ILibDuktape_EventEmitter_AddOn_Infrastructure(ctx, -1, "pipe", ILibDuktape_WritableStream_PipeSink); + ILibDuktape_EventEmitter_AddOn_Infrastructure(ctx, -1, "unpipe", ILibDuktape_WritableStream_UnPipeSink); return retVal; } diff --git a/microscript/ILibduktape_EventEmitter.c b/microscript/ILibduktape_EventEmitter.c index 891a893..58f4fcd 100644 --- a/microscript/ILibduktape_EventEmitter.c +++ b/microscript/ILibduktape_EventEmitter.c @@ -36,6 +36,13 @@ limitations under the License. #define ILibDuktape_EventEmitter_ForwardTable "\xFF_EventEmitter_ForwardTable" #define ILibDuktape_EventEmitter_EventTable "\xFF_EventEmitter_EventTable" #define ILibDuktape_EventEmitter_CountTable "\xFF_EventEmitter_CountTable" +#define ILibDuktape_EventEmitter_References "\xFF_EventReferences" + +#ifdef ILIBEVENTEMITTER_REFHOLD +int gEventEmitterReferenceHold = ILIBEVENTEMITTER_REFHOLD; +#else +int gEventEmitterReferenceHold = 0; +#endif typedef struct ILibDuktape_EventEmitter_EmitStruct { @@ -418,6 +425,27 @@ duk_ret_t ILibDuktape_EventEmitter_on(duk_context *ctx) duk_array_push(ctx, -2); // [object][table][array] } + if (gEventEmitterReferenceHold != 0) + { + duk_prepare_method_call(ctx, -3, "eventNames"); // [object][table][array][eventNames][this] + duk_call_method(ctx, 0); // [object][table][array][names] + + if (duk_get_length(ctx, -1) > 0) + { + duk_push_heap_stash(ctx); // [object][table][array][names][stash] + if (!duk_has_prop_string(ctx, -1, ILibDuktape_EventEmitter_References)) + { + duk_push_object(ctx); // [object][table][array][names][stash][refs] + duk_put_prop_string(ctx, -2, ILibDuktape_EventEmitter_References); // [object][table][array][names][stash] + } + duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_References); // [object][table][array][names][stash][refs] + duk_push_this(ctx); // [object][table][array][names][stash][refs][this] + duk_put_prop_string(ctx, -2, Duktape_GetStashKey(duk_get_heapptr(ctx, -1))); //ect][table][array][names][stash][refs] + duk_pop_2(ctx); // [object][table][array][names] + } + duk_pop(ctx); // [object][table][array] + } + if (!(propNameLen == 11 && strncmp(propName, "newListener", 11) == 0) && !(propNameLen == 12 && strncmp(propName, "newListener2", 12) == 0)) { // Only emit 'newListener2' when the event itself isn't 'newListener' or 'newListener2' @@ -600,13 +628,38 @@ duk_ret_t ILibDuktape_EventEmitter_listenerCount(duk_context *ctx) duk_ret_t ILibDuktape_EventEmitter_eventNames(duk_context *ctx) { + duk_size_t len; + duk_uarridx_t i; + duk_size_t count; + ILibDuktape_EventEmitter *emitter = ILibDuktape_EventEmitter_GetEmitter_fromThis(ctx); duk_push_array(ctx); // [array] duk_push_heapptr(ctx, emitter->table); // [array][table] duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY);// [array][table][enumerator] - while (duk_next(ctx, -1, 0)) // [array][table][enumerator][key] + while (duk_next(ctx, -1, 1)) // [array][table][enumerator][key][value] { - duk_array_push(ctx, -4); // [array][table][enumerator] + count = 0; + if (strcmp(duk_get_string(ctx, -2), "~") != 0) + { + // We will only look at events that aren't the finalizer event + len = duk_get_length(ctx, -1); + for (i = 0; i < len; ++i) + { + duk_get_prop_index(ctx, -1, i); // [array][table][enumerator][key][value][obj] + duk_get_prop_string(ctx, -1, "func"); // [array][table][enumerator][key][value][obj][func] + if (Duktape_GetBooleanProperty(ctx, -1, ILibDuktape_EventEmitter_InfrastructureEvent, 0) == 0) { ++count; } + duk_pop_2(ctx); // [array][table][enumerator][key][value] + } + } + duk_pop(ctx); // [array][table][enumerator][key] + if (count > 0) + { + duk_array_push(ctx, -4); // [array][table][enumerator] + } + else + { + duk_pop(ctx); // [array][table][enumerator] + } } duk_pop_2(ctx); // [array] return(1); @@ -657,9 +710,26 @@ duk_ret_t ILibDuktape_EventEmitter_listeners_tableinit(duk_context *ctx) int isAdd = Duktape_GetIntPropertyValue(ctx, -1, "add", 0); const char *eventName = duk_require_string(ctx, 0); - duk_push_this(ctx); + duk_push_this(ctx); // [obj] ILibDuktape_EventEmitter *emitter = (ILibDuktape_EventEmitter*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_EventEmitter_Data); + if (isAdd == 0 && gEventEmitterReferenceHold != 0) + { + duk_prepare_method_call(ctx, -1, "eventNames"); // [obj][eventNames][this] + duk_call_method(ctx, 0); // [obj][names] + if (duk_get_length(ctx, -1) == 0) + { + duk_push_heap_stash(ctx); // [obj][names][stash] + duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_References); // [obj][names][stash][refs] + if (!duk_is_null_or_undefined(ctx, -1)) + { + duk_del_prop_string(ctx, -1, Duktape_GetStashKey(duk_get_heapptr(ctx, -4))); + } + duk_pop_2(ctx); // [obj][names] + } + duk_pop(ctx); // [obj] + } + ILibSpinLock_Lock(&(emitter->listenerCountTableLock)); duk_push_global_object(ctx); // [g] duk_get_prop_string(ctx, -1, "JSON"); // [g][JSON] @@ -764,22 +834,6 @@ ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_Create(duk_context *ctx) ILibDuktape_CreateInstanceMethod(ctx, "emit", ILibDuktape_EventEmitter_emit, DUK_VARARGS); ILibDuktape_CreateInstanceMethod(ctx, "emit_returnValue", ILibDuktape_EventEmitter_emitReturnValue, DUK_VARARGS); - duk_push_heap_stash(ctx); - if (duk_has_prop_string(ctx, -1, ILibDuktape_EventEmitter_GlobalListenerCount)) - { - duk_get_prop_string(ctx, -1, ILibDuktape_EventEmitter_GlobalListenerCount); - retVal->totalListeners = (unsigned int *)Duktape_GetBuffer(ctx, -1, NULL); - duk_pop(ctx); - } - else - { - Duktape_PushBuffer(ctx, sizeof(unsigned int)); - retVal->totalListeners = (unsigned int *)Duktape_GetBuffer(ctx, -1, NULL); - duk_put_prop_string(ctx, -2, ILibDuktape_EventEmitter_GlobalListenerCount); - *(retVal->totalListeners) = 0; - } - duk_pop(ctx); - ILibDuktape_EventEmitter_CreateEventEx(retVal, "~"); duk_push_c_function(ctx, ILibDuktape_EventEmitter_EmbeddedFinalizer, 1); duk_set_finalizer(ctx, -2); @@ -789,10 +843,12 @@ ILibDuktape_EventEmitter* ILibDuktape_EventEmitter_Create(duk_context *ctx) duk_events_setup_on(ctx, -1, "newListener2", ILibDuktape_EventEmitter_listeners_tableinit); // [on][this][newListener][func] duk_push_int(ctx, 1); duk_put_prop_string(ctx, -2, "add"); + duk_push_true(ctx); duk_put_prop_string(ctx, -2, ILibDuktape_EventEmitter_InfrastructureEvent); duk_pcall_method(ctx, 2); duk_pop(ctx); // ... duk_events_setup_on(ctx, -1, "removeListener", ILibDuktape_EventEmitter_listeners_tableinit); // [on][this][removeListener][func] duk_push_int(ctx, 0); duk_put_prop_string(ctx, -2, "add"); + duk_push_true(ctx); duk_put_prop_string(ctx, -2, ILibDuktape_EventEmitter_InfrastructureEvent); duk_pcall_method(ctx, 2); duk_pop(ctx); // ... return retVal; @@ -936,7 +992,7 @@ void ILibDuktape_EventEmitter_CreateEventEx(ILibDuktape_EventEmitter *emitter, c duk_push_string(emitter->ctx, eventName); // [obj][prop][setFunc][name] duk_put_prop_string(emitter->ctx, -2, "eventName"); // [obj][prop][setFunc] - duk_def_prop(emitter->ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_SETTER); // [obj] + duk_def_prop(emitter->ctx, -3, DUK_DEFPROP_SET_ENUMERABLE | DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_SETTER); // [obj] duk_pop(emitter->ctx); // ... } else @@ -1077,12 +1133,30 @@ duk_ret_t ILibDuktape_EventEmitter_moderated(duk_context *ctx) duk_put_prop_string(ctx, -2, "interval"); // [func] return(1); } + +duk_ret_t ILibDuktape_EventEmitter_allProperties(duk_context *ctx) +{ + const char *tmp; + duk_push_array(ctx); // [arr] + duk_dup(ctx, 0); // [arr][obj] + duk_enum(ctx, -1, DUK_ENUM_INCLUDE_NONENUMERABLE | DUK_ENUM_INCLUDE_HIDDEN ); + while (duk_next(ctx, -1, 0)) // [arr][obj][enum][key] + { + tmp = duk_get_string(ctx, -1); + duk_push_string(ctx, tmp); // [arr][obj][enum][key][string] + duk_array_push(ctx, -5); // [arr][obj][enum][key] + duk_pop(ctx); // [arr][obj][enum] + } + duk_pop_2(ctx); // [arr] + return(1); +} void ILibDuktape_EventEmitter_PUSH(duk_context *ctx, void *chain) { duk_push_object(ctx); // [emitter] ILibDuktape_CreateInstanceMethod(ctx, "inherits", ILibDuktape_EventEmitter_Inherits, 1); ILibDuktape_CreateInstanceMethod(ctx, "EventEmitter", ILibDuktape_EventEmitter_EventEmitter, DUK_VARARGS); ILibDuktape_CreateInstanceMethod(ctx, "moderated", ILibDuktape_EventEmitter_moderated, DUK_VARARGS); + ILibDuktape_CreateInstanceMethod(ctx, "allProperties", ILibDuktape_EventEmitter_allProperties, 1); } void ILibDuktape_EventEmitter_Init(duk_context *ctx) {