diff --git a/src/task.c b/src/task.c index 1492b797..a2f6a4a9 100644 --- a/src/task.c +++ b/src/task.c @@ -95,7 +95,7 @@ typedef struct _tf_task_t { int _export_count; exportid_t _nextExport; - import_record_t* _imports; + import_record_t** _imports; int _import_count; JSValue _requires; JSValue _loadedFiles; @@ -143,64 +143,85 @@ static tf_taskstub_t* _tf_task_get_stub(tf_task_t* task, taskid_t id); static void _tf_task_release_export(tf_taskstub_t* stub, exportid_t exportId); typedef struct _import_record_t { + tf_task_t* _owner; JSValue _function; exportid_t _export; taskid_t _task; - tf_task_t* _owner; int _useCount; - import_record_t* _next; } import_record_t; +static int _import_compare(const void* a, const void* b) +{ + const import_record_t* ia = a; + const import_record_t* const* ib = b; + if (ia->_task != (*ib)->_task) + { + return ia->_task < (*ib)->_task ? -1 : 1; + } + else if (ia->_export != (*ib)->_export) + { + return ia->_export < (*ib)->_export ? -1 : 1; + } + else + { + return 0; + } +} + +static import_record_t** _tf_task_find_import(tf_task_t* task, taskid_t task_id, exportid_t export_id) +{ + if (!task->_imports) + { + return NULL; + } + import_record_t search = + { + ._task = task_id, + ._export = export_id, + }; + import_record_t** it = bsearch(&search, task->_imports, task->_import_count, sizeof(import_record_t*), _import_compare); + return it; +} + static void _tf_task_trace_imports(tf_task_t* task) { tf_trace_counter(task->_trace, "imports", 1, (const char*[]) { "count" }, (int64_t[]) { task->_import_count }); } -static void _import_record_release(import_record_t* import) +static void _import_record_release(import_record_t** import) { - JSContext* context = import->_owner->_context; - if (--import->_useCount > 0) + JSContext* context = (*import)->_owner->_context; + tf_task_t* task = (*import)->_owner; + import_record_t* record = *import; + + if (--record->_useCount > 0) { return; } - JS_SetOpaque(import->_function, NULL); - JS_FreeValue(context, import->_function); - import->_function = JS_UNDEFINED; - _tf_task_release_export(_tf_task_get_stub(import->_owner, import->_task), import->_export); + JS_SetOpaque(record->_function, NULL); + JS_FreeValue(context, record->_function); + record->_function = JS_UNDEFINED; + _tf_task_release_export(_tf_task_get_stub(task, record->_task), record->_export); - for (import_record_t** it = &import->_owner->_imports; - *it; - it = &(*it)->_next) - { - if (*it == import) - { - *it = import->_next; - import->_owner->_import_count--; - _tf_task_trace_imports(import->_owner); - import->_next = NULL; - break; - } - } + int index = import - task->_imports; + memmove(import, import + 1, sizeof(import_record_t*) * (task->_import_count - index - 1)); + task->_import_count--; + _tf_task_trace_imports(task); - free(import); + free(record); } static void _import_record_release_for_task(tf_task_t* task, taskid_t task_id) { bool any = false; - import_record_t** next = NULL; - for (import_record_t** it = &task->_imports; - *it; - it = next) + for (int i = 0; i < task->_import_count; i++) { - next = &(*it)->_next; - if ((*it)->_task == task_id) + if (task->_imports[i]->_task == task_id) { - import_record_t* import = *it; - _import_record_release(import); - next = it; + _import_record_release(&task->_imports[i]); any = true; + --i; } } @@ -644,12 +665,34 @@ static JSValue _tf_task_getFile(JSContext* context, JSValueConst this_val, int a return result; } +const char* _tf_task_get_message_type(tf_task_message_t type) +{ + switch (type) + { + case kResolvePromise: return "kResolvePromise"; + case kRejectPromise: return "kRejectPromise"; + case kInvokeExport: return "kInvokeExport"; + case kReleaseExport: return "kReleaseExport"; + case kReleaseImport: return "kReleaseImport"; + case kSetRequires: return "kSetRequires"; + case kActivate: return "kActivate"; + case kExecute: return "kExecute"; + case kKill: return "kKill"; + case kSetImports: return "kSetImports"; + case kGetExports: return "kGetExports"; + case kLoadFile: return "kLoadFile"; + case kTaskError: return "kTaskError"; + case kTaskTrace: return "kTaskTrace"; + } + return "unknown"; +} + void tf_task_on_receive_packet(int packetType, const char* begin, size_t length, void* userData) { tf_taskstub_t* stub = userData; tf_taskstub_t* from = stub; tf_task_t* to = tf_taskstub_get_owner(stub); - tf_trace_begin(to->_trace, "tf_task_on_receive_packet"); + tf_trace_begin(to->_trace, _tf_task_get_message_type(packetType)); switch (packetType) { @@ -721,13 +764,10 @@ void tf_task_on_receive_packet(int packetType, const char* begin, size_t length, assert(length == sizeof(exportid_t)); exportid_t exportId; memcpy(&exportId, begin, sizeof(exportId)); - for (import_record_t* it = to->_imports; it; it = it->_next) + import_record_t** it = _tf_task_find_import(to, tf_taskstub_get_id(from), exportId); + if (it) { - if (it->_task == tf_taskstub_get_id(from) && it->_export == exportId) - { - _import_record_release(it); - break; - } + _import_record_release(it); } } break; @@ -1091,7 +1131,10 @@ promiseid_t tf_task_allocate_promise(tf_task_t* task) promise.values[0] = JS_NewPromiseCapability(task->_context, &promise.values[1]); int index = _insert_index((void*)(intptr_t)promiseId, task->_promises, task->_promise_count, sizeof(promise_t), _promise_compare); task->_promises = realloc(task->_promises, sizeof(promise_t) * (task->_promise_count + 1)); - memmove(task->_promises + index, task->_promises + index + 1, sizeof(promise_t) * (task->_promise_count - index)); + if (task->_promise_count - index) + { + memmove(task->_promises + index + 1, task->_promises + index, sizeof(promise_t) * (task->_promise_count - index)); + } task->_promises[index] = promise; task->_promise_count++; _tf_task_trace_promises(task); @@ -1187,7 +1230,11 @@ void tf_task_remove_child(tf_task_t* task, tf_taskstub_t* child) static void _import_finalizer(JSRuntime* runtime, JSValue value) { import_record_t* import = JS_GetOpaque(value, _import_class_id); - _import_record_release(import); + if (import) + { + import_record_t** it = _tf_task_find_import(import->_owner, import->_task, import->_export); + _import_record_release(it); + } } static void _import_mark_func(JSRuntime* runtime, JSValueConst value, JS_MarkFunc mark_func) @@ -1346,15 +1393,14 @@ JSContext* tf_task_get_context(tf_task_t* task) void tf_task_destroy(tf_task_t* task) { - import_record_t* it = task->_imports; - while (it) + for (int i = 0; i < task->_import_count; i++) { - import_record_t* next = it->_next; - JS_FreeValue(task->_context, it->_function); - free(it); - it = next; + JS_FreeValue(task->_context, task->_imports[i]->_function); + free(task->_imports[i]); } + free(task->_imports); task->_imports = NULL; + task->_import_count = 0; while (task->_exports) { @@ -1429,10 +1475,15 @@ JSValue tf_task_add_import(tf_task_t* task, taskid_t stub_id, exportid_t export_ ._owner = task, ._task = stub_id, ._useCount = 1, - ._next = task->_imports, }; - task->_imports = import; + int index = _insert_index(import, task->_imports, task->_import_count, sizeof(import_record_t*), _import_compare); + task->_imports = realloc(task->_imports, sizeof(import_record_t*) * (task->_import_count + 1)); + if (task->_import_count - index) + { + memmove(task->_imports + index + 1, task->_imports + index, sizeof(import_record_t*) * (task->_import_count - index)); + } + task->_imports[index] = import; task->_import_count++; _tf_task_trace_imports(task); return function;