diff --git a/src/task.c b/src/task.c index a2f6a4a9..5470df52 100644 --- a/src/task.c +++ b/src/task.c @@ -91,7 +91,7 @@ typedef struct _tf_task_t { promiseid_t _nextPromise; uv_loop_t _loop; - export_record_t* _exports; + export_record_t** _exports; int _export_count; exportid_t _nextExport; @@ -109,11 +109,10 @@ typedef struct _tf_task_t { } tf_task_t; typedef struct _export_record_t { - exportid_t _export_id; taskid_t _taskid; + exportid_t _export_id; JSValue _function; int _useCount; - export_record_t* _next; } export_record_t; static void _export_record_ref(export_record_t* export) @@ -121,9 +120,22 @@ static void _export_record_ref(export_record_t* export) export->_useCount++; } -static bool _export_record_release(export_record_t* export) +static bool _export_record_release(tf_task_t* task, export_record_t** export) { - return --export->_useCount == 0; + if (--(*export)->_useCount == 0) + { + JS_FreeValue(task->_context, (*export)->_function); + (*export)->_function = JS_UNDEFINED; + free(*export); + int index = export - task->_exports; + if (task->_export_count - index) + { + memmove(export, export + 1, sizeof(export_record_t*) * (task->_export_count - index - 1)); + } + task->_export_count--; + return true; + } + return false; } static JSValue _tf_task_version(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); @@ -236,27 +248,31 @@ static void _tf_task_trace_exports(tf_task_t* task) tf_trace_counter(task->_trace, "exports", 1, (const char*[]) { "count" }, (int64_t[]) { task->_export_count }); } +static int _export_compare(const void* a, const void* b) +{ + exportid_t ia = *(const exportid_t*)a; + const export_record_t* const* ib = b; + if (ia != (*ib)->_export_id) + { + return ia < (*ib)->_export_id ? -1 : 1; + } + else + { + return 0; + } +} + static void _export_record_release_for_task(tf_task_t* task, taskid_t task_id) { bool any = false; - export_record_t** next = NULL; - for (export_record_t** it = &task->_exports; - *it; - it = next) + for (int i = 0; i < task->_export_count; i++) { - next = &(*it)->_next; - if ((*it)->_taskid == task_id) + if (task->_exports[i]->_taskid == task_id) { - export_record_t* export = *it; - if (_export_record_release(export)) + if (_export_record_release(task, &task->_exports[i])) { - *it = export->_next; - JS_FreeValue(task->_context, export->_function); - free(export); - task->_export_count--; - _tf_task_trace_exports(task); - next = it; any = true; + i--; } } } @@ -402,22 +418,17 @@ static JSValue _import_call(JSContext* context, JSValueConst func_obj, JSValueCo return result; } -static export_record_t* _task_get_export(tf_task_t* task, exportid_t export_id) +static export_record_t** _task_get_export(tf_task_t* task, exportid_t export_id) { - for (export_record_t* it = task->_exports; it; it = it->_next) - { - if (it->_export_id == export_id) - { - return it; - } - } - return NULL; + export_record_t** it = bsearch(&export_id, task->_exports, task->_export_count, sizeof(export_record_t*), _export_compare); + return it; } JSValue _task_invokeExport_internal(tf_taskstub_t* from, tf_task_t* to, exportid_t exportId, const char* buffer, size_t size) { JSValue result = JS_NULL; - export_record_t* export = _task_get_export(to, exportId); + export_record_t** it = _task_get_export(to, exportId); + export_record_t* export = it ? *it : NULL; if (export) { JSValue arguments = tf_serialize_load(to, from, buffer, size); @@ -589,16 +600,39 @@ static JSValue _tf_task_version(JSContext* context, JSValueConst this_val, int a return JS_NewString(task->_context, k_version); } +static int _insert_index(const void* key, const void* base, size_t count, size_t size, int (*compare)(const void*, const void*)) +{ + int lower = 0; + int upper = count; + while (lower < upper && lower < (int)count) + { + int guess = (lower + upper) / 2; + int result = compare(key, ((char*)base) + size * guess); + if (result < 0) + { + upper = guess; + } + else if (result > 0) + { + lower = guess + 1; + } + else + { + return guess; + } + }; + return lower; +} + exportid_t tf_task_export_function(tf_task_t* task, tf_taskstub_t* to, JSValue function) { export_record_t* export = NULL; - - for (export_record_t* it = task->_exports; it; it = it->_next) + /* TODO: _exports_by_function */ + for (int i = 0; i < task->_export_count; i++) { - if (JS_VALUE_GET_PTR(it->_function) == JS_VALUE_GET_PTR(function) && - it->_taskid == tf_taskstub_get_id(to)) + if (JS_VALUE_GET_PTR(task->_exports[i]->_function) == JS_VALUE_GET_PTR(function)) { - export = it; + export = task->_exports[i]; break; } } @@ -616,9 +650,15 @@ exportid_t tf_task_export_function(tf_task_t* task, tf_taskstub_t* to, JSValue f ._export_id = id, ._taskid = tf_taskstub_get_id(to), ._function = JS_DupValue(task->_context, function), - ._next = task->_exports, }; - task->_exports = export; + + int index = _insert_index(&id, task->_exports, task->_export_count, sizeof(export_record_t*), _export_compare); + task->_exports = realloc(task->_exports, sizeof(export_record_t*) * (task->_export_count + 1)); + if (task->_export_count - index) + { + memmove(task->_exports + index + 1, task->_exports + index, sizeof(export_record_t*) * (task->_export_count - index)); + } + task->_exports[index] = export; task->_export_count++; _tf_task_trace_exports(task); } @@ -740,22 +780,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 (export_record_t** it = &to->_exports; *it; it = &(*it)->_next) + export_record_t** it = _task_get_export(to, exportId); + if (it) { - export_record_t* export = *it; - if (export->_export_id == exportId && - export->_taskid == tf_taskstub_get_id(from)) - { - if (_export_record_release(export)) - { - *it = export->_next; - JS_FreeValue(to->_context, export->_function); - free(export); - to->_export_count--; - _tf_task_trace_exports(to); - } - break; - } + _export_record_release(to, it); } } break; @@ -1065,30 +1093,6 @@ static int _promise_compare(const void* a, const void* b) return ida < pb->id ? -1 : pb->id < ida ? 1 : 0; } -static int _insert_index(const void* key, const void* base, size_t count, size_t size, int (*compare)(const void*, const void*)) -{ - int lower = 0; - int upper = count; - while (lower < upper && lower < (int)count) - { - int guess = (lower + upper) / 2; - int result = compare(key, ((char*)base) + size * guess); - if (result < 0) - { - upper = guess; - } - else if (result > 0) - { - lower = guess + 1; - } - else - { - return guess; - } - }; - return lower; -} - static promise_t* _tf_task_find_promise(tf_task_t* task, promiseid_t id) { if (!task->_promises) @@ -1402,13 +1406,15 @@ void tf_task_destroy(tf_task_t* task) task->_imports = NULL; task->_import_count = 0; - while (task->_exports) + for (int i = 0; i < task->_export_count; i++) { - export_record_t* export = task->_exports; - JS_FreeValue(task->_context, export->_function); - task->_exports = export->_next; - free(export); + JS_FreeValue(task->_context, task->_exports[i]->_function); + free(task->_exports[i]); } + free(task->_exports); + task->_exports = NULL; + task->_export_count = 0; + while (task->_children) { task_child_node_t* node = task->_children;