diff --git a/source/adt/include/adt/adt_map.h b/source/adt/include/adt/adt_map.h index ef1b45ebc8..ca51cd07b0 100644 --- a/source/adt/include/adt/adt_map.h +++ b/source/adt/include/adt/adt_map.h @@ -63,6 +63,10 @@ ADT_API int map_insert_array(map m, map_key keys[], map_value values[], size_t s ADT_API vector map_get(map m, map_key key); +ADT_API vector map_get_keys(map m); + +ADT_API vector map_get_values(map m); + ADT_API int map_contains(map m, map_key key); ADT_API int map_contains_any(map dest, map src); diff --git a/source/adt/include/adt/adt_set.h b/source/adt/include/adt/adt_set.h index 81140723b2..9f8baf45e9 100644 --- a/source/adt/include/adt/adt_set.h +++ b/source/adt/include/adt/adt_set.h @@ -15,6 +15,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -62,6 +63,10 @@ ADT_API int set_insert_array(set s, set_key keys[], set_value values[], size_t s ADT_API set_value set_get(set s, set_key key); +ADT_API vector set_get_keys(set s); + +ADT_API vector set_get_values(set s); + ADT_API int set_contains(set s, set_key key); ADT_API int set_contains_any(set dest, set src); diff --git a/source/adt/source/adt_map.c b/source/adt/source/adt_map.c index 5e4fd572e5..b1ff7147f7 100644 --- a/source/adt/source/adt_map.c +++ b/source/adt/source/adt_map.c @@ -251,6 +251,48 @@ vector map_get(map m, map_key key) return NULL; } +vector map_get_keys(map m) +{ + vector v = vector_create(sizeof(void *)); + bucket b; + pair p; + for (size_t iterator = 0; iterator < m->capacity; iterator++) + { + b = &m->buckets[iterator]; + + if (b->pairs != NULL && b->count > 0) + { + for (size_t index = 0; index < b->count; index++) + { + p = &b->pairs[index]; + vector_push_back(v, &p->key); + } + } + } + return v; +} + +vector map_get_values(map m) +{ + vector v = vector_create(sizeof(void *)); + bucket b; + pair p; + for (size_t iterator = 0; iterator < m->capacity; iterator++) + { + b = &m->buckets[iterator]; + + if (b->pairs != NULL && b->count > 0) + { + for (size_t index = 0; index < b->count; index++) + { + p = &b->pairs[index]; + vector_push_back(v, &p->value); + } + } + } + return v; +} + int map_contains(map m, map_key key) { if (m != NULL && key != NULL) diff --git a/source/adt/source/adt_set.c b/source/adt/source/adt_set.c index 2014e56c00..5f448bb7d6 100644 --- a/source/adt/source/adt_set.c +++ b/source/adt/source/adt_set.c @@ -273,6 +273,48 @@ set_value set_get(set s, set_key key) return NULL; } +vector set_get_keys(set s) +{ + vector v = vector_create(sizeof(void *)); + bucket b; + pair p; + for (size_t iterator = 0; iterator < s->capacity; iterator++) + { + b = &s->buckets[iterator]; + + if (b->pairs != NULL && b->count > 0) + { + for (size_t index = 0; index < b->count; index++) + { + p = &b->pairs[index]; + vector_push_back(v, &p->key); + } + } + } + return v; +} + +vector set_get_values(set s) +{ + vector v = vector_create(sizeof(void *)); + bucket b; + pair p; + for (size_t iterator = 0; iterator < s->capacity; iterator++) + { + b = &s->buckets[iterator]; + + if (b->pairs != NULL && b->count > 0) + { + for (size_t index = 0; index < b->count; index++) + { + p = &b->pairs[index]; + vector_push_back(v, &p->value); + } + } + } + return v; +} + int set_contains(set s, set_key key) { if (s != NULL && key != NULL) diff --git a/source/loaders/node_loader/source/node_loader_impl.cpp b/source/loaders/node_loader/source/node_loader_impl.cpp index f796358f06..ac5167625b 100644 --- a/source/loaders/node_loader/source/node_loader_impl.cpp +++ b/source/loaders/node_loader/source/node_loader_impl.cpp @@ -196,6 +196,27 @@ typedef struct loader_impl_async_future_delete_safe_type *loader_impl_async_futu struct loader_impl_async_destroy_safe_type; typedef struct loader_impl_async_destroy_safe_type *loader_impl_async_destroy_safe; +struct loader_impl_async_object_get_safe_type; +typedef struct loader_impl_async_object_get_safe_type *loader_impl_async_object_get_safe; + +struct loader_impl_async_object_set_safe_type; +typedef struct loader_impl_async_object_set_safe_type *loader_impl_async_object_set_safe; + +struct loader_impl_async_object_method_invoke_safe_type; +typedef struct loader_impl_async_object_method_invoke_safe_type *loader_impl_async_object_method_invoke_safe; + +struct loader_impl_async_object_destroy_safe_type; +typedef struct loader_impl_async_object_destroy_safe_type *loader_impl_async_object_destroy_safe; + +struct loader_impl_async_class_ctor_safe_type; +typedef struct loader_impl_async_class_ctor_safe_type *loader_impl_async_class_ctor_safe; + +struct loader_impl_async_class_static_invoke_safe_type; +typedef struct loader_impl_async_class_static_invoke_safe_type *loader_impl_async_class_static_invoke_safe; + +struct loader_impl_async_class_destroy_safe_type; +typedef struct loader_impl_async_class_destroy_safe_type *loader_impl_async_class_destroy_safe; + template union loader_impl_async_safe_cast { @@ -265,6 +286,34 @@ struct loader_impl_node_type loader_impl_async_destroy_safe destroy_safe; napi_threadsafe_function threadsafe_destroy; + napi_value object_get_safe_ptr; + loader_impl_async_object_get_safe object_get_safe; + napi_threadsafe_function threadsafe_object_get; + + napi_value object_set_safe_ptr; + loader_impl_async_object_set_safe object_set_safe; + napi_threadsafe_function threadsafe_object_set; + + napi_value object_method_invoke_safe_ptr; + loader_impl_async_object_method_invoke_safe object_method_invoke_safe; + napi_threadsafe_function threadsafe_object_method_invoke; + + napi_value object_destroy_safe_ptr; + loader_impl_async_object_destroy_safe object_destroy_safe; + napi_threadsafe_function threadsafe_object_destroy; + + napi_value class_ctor_safe_ptr; + loader_impl_async_class_ctor_safe class_ctor_safe; + napi_threadsafe_function threadsafe_class_ctor; + + napi_value class_static_invoke_safe_ptr; + loader_impl_async_class_static_invoke_safe class_static_invoke_safe; + napi_threadsafe_function threadsafe_class_static_invoke; + + napi_value class_destroy_safe_ptr; + loader_impl_async_class_destroy_safe class_destroy_safe; + napi_threadsafe_function threadsafe_class_destroy; + uv_thread_t thread; uv_loop_t *thread_loop; @@ -426,6 +475,71 @@ struct loader_impl_async_future_await_safe_type future_return ret; }; +struct loader_impl_async_object_get_safe_type +{ + loader_impl_node node_impl; + object obj; + loader_impl_node_object node_obj; + struct accessor_type *accessor; + value ret_v; +}; + +struct loader_impl_async_object_set_safe_type +{ + loader_impl_node node_impl; + object obj; + loader_impl_node_object node_obj; + struct accessor_type *accessor; + value v; +}; + +struct loader_impl_async_object_method_invoke_safe_type +{ + loader_impl_node node_impl; + object obj; + loader_impl_node_object node_obj; + method m; + void **args; + size_t argc; + value ret_v; +}; + +struct loader_impl_async_object_destroy_safe_type +{ + loader_impl_node node_impl; + object obj; + loader_impl_node_object node_obj; +}; + +struct loader_impl_async_class_ctor_safe_type +{ + loader_impl_node node_impl; + klass cls; + loader_impl_node_class node_klass; + const char *name; + void **args; + size_t argc; + object ret_obj; +}; + +struct loader_impl_async_class_static_invoke_safe_type +{ + loader_impl_node node_impl; + klass cls; + loader_impl_node_class node_klass; + method m; + void **args; + size_t argc; + value ret_v; +}; + +struct loader_impl_async_class_destroy_safe_type +{ + loader_impl_node node_impl; + klass cls; + loader_impl_node_class node_klass; +}; + typedef napi_value (*function_resolve_trampoline)(loader_impl_node, napi_env, function_resolve_callback, napi_value, napi_value, void *); typedef napi_value (*function_reject_trampoline)(loader_impl_node, napi_env, function_reject_callback, napi_value, napi_value, void *); @@ -476,13 +590,14 @@ typedef struct loader_impl_class_constructor_callback_closure_type { klass cls; loader_impl_node node_impl; + napi_ref constructor_ref; } * loader_impl_class_constructor_callback_closure; typedef struct loader_impl_class_property_callback_closure_type { klass cls; loader_impl_node node_impl; - char *prop_name; + const char *prop_name; } * loader_impl_class_property_callback_closure; /* Type conversion */ @@ -583,6 +698,34 @@ static void node_loader_impl_clear_safe(napi_env env, loader_impl_async_clear_sa static napi_value node_loader_impl_async_clear_safe(napi_env env, napi_callback_info info); +static void node_loader_impl_object_get_safe(napi_env env, loader_impl_async_object_get_safe object_get_safe); + +static napi_value node_loader_impl_async_object_get_safe(napi_env env, napi_callback_info info); + +static void node_loader_impl_object_set_safe(napi_env env, loader_impl_async_object_set_safe object_set_safe); + +static napi_value node_loader_impl_async_object_set_safe(napi_env env, napi_callback_info info); + +static void node_loader_impl_object_method_invoke_safe(napi_env env, loader_impl_async_object_method_invoke_safe object_method_invoke_safe); + +static napi_value node_loader_impl_async_object_method_invoke_safe(napi_env env, napi_callback_info info); + +static void node_loader_impl_object_destroy_safe(napi_env env, loader_impl_async_object_destroy_safe object_destroy_safe); + +static napi_value node_loader_impl_async_object_destroy_safe(napi_env env, napi_callback_info info); + +static void node_loader_impl_class_ctor_safe(napi_env env, loader_impl_async_class_ctor_safe class_ctor_safe); + +static napi_value node_loader_impl_async_class_ctor_safe(napi_env env, napi_callback_info info); + +static void node_loader_impl_class_static_invoke_safe(napi_env env, loader_impl_async_class_static_invoke_safe class_static_invoke_safe); + +static napi_value node_loader_impl_async_class_static_invoke_safe(napi_env env, napi_callback_info info); + +static void node_loader_impl_class_destroy_safe(napi_env env, loader_impl_async_class_destroy_safe class_destroy_safe); + +static napi_value node_loader_impl_async_class_destroy_safe(napi_env env, napi_callback_info info); + static value node_loader_impl_discover_function_safe(napi_env env, loader_impl_async_discover_function_safe discover_function_safe); static value node_loader_impl_discover_klass_safe(napi_env env, loader_impl_discover_klass_safe discover_klass_safe); @@ -940,7 +1083,7 @@ static napi_value node_loader_impl_class_method_property_callback(napi_env env, napi_get_cb_info(env, info, &argc, NULL, &this_obj, &closure_cast.ptr); closure_cast.safe->node_impl->env = env; - if (argc != 1) + if (argc > 0) { argv = new napi_value[argc]; } @@ -972,6 +1115,7 @@ static napi_value node_loader_impl_class_method_property_callback(napi_env env, } else if (n_methods > 1) { + //TODO: this implementation is problematic for (size_t iterator = 0; iterator < n_methods; ++iterator) { m = vector_at_type(methods, iterator, method); @@ -996,6 +1140,8 @@ static napi_value node_loader_impl_class_method_property_callback(napi_env env, } value result = object_call(obj_impl, m, args, argc); + delete[] args; + return node_loader_impl_value_to_napi(closure_cast.safe->node_impl, env, result); } @@ -1004,13 +1150,13 @@ static napi_value node_loader_impl_class_set_data_property_callback(napi_env env napi_status status; loader_impl_async_safe_cast closure_cast = { NULL }; size_t argc = 1; - napi_value *argv = new napi_value[argc]; + napi_value argv; napi_value this_obj; - napi_get_cb_info(env, info, &argc, argv, &this_obj, &closure_cast.ptr); + napi_get_cb_info(env, info, &argc, &argv, &this_obj, &closure_cast.ptr); closure_cast.safe->node_impl->env = env; - value arg = node_loader_impl_napi_to_value(closure_cast.safe->node_impl, env, NULL, argv[0]); + value arg = node_loader_impl_napi_to_value(closure_cast.safe->node_impl, env, NULL, argv); value obj; napi_unwrap(env, this_obj, &obj); @@ -1051,75 +1197,109 @@ static napi_value node_loader_impl_class_get_data_property_callback(napi_env env static napi_value node_loader_impl_class_constructor_callback(napi_env env, napi_callback_info info) { napi_status status; + napi_value target; + status = napi_get_new_target(env, info, &target); + node_loader_impl_exception(env, status); + loader_impl_async_safe_cast closure_cast = { NULL }; - napi_get_cb_info(env, info, NULL, NULL, NULL, &closure_cast.ptr); + napi_value jsthis; + napi_get_cb_info(env, info, NULL, NULL, &jsthis, &closure_cast.ptr); /* Set environment */ closure_cast.safe->node_impl->env = env; - char *klass_name_str = const_cast(class_name(closure_cast.safe->cls)); + bool is_constructor = target != nullptr; - constructor ctor = class_default_constructor(closure_cast.safe->cls); - if (ctor == NULL) + if (is_constructor) { - log_write("metacall", LOG_LEVEL_INFO, "NodeJS Loader No default constructor in class: ", klass_name_str); - } + const char *klass_name_str = class_name(closure_cast.safe->cls); - size_t argc = constructor_count(ctor); - napi_value *argv = new napi_value[argc]; + constructor ctor = class_default_constructor(closure_cast.safe->cls); + if (ctor == NULL) + { + log_write("metacall", LOG_LEVEL_INFO, "NodeJS Loader No default constructor in class: ", klass_name_str); + } - napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + size_t argc = constructor_count(ctor); + napi_value *argv = new napi_value[argc]; + if (argv == nullptr) + { + napi_throw_error(env, NULL, "NodeJS Loader memory allocation failed"); + } - void **args = new void *[argc]; + napi_get_cb_info(env, info, &argc, argv, NULL, NULL); - for (size_t iterator = 0; iterator < argc; ++iterator) - { - args[iterator] = node_loader_impl_napi_to_value(closure_cast.safe->node_impl, env, NULL, argv[iterator]); - } + void **args = new void *[argc]; + if (args == nullptr) + { + napi_throw_error(env, NULL, "NodeJS Loader memory allocation failed"); + } - type_id *ids = node_loader_impl_type_ids(args, argc); + for (size_t iterator = 0; iterator < argc; ++iterator) + { + args[iterator] = node_loader_impl_napi_to_value(closure_cast.safe->node_impl, env, NULL, argv[iterator]); + } - ctor = class_constructor(closure_cast.safe->cls, ids, argc); + type_id *ids = node_loader_impl_type_ids(args, argc); - //convert class_name to lower case - std::string obj_name(klass_name_str); - for (size_t i = 0; i < obj_name.size(); i++) - { - obj_name[i] = std::tolower(obj_name[i]); - } + if (ids != NULL) + { + ctor = class_constructor(closure_cast.safe->cls, ids, argc); + free(ids); + } - object o = class_new(closure_cast.safe->cls, obj_name.c_str(), ctor, args, argc); + //convert class_name to lower case + std::string obj_name(klass_name_str); + for (size_t i = 0; i < obj_name.size(); i++) + { + obj_name[i] = std::tolower(obj_name[i]); + } - if (ids != NULL) - { - free(ids); - } + object o = class_new(closure_cast.safe->cls, obj_name.c_str(), ctor, args, argc); - if (o == NULL) - { - return NULL; - } + delete[] args; - value v = value_create_object(o); + if (o == NULL) + { + napi_throw_error(env, NULL, "NodeJS Loader Failed to create object"); + } - if (v == NULL) - { - object_destroy(o); - std::string error_msg = "NodeJS Loader Failed to create object for class: "; - error_msg += klass_name_str; - napi_throw_error(env, NULL, error_msg.c_str()); + value v = value_create_object(o); + + if (v == NULL) + { + object_destroy(o); + std::string error_msg = "NodeJS Loader Failed to create object for class: "; + error_msg += klass_name_str; + napi_throw_error(env, NULL, error_msg.c_str()); + } + + //Todo: Implement finalize callback + status = napi_wrap(env, jsthis, v, NULL, NULL, NULL); + node_loader_impl_exception(env, status); + + return jsthis; } + else + { + napi_value cons; + status = napi_get_reference_value(env, closure_cast.safe->constructor_ref, &cons); + node_loader_impl_exception(env, status); - napi_value js_object; - status = napi_create_object(env, &js_object); - node_loader_impl_exception(env, status); + size_t argc; + status = napi_get_cb_info(env, info, &argc, NULL, NULL, NULL); + node_loader_impl_exception(env, status); - //Todo: Implement finalize callback - status = napi_wrap(env, js_object, v, NULL, NULL, NULL); - node_loader_impl_exception(env, status); + napi_value *argv = new napi_value[argc]; + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + + napi_value instance; + status = napi_new_instance(env, cons, argc, argv, &instance); + node_loader_impl_exception(env, status); - return js_object; + return instance; + } } value node_loader_impl_napi_to_value(loader_impl_node node_impl, napi_env env, napi_value recv, napi_value v) @@ -1591,89 +1771,102 @@ napi_value node_loader_impl_value_to_napi(loader_impl_node node_impl, napi_env e else if (id == TYPE_CLASS) { klass cls = value_to_class(arg_value); - vector methods = class_method_names(cls); - vector static_methods = class_static_method_names(cls); - vector attributes = class_attribute_names(cls); - vector static_attributes = class_static_attribute_names(cls); + vector methods = class_get_methods(cls); + vector static_methods = class_get_static_methods(cls); + vector attributes = class_get_attributes(cls); + vector static_attributes = class_get_static_attributes(cls); size_t property_count = vector_size(methods) + vector_size(static_methods) + vector_size(attributes) + vector_size(static_attributes); + napi_property_descriptor *properties = new napi_property_descriptor[property_count]; size_t iterator = 0; //Define method properties for (size_t i = 0; i < vector_size(methods) && iterator < property_count; iterator++, i++) { + method m = vector_at_type(methods, i, method); + const char *m_name = method_name(m); + loader_impl_class_property_callback_closure closure = new struct loader_impl_class_property_callback_closure_type; closure->cls = cls; closure->node_impl = node_impl; - closure->prop_name = vector_at_type(methods, i, char *); + closure->prop_name = m_name; - properties[iterator].utf8name = vector_at_type(methods, i, char *); + properties[iterator].utf8name = m_name; properties[iterator].name = NULL; properties[iterator].method = node_loader_impl_class_method_property_callback; properties[iterator].getter = NULL; properties[iterator].setter = NULL; properties[iterator].value = NULL; properties[iterator].attributes = napi_default_method; - properties[iterator].data = (void *)closure; + properties[iterator].data = reinterpret_cast(closure); } //Define static method properties for (size_t i = 0; i < vector_size(static_methods) && iterator < property_count; iterator++, i++) { + method m = vector_at_type(static_methods, i, method); + const char *m_name = method_name(m); + loader_impl_class_property_callback_closure closure = new struct loader_impl_class_property_callback_closure_type; closure->cls = cls; closure->node_impl = node_impl; - closure->prop_name = vector_at_type(static_methods, i, char *); + closure->prop_name = m_name; - properties[iterator].utf8name = vector_at_type(static_methods, i, char *); + properties[iterator].utf8name = m_name; properties[iterator].name = NULL; properties[iterator].method = node_loader_impl_class_method_property_callback; properties[iterator].getter = NULL; properties[iterator].setter = NULL; properties[iterator].value = NULL; properties[iterator].attributes = napi_static; - properties[iterator].data = (void *)closure; + properties[iterator].data = reinterpret_cast(closure); } //Define attribute properties for (size_t i = 0; i < vector_size(attributes) && iterator < property_count; iterator++, i++) { + attribute attr = vector_at_type(attributes, i, attribute); + const char *attr_name = attribute_name(attr); + loader_impl_class_property_callback_closure closure = new struct loader_impl_class_property_callback_closure_type; closure->cls = cls; closure->node_impl = node_impl; - closure->prop_name = vector_at_type(attributes, i, char *); + closure->prop_name = attr_name; - properties[iterator].utf8name = vector_at_type(attributes, i, char *); + properties[iterator].utf8name = attr_name; properties[iterator].name = NULL; properties[iterator].method = NULL; properties[iterator].getter = node_loader_impl_class_get_data_property_callback; properties[iterator].setter = node_loader_impl_class_set_data_property_callback; properties[iterator].value = NULL; properties[iterator].attributes = napi_default_jsproperty; - properties[iterator].data = (void *)closure; + properties[iterator].data = reinterpret_cast(closure); } //NodeJS doesn't support static attributes so we define them as normal attributes for (size_t i = 0; i < vector_size(static_attributes) && iterator < property_count; iterator++, i++) { + attribute attr = vector_at_type(static_attributes, i, attribute); + const char *attr_name = attribute_name(attr); + loader_impl_class_property_callback_closure closure = new struct loader_impl_class_property_callback_closure_type; closure->cls = cls; closure->node_impl = node_impl; - closure->prop_name = vector_at_type(static_attributes, i, char *); + closure->prop_name = attr_name; - properties[iterator].utf8name = vector_at_type(static_attributes, i, char *); + properties[iterator].utf8name = attr_name; properties[iterator].name = NULL; properties[iterator].method = NULL; properties[iterator].getter = node_loader_impl_class_get_data_property_callback; properties[iterator].setter = node_loader_impl_class_set_data_property_callback; properties[iterator].value = NULL; properties[iterator].attributes = napi_default_jsproperty; - properties[iterator].data = (void *)closure; + properties[iterator].data = reinterpret_cast(closure); } napi_value result; @@ -1684,6 +1877,10 @@ napi_value node_loader_impl_value_to_napi(loader_impl_node node_impl, napi_env e status = napi_define_class(env, class_name(cls), NAPI_AUTO_LENGTH, node_loader_impl_class_constructor_callback, (void *)ctor_data, property_count, properties, &result); node_loader_impl_exception(env, status); + + status = napi_create_reference(env, result, 1, &ctor_data->constructor_ref); + node_loader_impl_exception(env, status); + return result; } else if (id == TYPE_OBJECT) @@ -2208,83 +2405,207 @@ int node_object_interface_create(object obj, object_impl impl) value node_object_interface_get(object obj, object_impl impl, struct accessor_type *accessor) { - (void)obj; - loader_impl_node_object node_obj = (loader_impl_node_object)impl; - napi_value obj_value = NULL; + value ret = NULL; napi_status status; - status = napi_get_reference_value(node_obj->node_impl->env, node_obj->obj_ref, &obj_value); - node_loader_impl_exception(node_obj->node_impl->env, status); + /* Set up call safe arguments */ + node_obj->node_impl->object_get_safe->node_impl = node_obj->node_impl; + node_obj->node_impl->object_get_safe->obj = obj; + node_obj->node_impl->object_get_safe->node_obj = node_obj; + node_obj->node_impl->object_get_safe->accessor = accessor; + node_obj->node_impl->object_get_safe->ret_v = NULL; - attribute attr = accessor->data.attr; - const char *key = (const char *)attribute_name(attr); - //type fieldType = (type)attribute_type(attr); + /* Check if we are in the JavaScript thread */ + if (node_obj->node_impl->js_thread_id == std::this_thread::get_id()) + { + /* We are already in the V8 thread, we can call safely */ + node_loader_impl_object_get_safe(node_obj->node_impl->env, node_obj->node_impl->object_get_safe); - napi_value prop_value = NULL; - status = napi_get_named_property(node_obj->node_impl->env, obj_value, key, &prop_value); - node_loader_impl_exception(node_obj->node_impl->env, status); + /* Set up return of the static method call */ + ret = node_obj->node_impl->object_get_safe->ret_v; + } + /* Lock the mutex and set the parameters */ + else if (node_obj->node_impl->locked.load() == false && uv_mutex_trylock(&node_obj->node_impl->mutex) == 0) + { + node_obj->node_impl->locked.store(true); - value v = node_loader_impl_napi_to_value(node_obj->node_impl, node_obj->node_impl->env, nullptr, prop_value); + /* Acquire the thread safe function in order to do the call */ + status = napi_acquire_threadsafe_function(node_obj->node_impl->threadsafe_object_get); - return v; + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to aquire thread safe function for object set in NodeJS loader"); + } + + /* Execute the thread safe call in a nonblocking manner */ + status = napi_call_threadsafe_function(node_obj->node_impl->threadsafe_object_get, nullptr, napi_tsfn_nonblocking); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "call to object set thread safe function failed in NodeJS loader"); + } + + /* Release call safe function */ + status = napi_release_threadsafe_function(node_obj->node_impl->threadsafe_object_get, napi_tsfn_release); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to release object set thread safe function in NodeJS loader"); + } + + /* Wait for the execution of the safe call */ + uv_cond_wait(&node_obj->node_impl->cond, &node_obj->node_impl->mutex); + + /* Set up return of the function call */ + ret = node_obj->node_impl->object_get_safe->ret_v; + + node_obj->node_impl->locked.store(false); + + /* Unlock the mutex */ + uv_mutex_unlock(&node_obj->node_impl->mutex); + } + else + { + log_write("metacall", LOG_LEVEL_ERROR, "Potential deadlock detected in node_object_interface_set, the call has not been executed in order to avoid the deadlock"); + } + + return ret; } int node_object_interface_set(object obj, object_impl impl, struct accessor_type *accessor, value v) { - (void)obj; - loader_impl_node_object node_obj = (loader_impl_node_object)impl; - napi_value obj_value = NULL; napi_status status; - status = napi_get_reference_value(node_obj->node_impl->env, node_obj->obj_ref, &obj_value); - node_loader_impl_exception(node_obj->node_impl->env, status); + /* Set up call safe arguments */ + node_obj->node_impl->object_set_safe->node_impl = node_obj->node_impl; + node_obj->node_impl->object_set_safe->obj = obj; + node_obj->node_impl->object_set_safe->node_obj = node_obj; + node_obj->node_impl->object_set_safe->accessor = accessor; + node_obj->node_impl->object_set_safe->v = v; - attribute attr = accessor->data.attr; - const char *key = (const char *)attribute_name(attr); - //type fieldType = (type)attribute_type(attr); + /* Check if we are in the JavaScript thread */ + if (node_obj->node_impl->js_thread_id == std::this_thread::get_id()) + { + /* We are already in the V8 thread, we can call safely */ + node_loader_impl_object_set_safe(node_obj->node_impl->env, node_obj->node_impl->object_set_safe); + } + /* Lock the mutex and set the parameters */ + else if (node_obj->node_impl->locked.load() == false && uv_mutex_trylock(&node_obj->node_impl->mutex) == 0) + { + node_obj->node_impl->locked.store(true); + + /* Acquire the thread safe function in order to do the call */ + status = napi_acquire_threadsafe_function(node_obj->node_impl->threadsafe_object_set); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to aquire thread safe function for object set in NodeJS loader"); + } + + /* Execute the thread safe call in a nonblocking manner */ + status = napi_call_threadsafe_function(node_obj->node_impl->threadsafe_object_set, nullptr, napi_tsfn_nonblocking); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "call to object set thread safe function failed in NodeJS loader"); + } + + /* Release call safe function */ + status = napi_release_threadsafe_function(node_obj->node_impl->threadsafe_object_set, napi_tsfn_release); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to release object set thread safe function in NodeJS loader"); + } - napi_value prop_value = node_loader_impl_value_to_napi(node_obj->node_impl, node_obj->node_impl->env, v); + /* Wait for the execution of the safe call */ + uv_cond_wait(&node_obj->node_impl->cond, &node_obj->node_impl->mutex); - status = napi_set_named_property(node_obj->node_impl->env, obj_value, key, prop_value); + node_obj->node_impl->locked.store(false); - node_loader_impl_exception(node_obj->node_impl->env, status); + /* Unlock the mutex */ + uv_mutex_unlock(&node_obj->node_impl->mutex); + } + else + { + log_write("metacall", LOG_LEVEL_ERROR, "Potential deadlock detected in node_object_interface_set, the call has not been executed in order to avoid the deadlock"); + } return 0; } value node_object_interface_method_invoke(object obj, object_impl impl, method m, object_args args, size_t argc) { - (void)obj; loader_impl_node_object node_obj = (loader_impl_node_object)impl; - napi_value obj_value; - napi_value result; + value ret = NULL; napi_status status; - status = napi_get_reference_value(node_obj->node_impl->env, node_obj->obj_ref, &obj_value); - node_loader_impl_exception(node_obj->node_impl->env, status); + /* Set up call safe arguments */ + node_obj->node_impl->object_method_invoke_safe->node_impl = node_obj->node_impl; + node_obj->node_impl->object_method_invoke_safe->obj = obj; + node_obj->node_impl->object_method_invoke_safe->node_obj = node_obj; + node_obj->node_impl->object_method_invoke_safe->m = m; + node_obj->node_impl->object_method_invoke_safe->args = args; + node_obj->node_impl->object_method_invoke_safe->argc = argc; + node_obj->node_impl->object_method_invoke_safe->ret_v = nullptr; - const char *m_name = method_name(m); + /* Check if we are in the JavaScript thread */ + if (node_obj->node_impl->js_thread_id == std::this_thread::get_id()) + { + /* We are already in the V8 thread, we can call safely */ + node_loader_impl_object_method_invoke_safe(node_obj->node_impl->env, node_obj->node_impl->object_method_invoke_safe); - napi_value m_value = NULL; - status = napi_get_named_property(node_obj->node_impl->env, obj_value, m_name, &m_value); - node_loader_impl_exception(node_obj->node_impl->env, status); + /* Set up return of the static method call */ + ret = node_obj->node_impl->object_method_invoke_safe->ret_v; + } + /* Lock the mutex and set the parameters */ + else if (node_obj->node_impl->locked.load() == false && uv_mutex_trylock(&node_obj->node_impl->mutex) == 0) + { + node_obj->node_impl->locked.store(true); - napi_value *m_args = new napi_value[argc]; + /* Acquire the thread safe function in order to do the call */ + status = napi_acquire_threadsafe_function(node_obj->node_impl->threadsafe_object_method_invoke); - for (size_t i = 0; i < argc; i++) - { - m_args[i] = node_loader_impl_value_to_napi(node_obj->node_impl, node_obj->node_impl->env, args[i]); - } + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to aquire thread safe function for object method invoke in NodeJS loader"); + } - napi_call_function(node_obj->node_impl->env, obj_value, m_value, argc, m_args, &result); + /* Execute the thread safe call in a nonblocking manner */ + status = napi_call_threadsafe_function(node_obj->node_impl->threadsafe_object_method_invoke, nullptr, napi_tsfn_nonblocking); - value v = node_loader_impl_napi_to_value(node_obj->node_impl, node_obj->node_impl->env, nullptr, result); + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "call to object method invoke thread safe function failed in NodeJS loader"); + } - delete[] m_args; + /* Release call safe function */ + status = napi_release_threadsafe_function(node_obj->node_impl->threadsafe_object_method_invoke, napi_tsfn_release); - return v; + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to release object method invoke thread safe function in NodeJS loader"); + } + + /* Wait for the execution of the safe call */ + uv_cond_wait(&node_obj->node_impl->cond, &node_obj->node_impl->mutex); + + /* Set up return of the function call */ + ret = node_obj->node_impl->object_method_invoke_safe->ret_v; + + node_obj->node_impl->locked.store(false); + + /* Unlock the mutex */ + uv_mutex_unlock(&node_obj->node_impl->mutex); + } + else + { + log_write("metacall", LOG_LEVEL_ERROR, "Potential deadlock detected in node_object_interface_method_invoke, the call has not been executed in order to avoid the deadlock"); + } + + return ret; } value node_object_interface_method_await(object obj, object_impl impl, method m, object_args args, size_t size, object_resolve_callback resolve, object_reject_callback reject, void *ctx) @@ -2314,34 +2635,87 @@ int node_object_interface_destructor(object obj, object_impl impl) void node_object_interface_destroy(object obj, object_impl impl) { - (void)obj; - loader_impl_node_object node_obj = (loader_impl_node_object)impl; if (node_obj != NULL) { if (loader_is_destroyed(node_obj->impl) != 0) { - //Todo - } - - free(node_obj); - } -} + loader_impl_node node_impl = node_obj->node_impl; + napi_status status; -object_interface node_object_interface_singleton(void) -{ - static struct object_interface_type node_object_interface = { - &node_object_interface_create, - &node_object_interface_get, - &node_object_interface_set, - &node_object_interface_method_invoke, - &node_object_interface_method_await, - &node_object_interface_destructor, - &node_object_interface_destroy - }; + /* Set up class destroy safe arguments */ + node_obj->node_impl->object_destroy_safe->node_impl = node_impl; + node_obj->node_impl->object_destroy_safe->node_obj = node_obj; + node_obj->node_impl->object_destroy_safe->obj = obj; - return &node_object_interface; + /* Check if we are in the JavaScript thread */ + if (node_impl->js_thread_id == std::this_thread::get_id()) + { + /* We are already in the V8 thread, we can call safely */ + node_loader_impl_object_destroy_safe(node_impl->env, node_impl->object_destroy_safe); + } + /* Lock the mutex and set the parameters */ + else if (node_impl->locked.load() == false && uv_mutex_trylock(&node_impl->mutex) == 0) + { + node_impl->locked.store(true); + + /* Acquire the thread safe function in order to do the call */ + status = napi_acquire_threadsafe_function(node_impl->threadsafe_object_destroy); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to aquire thread safe function class_destroy in NodeJS loader"); + } + + /* Execute the thread safe call in a nonblocking manner */ + status = napi_call_threadsafe_function(node_impl->threadsafe_object_destroy, nullptr, napi_tsfn_nonblocking); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "call to class_destroy_safe thread safe function failed in NodeJS loader"); + } + + /* Release call safe function */ + status = napi_release_threadsafe_function(node_impl->threadsafe_object_destroy, napi_tsfn_release); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to release class_destroy_safe thread safe function in NodeJS loader"); + } + + /* Wait for the execution of the safe call */ + uv_cond_wait(&node_impl->cond, &node_impl->mutex); + + node_impl->locked.store(false); + + /* Unlock call safe mutex */ + uv_mutex_unlock(&node_impl->mutex); + } + else + { + log_write("metacall", LOG_LEVEL_ERROR, "Potential deadlock detected in node_class_interface_destroy, the call has not been executed in order to avoid the deadlock"); + } + } + + /* Delete node class impl */ + delete node_obj; + } +} + +object_interface node_object_interface_singleton(void) +{ + static struct object_interface_type node_object_interface = { + &node_object_interface_create, + &node_object_interface_get, + &node_object_interface_set, + &node_object_interface_method_invoke, + &node_object_interface_method_await, + &node_object_interface_destructor, + &node_object_interface_destroy + }; + + return &node_object_interface; } int node_class_interface_create(klass cls, class_impl impl) @@ -2358,39 +2732,73 @@ object node_class_interface_constructor(klass cls, class_impl impl, const char * loader_impl_node_class node_klass = (loader_impl_node_class)impl; - loader_impl_node_object node_obj = new struct loader_impl_node_object_type; + object ret = nullptr; + napi_status status; - object obj = object_create(name, ACCESSOR_TYPE_DYNAMIC, node_obj, &node_object_interface_singleton, cls); + /* Set up call safe arguments */ + node_klass->node_impl->class_ctor_safe->node_impl = node_klass->node_impl; + node_klass->node_impl->class_ctor_safe->cls = cls; + node_klass->node_impl->class_ctor_safe->node_klass = node_klass; + node_klass->node_impl->class_ctor_safe->name = name; + node_klass->node_impl->class_ctor_safe->args = args; + node_klass->node_impl->class_ctor_safe->argc = argc; + node_klass->node_impl->class_ctor_safe->ret_obj = nullptr; - if (obj == NULL) + /* Check if we are in the JavaScript thread */ + if (node_klass->node_impl->js_thread_id == std::this_thread::get_id()) { - return NULL; + /* We are already in the V8 thread, we can call safely */ + node_loader_impl_class_ctor_safe(node_klass->node_impl->env, node_klass->node_impl->class_ctor_safe); + + /* Set up return of the constructor call */ + ret = node_klass->node_impl->class_ctor_safe->ret_obj; } + /* Lock the mutex and set the parameters */ + else if (node_klass->node_impl->locked.load() == false && uv_mutex_trylock(&node_klass->node_impl->mutex) == 0) + { + node_klass->node_impl->locked.store(true); - napi_value *m_args = new napi_value[argc]; + /* Acquire the thread safe function in order to do the call */ + status = napi_acquire_threadsafe_function(node_klass->node_impl->threadsafe_class_ctor); - for (size_t i = 0; i < argc; i++) - { - m_args[i] = node_loader_impl_value_to_napi(node_obj->node_impl, node_obj->node_impl->env, args[i]); - } + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to aquire thread safe function for class constructor call in NodeJS loader"); + } - napi_status status; - napi_value klass_cons; - status = napi_get_reference_value(node_obj->node_impl->env, node_klass->klass_ref, &klass_cons); - node_loader_impl_exception(node_obj->node_impl->env, status); + /* Execute the thread safe call in a nonblocking manner */ + status = napi_call_threadsafe_function(node_klass->node_impl->threadsafe_class_ctor, nullptr, napi_tsfn_nonblocking); - napi_value result; - status = napi_new_instance(node_obj->node_impl->env, klass_cons, argc, m_args, &result); - node_loader_impl_exception(node_obj->node_impl->env, status); + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "call to class constructor thread safe function failed in NodeJS loader"); + } - //Todo check that object is an instance of constructor + /* Release call safe function */ + status = napi_release_threadsafe_function(node_klass->node_impl->threadsafe_class_ctor, napi_tsfn_release); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to release class constructor thread safe function in NodeJS loader"); + } + + /* Wait for the execution of the safe call */ + uv_cond_wait(&node_klass->node_impl->cond, &node_klass->node_impl->mutex); - status = napi_create_reference(node_obj->node_impl->env, result, 1, &node_obj->obj_ref); - node_loader_impl_exception(node_obj->node_impl->env, status); + /* Set up return of the function call */ + ret = node_klass->node_impl->class_ctor_safe->ret_obj; - delete[] m_args; + node_klass->node_impl->locked.store(false); - return obj; + /* Unlock the mutex */ + uv_mutex_unlock(&node_klass->node_impl->mutex); + } + else + { + log_write("metacall", LOG_LEVEL_ERROR, "Potential deadlock detected in node_class_interface_constructor, the call has not been executed in order to avoid the deadlock"); + } + + return ret; } value node_class_interface_static_get(klass cls, class_impl impl, struct accessor_type *accessor) @@ -2416,34 +2824,73 @@ value node_class_interface_static_invoke(klass cls, class_impl impl, method m, c { (void)cls; loader_impl_node_class node_klass = (loader_impl_node_class)impl; - napi_value klass_cons; - napi_value result; + value ret = NULL; napi_status status; - status = napi_get_reference_value(node_klass->node_impl->env, node_klass->klass_ref, &klass_cons); - node_loader_impl_exception(node_klass->node_impl->env, status); + /* Set up call safe arguments */ + node_klass->node_impl->class_static_invoke_safe->node_impl = node_klass->node_impl; + node_klass->node_impl->class_static_invoke_safe->cls = cls; + node_klass->node_impl->class_static_invoke_safe->node_klass = node_klass; + node_klass->node_impl->class_static_invoke_safe->m = m; + node_klass->node_impl->class_static_invoke_safe->args = args; + node_klass->node_impl->class_static_invoke_safe->argc = argc; + node_klass->node_impl->class_static_invoke_safe->ret_v = nullptr; - const char *m_name = method_name(m); + /* Check if we are in the JavaScript thread */ + if (node_klass->node_impl->js_thread_id == std::this_thread::get_id()) + { + /* We are already in the V8 thread, we can call safely */ + node_loader_impl_class_static_invoke_safe(node_klass->node_impl->env, node_klass->node_impl->class_static_invoke_safe); - napi_value m_value = NULL; - status = napi_get_named_property(node_klass->node_impl->env, klass_cons, m_name, &m_value); - node_loader_impl_exception(node_klass->node_impl->env, status); + /* Set up return of the static method call */ + ret = node_klass->node_impl->class_static_invoke_safe->ret_v; + } + /* Lock the mutex and set the parameters */ + else if (node_klass->node_impl->locked.load() == false && uv_mutex_trylock(&node_klass->node_impl->mutex) == 0) + { + node_klass->node_impl->locked.store(true); - napi_value *m_args = new napi_value[argc]; + /* Acquire the thread safe function in order to do the call */ + status = napi_acquire_threadsafe_function(node_klass->node_impl->threadsafe_class_static_invoke); - for (size_t i = 0; i < argc; i++) - { - m_args[i] = node_loader_impl_value_to_napi(node_klass->node_impl, node_klass->node_impl->env, args[i]); - } + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to aquire thread safe function for static method invoke in NodeJS loader"); + } + + /* Execute the thread safe call in a nonblocking manner */ + status = napi_call_threadsafe_function(node_klass->node_impl->threadsafe_class_static_invoke, nullptr, napi_tsfn_nonblocking); - status = napi_call_function(node_klass->node_impl->env, klass_cons, m_value, argc, m_args, &result); - node_loader_impl_exception(node_klass->node_impl->env, status); + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "call to static method invoke thread safe function failed in NodeJS loader"); + } - value v = node_loader_impl_napi_to_value(node_klass->node_impl, node_klass->node_impl->env, nullptr, result); + /* Release call safe function */ + status = napi_release_threadsafe_function(node_klass->node_impl->threadsafe_class_static_invoke, napi_tsfn_release); - delete[] m_args; + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to release static method invoke thread safe function in NodeJS loader"); + } - return v; + /* Wait for the execution of the safe call */ + uv_cond_wait(&node_klass->node_impl->cond, &node_klass->node_impl->mutex); + + /* Set up return of the function call */ + ret = node_klass->node_impl->class_static_invoke_safe->ret_v; + + node_klass->node_impl->locked.store(false); + + /* Unlock the mutex */ + uv_mutex_unlock(&node_klass->node_impl->mutex); + } + else + { + log_write("metacall", LOG_LEVEL_ERROR, "Potential deadlock detected in node_class_interface_static_invoke, the call has not been executed in order to avoid the deadlock"); + } + + return ret; } value node_class_interface_static_await(klass cls, class_impl impl, method m, class_args args, size_t size, class_resolve_callback resolve, class_reject_callback reject, void *ctx) @@ -2463,18 +2910,71 @@ value node_class_interface_static_await(klass cls, class_impl impl, method m, cl void node_class_interface_destroy(klass cls, class_impl impl) { - loader_impl_node_class node_class = (loader_impl_node_class)impl; - - (void)cls; + loader_impl_node_class node_klass = (loader_impl_node_class)impl; - if (node_class != NULL) + if (node_klass != NULL) { - if (loader_is_destroyed(node_class->impl) != 0) + if (loader_is_destroyed(node_klass->impl) != 0) { - //TODO + loader_impl_node node_impl = node_klass->node_impl; + napi_status status; + + /* Set up class destroy safe arguments */ + node_klass->node_impl->class_destroy_safe->node_impl = node_impl; + node_klass->node_impl->class_destroy_safe->node_klass = node_klass; + node_klass->node_impl->class_destroy_safe->cls = cls; + + /* Check if we are in the JavaScript thread */ + if (node_impl->js_thread_id == std::this_thread::get_id()) + { + /* We are already in the V8 thread, we can call safely */ + node_loader_impl_class_destroy_safe(node_impl->env, node_impl->class_destroy_safe); + } + /* Lock the mutex and set the parameters */ + else if (node_impl->locked.load() == false && uv_mutex_trylock(&node_impl->mutex) == 0) + { + node_impl->locked.store(true); + + /* Acquire the thread safe function in order to do the call */ + status = napi_acquire_threadsafe_function(node_impl->threadsafe_class_destroy); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to aquire thread safe function class_destroy in NodeJS loader"); + } + + /* Execute the thread safe call in a nonblocking manner */ + status = napi_call_threadsafe_function(node_impl->threadsafe_class_destroy, nullptr, napi_tsfn_nonblocking); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "call to class_destroy_safe thread safe function failed in NodeJS loader"); + } + + /* Release call safe function */ + status = napi_release_threadsafe_function(node_impl->threadsafe_class_destroy, napi_tsfn_release); + + if (status != napi_ok) + { + log_write("metacall", LOG_LEVEL_ERROR, "Unable to release class_destroy_safe thread safe function in NodeJS loader"); + } + + /* Wait for the execution of the safe call */ + uv_cond_wait(&node_impl->cond, &node_impl->mutex); + + node_impl->locked.store(false); + + /* Unlock call safe mutex */ + uv_mutex_unlock(&node_impl->mutex); + } + else + { + log_write("metacall", LOG_LEVEL_ERROR, "Potential deadlock detected in node_class_interface_destroy, the call has not been executed in order to avoid the deadlock"); + } } - free(node_class); + /* Delete node class impl */ + delete node_klass; } } @@ -2551,244 +3051,652 @@ void node_loader_impl_initialize_safe(napi_env env, loader_impl_async_initialize status = napi_get_reference_value(env, node_impl->global_ref, &global); - node_loader_impl_exception(env, status); + node_loader_impl_exception(env, status); + + status = napi_call_function(env, global, function_trampoline_initialize, 1, argv, &return_value); + + node_loader_impl_exception(env, status); + } + + /* Close scope */ + status = napi_close_handle_scope(env, handle_scope); + + node_loader_impl_exception(env, status); +} + +napi_value node_loader_impl_async_initialize_safe(napi_env env, napi_callback_info info) +{ + loader_impl_async_safe_cast initialize_cast = { NULL }; + + napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &initialize_cast.ptr); + + node_loader_impl_exception(env, status); + + /* Lock node implementation mutex */ + uv_mutex_lock(&initialize_cast.safe->node_impl->mutex); + + /* Store environment for reentrant calls */ + initialize_cast.safe->node_impl->env = env; + + /* Call to the implementation function */ + node_loader_impl_initialize_safe(env, initialize_cast.safe); + + /* Clear environment */ + // initialize_cast.safe->node_impl->env = NULL; + + /* Signal start condition */ + uv_cond_signal(&initialize_cast.safe->node_impl->cond); + + uv_mutex_unlock(&initialize_cast.safe->node_impl->mutex); + + return nullptr; +} + +void node_loader_impl_execution_path_safe(napi_env env, loader_impl_async_execution_path_safe execution_path_safe) +{ + static const char execution_path_str[] = "execution_path"; + napi_value function_table_object; + napi_value execution_path_str_value; + bool result = false; + napi_handle_scope handle_scope; + loader_impl_node node_impl = execution_path_safe->node_impl; + + /* Create scope */ + napi_status status = napi_open_handle_scope(env, &handle_scope); + + node_loader_impl_exception(env, status); + + /* Get function table object from reference */ + status = napi_get_reference_value(env, node_impl->function_table_object_ref, &function_table_object); + + node_loader_impl_exception(env, status); + + /* Create function string */ + status = napi_create_string_utf8(env, execution_path_str, sizeof(execution_path_str) - 1, &execution_path_str_value); + + node_loader_impl_exception(env, status); + + /* Check if exists in the table */ + status = napi_has_own_property(env, function_table_object, execution_path_str_value, &result); + + node_loader_impl_exception(env, status); + + if (result == true) + { + napi_value function_trampoline_execution_path; + napi_valuetype valuetype; + napi_value argv[1]; + + status = napi_get_named_property(env, function_table_object, execution_path_str, &function_trampoline_execution_path); + + node_loader_impl_exception(env, status); + + status = napi_typeof(env, function_trampoline_execution_path, &valuetype); + + node_loader_impl_exception(env, status); + + if (valuetype != napi_function) + { + napi_throw_type_error(env, nullptr, "Invalid function execution_path in function table object"); + } + + /* Create parameters */ + status = napi_create_string_utf8(env, execution_path_safe->path, strlen(execution_path_safe->path), &argv[0]); + + node_loader_impl_exception(env, status); + + /* Call to load from file function */ + napi_value global, return_value; + + status = napi_get_reference_value(env, node_impl->global_ref, &global); + + node_loader_impl_exception(env, status); + + status = napi_call_function(env, global, function_trampoline_execution_path, 1, argv, &return_value); + + node_loader_impl_exception(env, status); + } + + /* Close scope */ + status = napi_close_handle_scope(env, handle_scope); + + node_loader_impl_exception(env, status); +} + +napi_value node_loader_impl_async_execution_path_safe(napi_env env, napi_callback_info info) +{ + loader_impl_async_safe_cast execution_path_cast = { NULL }; + + napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &execution_path_cast.ptr); + + node_loader_impl_exception(env, status); + + /* Lock node implementation mutex */ + uv_mutex_lock(&execution_path_cast.safe->node_impl->mutex); + + /* Store environment for reentrant calls */ + execution_path_cast.safe->node_impl->env = env; + + /* Call to the implementation function */ + node_loader_impl_execution_path_safe(env, execution_path_cast.safe); + + /* Clear environment */ + // execution_path_cast.safe->node_impl->env = NULL; + + /* Signal start condition */ + uv_cond_signal(&execution_path_cast.safe->node_impl->cond); + + uv_mutex_unlock(&execution_path_cast.safe->node_impl->mutex); + + return nullptr; +} + +void node_loader_impl_func_call_safe(napi_env env, loader_impl_async_func_call_safe func_call_safe) +{ + napi_handle_scope handle_scope; + size_t args_size; + value *args; + napi_value *argv; + loader_impl_node_function node_func; + size_t args_count; + signature s = function_signature(func_call_safe->func); + const size_t signature_args_size = signature_count(s); + + /* Get function data */ + args_size = func_call_safe->size; + node_func = func_call_safe->node_func; + args = func_call_safe->args; + + /* Allocate dynamically more space for values in case of variable arguments */ + argv = args_size > signature_args_size ? static_cast(malloc(sizeof(napi_value) * args_size)) : node_func->argv; + + /* Create scope */ + napi_status status = napi_open_handle_scope(env, &handle_scope); + + node_loader_impl_exception(env, status); + + /* Build parameters */ + for (args_count = 0; args_count < args_size; ++args_count) + { + /* Define parameter */ + argv[args_count] = node_loader_impl_value_to_napi(func_call_safe->node_impl, env, args[args_count]); + } + + /* Get function reference */ + napi_value function_ptr; + + status = napi_get_reference_value(env, node_func->func_ref, &function_ptr); + + node_loader_impl_exception(env, status); + + /* Get global */ + napi_value global; + + status = napi_get_reference_value(env, func_call_safe->node_impl->global_ref, &global); + + node_loader_impl_exception(env, status); + + /* Call to function */ + napi_value func_return; + + status = napi_call_function(env, global, function_ptr, args_size, argv, &func_return); + + func_call_safe->ret = node_loader_impl_exception_value(func_call_safe->node_impl, env, status, func_call_safe->recv); + + if (func_call_safe->ret == NULL) + { + /* Convert function return to value */ + func_call_safe->ret = node_loader_impl_napi_to_value(func_call_safe->node_impl, env, func_call_safe->recv, func_return); + } + + /* Close scope */ + status = napi_close_handle_scope(env, handle_scope); + + node_loader_impl_exception(env, status); + + if (args_size > signature_args_size) + { + free(argv); + } +} + +napi_value node_loader_impl_async_func_call_safe(napi_env env, napi_callback_info info) +{ + loader_impl_async_safe_cast func_call_cast = { NULL }; + napi_status status; + napi_value recv; + + status = napi_get_cb_info(env, info, nullptr, nullptr, &recv, &func_call_cast.ptr); + + node_loader_impl_exception(env, status); + + /* Lock the call safe mutex and get the parameters */ + uv_mutex_lock(&func_call_cast.safe->node_impl->mutex); + + /* Store function recv for reentrant calls */ + func_call_cast.safe->recv = recv; + + /* Store environment for reentrant calls */ + func_call_cast.safe->node_impl->env = env; + + /* Call to the implementation function */ + node_loader_impl_func_call_safe(env, func_call_cast.safe); + + /* Clear environment */ + // func_call_cast.safe->node_impl->env = NULL; + + /* Signal function call condition */ + uv_cond_signal(&func_call_cast.safe->node_impl->cond); + + uv_mutex_unlock(&func_call_cast.safe->node_impl->mutex); + + return nullptr; +} + +void node_loader_impl_object_method_invoke_safe(napi_env env, loader_impl_async_object_method_invoke_safe object_method_invoke_safe) +{ + napi_value obj_value; + napi_value result; + napi_status status; + + status = napi_get_reference_value(env, object_method_invoke_safe->node_obj->obj_ref, &obj_value); + node_loader_impl_exception(env, status); + + const char *m_name = method_name(object_method_invoke_safe->m); + + napi_value m_value = NULL; + status = napi_get_named_property(env, obj_value, m_name, &m_value); + node_loader_impl_exception(env, status); + + napi_value *m_args = new napi_value[object_method_invoke_safe->argc]; + + for (size_t i = 0; i < object_method_invoke_safe->argc; i++) + { + m_args[i] = node_loader_impl_value_to_napi(object_method_invoke_safe->node_impl, env, object_method_invoke_safe->args[i]); + } + + napi_call_function(env, obj_value, m_value, object_method_invoke_safe->argc, m_args, &result); + + value v = node_loader_impl_napi_to_value(object_method_invoke_safe->node_impl, env, nullptr, result); + + delete[] m_args; + + object_method_invoke_safe->ret_v = v; +} + +napi_value node_loader_impl_async_object_method_invoke_safe(napi_env env, napi_callback_info info) +{ + loader_impl_async_safe_cast object_method_invoke_cast = { NULL }; + napi_status status; + + status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &object_method_invoke_cast.ptr); + + node_loader_impl_exception(env, status); + + /* Lock the call safe mutex and get the parameters */ + uv_mutex_lock(&object_method_invoke_cast.safe->node_impl->mutex); + + /* Store environment for reentrant calls */ + object_method_invoke_cast.safe->node_impl->env = env; + + /* Call to the implementation function */ + node_loader_impl_object_method_invoke_safe(env, object_method_invoke_cast.safe); + + /* Signal function call condition */ + uv_cond_signal(&object_method_invoke_cast.safe->node_impl->cond); + + uv_mutex_unlock(&object_method_invoke_cast.safe->node_impl->mutex); + + return nullptr; +} + +void node_loader_impl_object_get_safe(napi_env env, loader_impl_async_object_get_safe object_get_safe) +{ + napi_value obj_value = NULL; + napi_status status; + + status = napi_get_reference_value(env, object_get_safe->node_obj->obj_ref, &obj_value); + node_loader_impl_exception(env, status); + + attribute attr = object_get_safe->accessor->data.attr; + const char *key = (const char *)attribute_name(attr); + //type fieldType = (type)attribute_type(attr); + + napi_value prop_value = NULL; + status = napi_get_named_property(env, obj_value, key, &prop_value); + node_loader_impl_exception(env, status); + + value v = node_loader_impl_napi_to_value(object_get_safe->node_impl, env, nullptr, prop_value); + + object_get_safe->ret_v = v; +} + +napi_value node_loader_impl_async_object_get_safe(napi_env env, napi_callback_info info) +{ + loader_impl_async_safe_cast object_get_cast = { NULL }; + napi_status status; + + status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &object_get_cast.ptr); + + node_loader_impl_exception(env, status); + + /* Lock the call safe mutex and get the parameters */ + uv_mutex_lock(&object_get_cast.safe->node_impl->mutex); + + /* Store environment for reentrant calls */ + object_get_cast.safe->node_impl->env = env; + + /* Call to the implementation function */ + node_loader_impl_object_get_safe(env, object_get_cast.safe); + + /* Signal function call condition */ + uv_cond_signal(&object_get_cast.safe->node_impl->cond); + + uv_mutex_unlock(&object_get_cast.safe->node_impl->mutex); + + return nullptr; +} + +void node_loader_impl_object_set_safe(napi_env env, loader_impl_async_object_set_safe object_set_safe) +{ + napi_value obj_value = NULL; + napi_status status; + + status = napi_get_reference_value(env, object_set_safe->node_obj->obj_ref, &obj_value); + node_loader_impl_exception(env, status); + + attribute attr = object_set_safe->accessor->data.attr; + const char *key = (const char *)attribute_name(attr); + //type fieldType = (type)attribute_type(attr); + + napi_value prop_value = node_loader_impl_value_to_napi(object_set_safe->node_impl, env, object_set_safe->v); + + status = napi_set_named_property(env, obj_value, key, prop_value); + + node_loader_impl_exception(env, status); +} + +napi_value node_loader_impl_async_object_set_safe(napi_env env, napi_callback_info info) +{ + loader_impl_async_safe_cast object_set_cast = { NULL }; + napi_status status; + + status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &object_set_cast.ptr); + + node_loader_impl_exception(env, status); + + /* Lock the call safe mutex and get the parameters */ + uv_mutex_lock(&object_set_cast.safe->node_impl->mutex); + + /* Store environment for reentrant calls */ + object_set_cast.safe->node_impl->env = env; + + /* Call to the implementation function */ + node_loader_impl_object_set_safe(env, object_set_cast.safe); + + /* Signal function call condition */ + uv_cond_signal(&object_set_cast.safe->node_impl->cond); + + uv_mutex_unlock(&object_set_cast.safe->node_impl->mutex); + + return nullptr; +} + +void node_loader_impl_object_destroy_safe(napi_env env, loader_impl_async_object_destroy_safe object_destroy_safe) +{ + uint32_t ref_count = 0; + napi_handle_scope handle_scope; + + /* Create scope */ + napi_status status = napi_open_handle_scope(env, &handle_scope); + + node_loader_impl_exception(env, status); + + /* Clear class persistent reference */ + status = napi_reference_unref(env, object_destroy_safe->node_obj->obj_ref, &ref_count); + + node_loader_impl_exception(env, status); + + if (ref_count != 0) + { + /* TODO: Error handling */ + } + + status = napi_delete_reference(env, object_destroy_safe->node_obj->obj_ref); + + node_loader_impl_exception(env, status); + + /* Close scope */ + status = napi_close_handle_scope(env, handle_scope); + + node_loader_impl_exception(env, status); +} + +napi_value node_loader_impl_async_object_destroy_safe(napi_env env, napi_callback_info info) +{ + loader_impl_async_safe_cast object_destroy_safe_cast = { NULL }; + + napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &object_destroy_safe_cast.ptr); + + node_loader_impl_exception(env, status); + + /* Lock node implementation mutex */ + uv_mutex_lock(&object_destroy_safe_cast.safe->node_impl->mutex); + + /* Store environment for reentrant calls */ + object_destroy_safe_cast.safe->node_impl->env = env; + + /* Call to the implementation function */ + node_loader_impl_object_destroy_safe(env, object_destroy_safe_cast.safe); + + /* Signal function destroy condition */ + uv_cond_signal(&object_destroy_safe_cast.safe->node_impl->cond); + + uv_mutex_unlock(&object_destroy_safe_cast.safe->node_impl->mutex); + + return nullptr; +} + +void node_loader_impl_class_static_invoke_safe(napi_env env, loader_impl_async_class_static_invoke_safe class_static_invoke_safe) +{ + napi_status status; + napi_handle_scope handle_scope; + + /* Create scope */ + status = napi_open_handle_scope(env, &handle_scope); + ; + napi_value klass_cons; + napi_value result; + + status = napi_get_reference_value(env, class_static_invoke_safe->node_klass->klass_ref, &klass_cons); + node_loader_impl_exception(env, status); + + const char *m_name = method_name(class_static_invoke_safe->m); + + napi_value m_value = NULL; + status = napi_get_named_property(env, klass_cons, m_name, &m_value); + node_loader_impl_exception(env, status); + + napi_value *m_args = new napi_value[class_static_invoke_safe->argc]; + + for (size_t i = 0; i < class_static_invoke_safe->argc; i++) + { + m_args[i] = node_loader_impl_value_to_napi(class_static_invoke_safe->node_impl, env, class_static_invoke_safe->args[i]); + } + + //Not sure if we need to pass a recv value since this is a static method + status = napi_call_function(env, klass_cons, m_value, class_static_invoke_safe->argc, m_args, &result); + node_loader_impl_exception(env, status); - status = napi_call_function(env, global, function_trampoline_initialize, 1, argv, &return_value); + value v = node_loader_impl_napi_to_value(class_static_invoke_safe->node_impl, env, nullptr, result); - node_loader_impl_exception(env, status); - } + delete[] m_args; /* Close scope */ status = napi_close_handle_scope(env, handle_scope); node_loader_impl_exception(env, status); + + class_static_invoke_safe->ret_v = v; } -napi_value node_loader_impl_async_initialize_safe(napi_env env, napi_callback_info info) +napi_value node_loader_impl_async_class_static_invoke_safe(napi_env env, napi_callback_info info) { - loader_impl_async_safe_cast initialize_cast = { NULL }; + loader_impl_async_safe_cast class_static_invoke_cast = { NULL }; + napi_status status; - napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &initialize_cast.ptr); + status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &class_static_invoke_cast.ptr); node_loader_impl_exception(env, status); - /* Lock node implementation mutex */ - uv_mutex_lock(&initialize_cast.safe->node_impl->mutex); + /* Lock the call safe mutex and get the parameters */ + uv_mutex_lock(&class_static_invoke_cast.safe->node_impl->mutex); /* Store environment for reentrant calls */ - initialize_cast.safe->node_impl->env = env; + class_static_invoke_cast.safe->node_impl->env = env; /* Call to the implementation function */ - node_loader_impl_initialize_safe(env, initialize_cast.safe); - - /* Clear environment */ - // initialize_cast.safe->node_impl->env = NULL; + node_loader_impl_class_static_invoke_safe(env, class_static_invoke_cast.safe); - /* Signal start condition */ - uv_cond_signal(&initialize_cast.safe->node_impl->cond); + /* Signal function call condition */ + uv_cond_signal(&class_static_invoke_cast.safe->node_impl->cond); - uv_mutex_unlock(&initialize_cast.safe->node_impl->mutex); + uv_mutex_unlock(&class_static_invoke_cast.safe->node_impl->mutex); return nullptr; } -void node_loader_impl_execution_path_safe(napi_env env, loader_impl_async_execution_path_safe execution_path_safe) +void node_loader_impl_class_ctor_safe(napi_env env, loader_impl_async_class_ctor_safe class_ctor_safe) { - static const char execution_path_str[] = "execution_path"; - napi_value function_table_object; - napi_value execution_path_str_value; - bool result = false; napi_handle_scope handle_scope; - loader_impl_node node_impl = execution_path_safe->node_impl; /* Create scope */ napi_status status = napi_open_handle_scope(env, &handle_scope); node_loader_impl_exception(env, status); - /* Get function table object from reference */ - status = napi_get_reference_value(env, node_impl->function_table_object_ref, &function_table_object); - - node_loader_impl_exception(env, status); - - /* Create function string */ - status = napi_create_string_utf8(env, execution_path_str, sizeof(execution_path_str) - 1, &execution_path_str_value); - - node_loader_impl_exception(env, status); - - /* Check if exists in the table */ - status = napi_has_own_property(env, function_table_object, execution_path_str_value, &result); + loader_impl_node_object node_obj = new struct loader_impl_node_object_type; - node_loader_impl_exception(env, status); + object obj = object_create(class_ctor_safe->name, ACCESSOR_TYPE_DYNAMIC, node_obj, &node_object_interface_singleton, class_ctor_safe->cls); - if (result == true) + if (obj == NULL) { - napi_value function_trampoline_execution_path; - napi_valuetype valuetype; - napi_value argv[1]; - - status = napi_get_named_property(env, function_table_object, execution_path_str, &function_trampoline_execution_path); - - node_loader_impl_exception(env, status); - - status = napi_typeof(env, function_trampoline_execution_path, &valuetype); - - node_loader_impl_exception(env, status); + class_ctor_safe->ret_obj = NULL; + return; + } - if (valuetype != napi_function) - { - napi_throw_type_error(env, nullptr, "Invalid function execution_path in function table object"); - } + /* Get loader implementation from class */ + node_obj->node_impl = class_ctor_safe->node_impl; + //node_obj->impl = node_klass->impl; - /* Create parameters */ - status = napi_create_string_utf8(env, execution_path_safe->path, strlen(execution_path_safe->path), &argv[0]); + napi_value *m_args = new napi_value[class_ctor_safe->argc]; - node_loader_impl_exception(env, status); + for (size_t i = 0; i < class_ctor_safe->argc; i++) + { + m_args[i] = node_loader_impl_value_to_napi(class_ctor_safe->node_impl, env, class_ctor_safe->args[i]); + } - /* Call to load from file function */ - napi_value global, return_value; + napi_value klass_cons; + status = napi_get_reference_value(env, class_ctor_safe->node_klass->klass_ref, &klass_cons); + node_loader_impl_exception(env, status); - status = napi_get_reference_value(env, node_impl->global_ref, &global); + napi_value result; + status = napi_new_instance(env, klass_cons, class_ctor_safe->argc, m_args, &result); + node_loader_impl_exception(env, status); - node_loader_impl_exception(env, status); + //Todo check that object is an instance of constructor - status = napi_call_function(env, global, function_trampoline_execution_path, 1, argv, &return_value); + status = napi_create_reference(env, result, 1, &node_obj->obj_ref); + node_loader_impl_exception(env, status); - node_loader_impl_exception(env, status); - } + delete[] m_args; /* Close scope */ status = napi_close_handle_scope(env, handle_scope); node_loader_impl_exception(env, status); + + class_ctor_safe->ret_obj = obj; } -napi_value node_loader_impl_async_execution_path_safe(napi_env env, napi_callback_info info) +napi_value node_loader_impl_async_class_ctor_safe(napi_env env, napi_callback_info info) { - loader_impl_async_safe_cast execution_path_cast = { NULL }; + loader_impl_async_safe_cast class_ctor_safe_cast = { NULL }; + napi_status status; - napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &execution_path_cast.ptr); + status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &class_ctor_safe_cast.ptr); node_loader_impl_exception(env, status); - /* Lock node implementation mutex */ - uv_mutex_lock(&execution_path_cast.safe->node_impl->mutex); + /* Lock the call safe mutex and get the parameters */ + uv_mutex_lock(&class_ctor_safe_cast.safe->node_impl->mutex); /* Store environment for reentrant calls */ - execution_path_cast.safe->node_impl->env = env; + class_ctor_safe_cast.safe->node_impl->env = env; + printf("calling class_ctor_safe async"); /* Call to the implementation function */ - node_loader_impl_execution_path_safe(env, execution_path_cast.safe); + node_loader_impl_class_ctor_safe(env, class_ctor_safe_cast.safe); - /* Clear environment */ - // execution_path_cast.safe->node_impl->env = NULL; - - /* Signal start condition */ - uv_cond_signal(&execution_path_cast.safe->node_impl->cond); + /* Signal function call condition */ + uv_cond_signal(&class_ctor_safe_cast.safe->node_impl->cond); - uv_mutex_unlock(&execution_path_cast.safe->node_impl->mutex); + uv_mutex_unlock(&class_ctor_safe_cast.safe->node_impl->mutex); return nullptr; } -void node_loader_impl_func_call_safe(napi_env env, loader_impl_async_func_call_safe func_call_safe) +void node_loader_impl_class_destroy_safe(napi_env env, loader_impl_async_class_destroy_safe class_destroy_safe) { + uint32_t ref_count = 0; napi_handle_scope handle_scope; - size_t args_size; - value *args; - napi_value *argv; - loader_impl_node_function node_func; - size_t args_count; - signature s = function_signature(func_call_safe->func); - const size_t signature_args_size = signature_count(s); - - /* Get function data */ - args_size = func_call_safe->size; - node_func = func_call_safe->node_func; - args = func_call_safe->args; - - /* Allocate dynamically more space for values in case of variable arguments */ - argv = args_size > signature_args_size ? static_cast(malloc(sizeof(napi_value) * args_size)) : node_func->argv; /* Create scope */ napi_status status = napi_open_handle_scope(env, &handle_scope); node_loader_impl_exception(env, status); - /* Build parameters */ - for (args_count = 0; args_count < args_size; ++args_count) - { - /* Define parameter */ - argv[args_count] = node_loader_impl_value_to_napi(func_call_safe->node_impl, env, args[args_count]); - } - - /* Get function reference */ - napi_value function_ptr; - - status = napi_get_reference_value(env, node_func->func_ref, &function_ptr); + /* Clear class persistent reference */ + status = napi_reference_unref(env, class_destroy_safe->node_klass->klass_ref, &ref_count); node_loader_impl_exception(env, status); - /* Get global */ - napi_value global; + if (ref_count != 0) + { + /* TODO: Error handling */ + } - status = napi_get_reference_value(env, func_call_safe->node_impl->global_ref, &global); + status = napi_delete_reference(env, class_destroy_safe->node_klass->klass_ref); node_loader_impl_exception(env, status); - /* Call to function */ - napi_value func_return; - - status = napi_call_function(env, global, function_ptr, args_size, argv, &func_return); - - func_call_safe->ret = node_loader_impl_exception_value(func_call_safe->node_impl, env, status, func_call_safe->recv); - - if (func_call_safe->ret == NULL) - { - /* Convert function return to value */ - func_call_safe->ret = node_loader_impl_napi_to_value(func_call_safe->node_impl, env, func_call_safe->recv, func_return); - } - /* Close scope */ status = napi_close_handle_scope(env, handle_scope); node_loader_impl_exception(env, status); - - if (args_size > signature_args_size) - { - free(argv); - } } -napi_value node_loader_impl_async_func_call_safe(napi_env env, napi_callback_info info) +napi_value node_loader_impl_async_class_destroy_safe(napi_env env, napi_callback_info info) { - loader_impl_async_safe_cast func_call_cast = { NULL }; - napi_status status; - napi_value recv; + loader_impl_async_safe_cast class_destroy_safe_cast = { NULL }; - status = napi_get_cb_info(env, info, nullptr, nullptr, &recv, &func_call_cast.ptr); + napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &class_destroy_safe_cast.ptr); node_loader_impl_exception(env, status); - /* Lock the call safe mutex and get the parameters */ - uv_mutex_lock(&func_call_cast.safe->node_impl->mutex); - - /* Store function recv for reentrant calls */ - func_call_cast.safe->recv = recv; + /* Lock node implementation mutex */ + uv_mutex_lock(&class_destroy_safe_cast.safe->node_impl->mutex); /* Store environment for reentrant calls */ - func_call_cast.safe->node_impl->env = env; + class_destroy_safe_cast.safe->node_impl->env = env; /* Call to the implementation function */ - node_loader_impl_func_call_safe(env, func_call_cast.safe); - - /* Clear environment */ - // func_call_cast.safe->node_impl->env = NULL; + node_loader_impl_class_destroy_safe(env, class_destroy_safe_cast.safe); - /* Signal function call condition */ - uv_cond_signal(&func_call_cast.safe->node_impl->cond); + /* Signal function destroy condition */ + uv_cond_signal(&class_destroy_safe_cast.safe->node_impl->cond); - uv_mutex_unlock(&func_call_cast.safe->node_impl->mutex); + uv_mutex_unlock(&class_destroy_safe_cast.safe->node_impl->mutex); return nullptr; } @@ -4459,9 +5367,18 @@ value node_loader_impl_discover_klass_safe(napi_env env, loader_impl_discover_kl } } } + /* Close scope */ + status = napi_close_handle_scope(env, handle_scope); + + node_loader_impl_exception(env, status); return value_create_class(c); } + /* Close scope */ + status = napi_close_handle_scope(env, handle_scope); + + node_loader_impl_exception(env, status); + return NULL; } @@ -5134,6 +6051,97 @@ void *node_loader_impl_register(void *node_impl_ptr, void *env_ptr, void *functi &node_impl->threadsafe_future_delete); } + /* Safe object get */ + { + static const char threadsafe_func_name_str[] = "node_loader_impl_async_object_get_safe"; + + node_loader_impl_thread_safe_function_initialize( + env, + threadsafe_func_name_str, sizeof(threadsafe_func_name_str), + &node_loader_impl_async_object_get_safe, + (loader_impl_async_object_get_safe_type **)(&node_impl->object_get_safe), + &node_impl->object_get_safe_ptr, + &node_impl->threadsafe_object_get); + } + + /* Safe object set */ + { + static const char threadsafe_func_name_str[] = "node_loader_impl_async_object_set_safe"; + + node_loader_impl_thread_safe_function_initialize( + env, + threadsafe_func_name_str, sizeof(threadsafe_func_name_str), + &node_loader_impl_async_object_set_safe, + (loader_impl_async_object_set_safe_type **)(&node_impl->object_set_safe), + &node_impl->object_set_safe_ptr, + &node_impl->threadsafe_object_set); + } + + /* Safe object method invoke */ + { + static const char threadsafe_func_name_str[] = "node_loader_impl_async_object_method_invoke_safe"; + + node_loader_impl_thread_safe_function_initialize( + env, + threadsafe_func_name_str, sizeof(threadsafe_func_name_str), + &node_loader_impl_async_object_method_invoke_safe, + (loader_impl_async_object_method_invoke_safe_type **)(&node_impl->object_method_invoke_safe), + &node_impl->object_method_invoke_safe_ptr, + &node_impl->threadsafe_object_method_invoke); + } + + /* Safe object destroy */ + { + static const char threadsafe_func_name_str[] = "node_loader_impl_async_object_destroy_safe"; + + node_loader_impl_thread_safe_function_initialize( + env, + threadsafe_func_name_str, sizeof(threadsafe_func_name_str), + &node_loader_impl_async_object_destroy_safe, + (loader_impl_async_object_destroy_safe_type **)(&node_impl->object_destroy_safe), + &node_impl->object_destroy_safe_ptr, + &node_impl->threadsafe_object_destroy); + } + + /* Safe class constructor */ + { + static const char threadsafe_func_name_str[] = "node_loader_impl_async_class_ctor_safe"; + + node_loader_impl_thread_safe_function_initialize( + env, + threadsafe_func_name_str, sizeof(threadsafe_func_name_str), + &node_loader_impl_async_class_ctor_safe, + (loader_impl_async_class_ctor_safe_type **)(&node_impl->class_ctor_safe), + &node_impl->class_ctor_safe_ptr, + &node_impl->threadsafe_class_ctor); + } + + /* Safe class static invoke */ + { + static const char threadsafe_func_name_str[] = "node_loader_impl_async_class_static_invoke_safe"; + + node_loader_impl_thread_safe_function_initialize( + env, + threadsafe_func_name_str, sizeof(threadsafe_func_name_str), + &node_loader_impl_async_class_static_invoke_safe, + (loader_impl_async_class_static_invoke_safe_type **)(&node_impl->class_static_invoke_safe), + &node_impl->class_static_invoke_safe_ptr, + &node_impl->threadsafe_class_static_invoke); + } + + /* Safe class destroy */ + { + static const char threadsafe_func_name_str[] = "node_loader_impl_async_class_destroy_safe"; + + node_loader_impl_thread_safe_function_initialize( + env, + threadsafe_func_name_str, sizeof(threadsafe_func_name_str), + &node_loader_impl_async_class_destroy_safe, + (loader_impl_async_class_destroy_safe_type **)(&node_impl->class_destroy_safe), + &node_impl->class_destroy_safe_ptr, + &node_impl->threadsafe_class_destroy); + } + /* Safe destroy */ { static const char threadsafe_func_name_str[] = "node_loader_impl_async_destroy_safe"; @@ -6357,6 +7365,55 @@ void node_loader_impl_destroy_safe_impl(loader_impl_node node_impl, napi_env env node_loader_impl_exception(env, status); } + /* Safe object get */ + { + status = napi_release_threadsafe_function(node_impl->threadsafe_object_get, napi_tsfn_abort); + + node_loader_impl_exception(env, status); + } + + /* Safe object set */ + { + status = napi_release_threadsafe_function(node_impl->threadsafe_object_set, napi_tsfn_abort); + + node_loader_impl_exception(env, status); + } + + /* Safe object method invoke */ + { + status = napi_release_threadsafe_function(node_impl->threadsafe_object_method_invoke, napi_tsfn_abort); + + node_loader_impl_exception(env, status); + } + + /* Safe object destroy */ + { + status = napi_release_threadsafe_function(node_impl->threadsafe_object_destroy, napi_tsfn_abort); + + node_loader_impl_exception(env, status); + } + + /* Safe class constructor */ + { + status = napi_release_threadsafe_function(node_impl->threadsafe_class_ctor, napi_tsfn_abort); + + node_loader_impl_exception(env, status); + } + + /* Safe class static invoke */ + { + status = napi_release_threadsafe_function(node_impl->threadsafe_class_static_invoke, napi_tsfn_abort); + + node_loader_impl_exception(env, status); + } + + /* Safe class destroy */ + { + status = napi_release_threadsafe_function(node_impl->threadsafe_class_destroy, napi_tsfn_abort); + + node_loader_impl_exception(env, status); + } + /* Safe destroy */ { status = napi_release_threadsafe_function(node_impl->threadsafe_destroy, napi_tsfn_abort); @@ -6533,6 +7590,13 @@ int node_loader_impl_destroy(loader_impl impl) delete node_impl->future_await_safe; delete node_impl->future_delete_safe; delete node_impl->destroy_safe; + delete node_impl->object_get_safe; + delete node_impl->object_set_safe; + delete node_impl->object_method_invoke_safe; + delete node_impl->object_destroy_safe; + delete node_impl->class_ctor_safe; + delete node_impl->class_static_invoke_safe; + delete node_impl->class_destroy_safe; #ifdef __ANDROID__ /* Close file descriptors */ diff --git a/source/reflect/include/reflect/reflect_class.h b/source/reflect/include/reflect/reflect_class.h index ad9967f6c2..8bc64b6bef 100644 --- a/source/reflect/include/reflect/reflect_class.h +++ b/source/reflect/include/reflect/reflect_class.h @@ -99,17 +99,17 @@ REFLECT_API method class_static_method(klass cls, const char *key, type_id ret, REFLECT_API method class_method(klass cls, const char *key, type_id ret, type_id args[], size_t size); -REFLECT_API vector class_method_names(klass cls); +REFLECT_API vector class_get_methods(klass cls); -REFLECT_API vector class_static_method_names(klass cls); +REFLECT_API vector class_get_static_methods(klass cls); REFLECT_API attribute class_static_attribute(klass cls, const char *key); REFLECT_API attribute class_attribute(klass cls, const char *key); -REFLECT_API vector class_attribute_names(klass cls); +REFLECT_API vector class_get_attributes(klass cls); -REFLECT_API vector class_static_attribute_names(klass cls); +REFLECT_API vector class_get_static_attributes(klass cls); REFLECT_API int class_register_constructor(klass cls, constructor ctor); diff --git a/source/reflect/source/reflect_class.c b/source/reflect/source/reflect_class.c index 5242e27fee..e85d32d0fb 100644 --- a/source/reflect/source/reflect_class.c +++ b/source/reflect/source/reflect_class.c @@ -588,7 +588,7 @@ constructor class_default_constructor(klass cls) return NULL; } - return (constructor)vector_at(cls->constructors, 0); + return vector_at_type(cls->constructors, 0, constructor); } constructor class_constructor(klass cls, type_id args[], size_t size) @@ -680,28 +680,14 @@ method class_method(klass cls, const char *key, type_id ret, type_id args[], siz return class_get_method_type_safe(class_methods(cls, key), ret, args, size); } -vector class_method_names(klass cls) +vector class_get_methods(klass cls) { - vector v = vector_create_type(char *); - map_iterator it = map_iterator_begin(cls->methods); - while (map_iterator_end(&it) != 0) - { - char *key = (char *)map_iterator_get_key(it); - vector_push_back(v, (void *)key); - } - return v; + return map_get_values(cls->methods); } -vector class_static_method_names(klass cls) +vector class_get_static_methods(klass cls) { - vector v = vector_create_type(char *); - map_iterator it = map_iterator_begin(cls->static_methods); - while (map_iterator_end(&it) != 0) - { - char *key = (char *)map_iterator_get_key(it); - vector_push_back(v, (void *)key); - } - return v; + return map_get_values(cls->static_methods); } attribute class_static_attribute(klass cls, const char *key) @@ -724,28 +710,14 @@ attribute class_attribute(klass cls, const char *key) return set_get(cls->attributes, (set_key)key); } -vector class_attribute_names(klass cls) +vector class_get_attributes(klass cls) { - vector v = vector_create_type(char *); - set_iterator it = set_iterator_begin(cls->attributes); - while (set_iterator_end(&it) != 0) - { - char *key = (char *)set_iterator_get_key(it); - vector_push_back(v, (void *)key); - } - return v; + return set_get_values(cls->attributes); } -vector class_static_attribute_names(klass cls) +vector class_get_static_attributes(klass cls) { - vector v = vector_create_type(char *); - set_iterator it = set_iterator_begin(cls->static_attributes); - while (set_iterator_end(&it) != 0) - { - char *key = (char *)set_iterator_get_key(it); - vector_push_back(v, (void *)key); - } - return v; + return set_get_values(cls->static_attributes); } int class_register_constructor(klass cls, constructor ctor) diff --git a/source/scripts/node/CMakeLists.txt b/source/scripts/node/CMakeLists.txt index e876f52219..0bc35e1533 100644 --- a/source/scripts/node/CMakeLists.txt +++ b/source/scripts/node/CMakeLists.txt @@ -23,3 +23,4 @@ add_subdirectory(derpyramda) add_subdirectory(gram) add_subdirectory(duplicated) add_subdirectory(ramda) +add_subdirectory(node_test) diff --git a/source/scripts/node/node_test/CMakeLists.txt b/source/scripts/node/node_test/CMakeLists.txt new file mode 100644 index 0000000000..f8e60b6039 --- /dev/null +++ b/source/scripts/node/node_test/CMakeLists.txt @@ -0,0 +1,5 @@ +# +# Configure nodejs project +# + +nodejs_project(node_test 0.1.0) diff --git a/source/scripts/node/node_test/source/node_test.js b/source/scripts/node/node_test/source/node_test.js new file mode 100644 index 0000000000..a4e88a7ef9 --- /dev/null +++ b/source/scripts/node/node_test/source/node_test.js @@ -0,0 +1,77 @@ +class Fibonacci { + fib_impl(n) { + if (n <= 2) { + return 1; + } else { + return fib_impl(n - 2) + fib_impl(n - 1); + } + } + + static fib(n) { + console.log("Fibbonaci of " + n + " = " + fib_impl(n)); + } +} + +class Test { + + constructor (num, str, cls, cls_args) { + this.int = 231; + this.b = 100; + this.hello_str = "hello!"; + + this.arr = [ 'K', 'G', 50, 100, "Hello", "world"]; + this.num = num; + this.str = str; + this.cls = Fibonacci; + + this.obj = new cls(...cls_args); + + // TODO: This works, But we should add tests for it + const objWithoutNew = cls(...cls_args); + // END-TODO + + console.log("NodeJs Loader: Test constructor Called!"); + } + + newFibonacci() { + return new Fibonacci; + } + + return_class() { + return Fibonacci; + } + + print() { + console.log(this.str); + } + + test_value_to_napi_class_get(property) { + return this.obj[property] + } + + test_value_to_napi_class_set(property, value) { + this.obj[property] = value + } + + test_value_to_napi_class_method_invoke(method_name, args) { + return this.obj[method_name](...args) + } + + // Static method with no parameter and void return type + static hello(s) { + console.log("hello, world! from " + s); + return 10; + } + + static sumArray(i) { + let sum = 0; + + for (let c of i) + sum += c; + + return sum; + } + +} + +module.exports = Test \ No newline at end of file diff --git a/source/tests/metacall-node-class-test/source/metacall_node_class_test.cpp b/source/tests/metacall-node-class-test/source/metacall_node_class_test.cpp index 2dc81cc7a6..91f5703f8d 100644 --- a/source/tests/metacall-node-class-test/source/metacall_node_class_test.cpp +++ b/source/tests/metacall-node-class-test/source/metacall_node_class_test.cpp @@ -52,7 +52,7 @@ TEST_F(metacall_node_class_test, DefaultConstructor) void *new_object_v = NULL; { /* TEST LOAD FROM FILE */ const char *node_scripts[] = { - "scripts/test.js" + "scripts/node_test.js" }; static const char tag[] = "node"; @@ -84,12 +84,10 @@ TEST_F(metacall_node_class_test, DefaultConstructor) new_object_v = metacall_class_new(myclass, "test", constructor_params, sizeof(constructor_params) / sizeof(constructor_params[0])); ASSERT_NE((void *)NULL, (void *)new_object_v); - metacall_value_destroy(new_object_v); - { //Invoke static method { - void *args[] = { + const void *args[] = { metacall_value_create_int(1), metacall_value_create_int(2), metacall_value_create_int(3), @@ -102,8 +100,10 @@ TEST_F(metacall_node_class_test, DefaultConstructor) metacall_value_create_int(10) }; - void *ret = metacallt_class(myclass, "hello", METACALL_INT, args, sizeof(args) / sizeof(args[0])); - ASSERT_EQ((long)55, (long)metacall_value_to_long(ret)); + void *argv = metacall_value_create_array(args, sizeof(args) / sizeof(args[0])); + + void *ret = metacallv_class(myclass, "sumArray", &argv, 1); + ASSERT_EQ((double)55, (double)metacall_value_to_double(ret)); metacall_value_destroy(ret); } @@ -113,8 +113,8 @@ TEST_F(metacall_node_class_test, DefaultConstructor) metacall_value_create_string("Metacall", 8) }; - void *ret = metacallt_class(myclass, "sumArray", METACALL_INT, args, 1); - ASSERT_EQ((long)10, (long)metacall_value_to_long(ret)); + void *ret = metacallv_class(myclass, "hello", args, 1); + ASSERT_EQ((double)10, (double)metacall_value_to_double(ret)); metacall_value_destroy(ret); } @@ -127,7 +127,8 @@ TEST_F(metacall_node_class_test, DefaultConstructor) { void *param1 = metacall_object_get(new_object, "num"); - ASSERT_EQ((long)10, (long)metacall_value_to_long(param1)); + ASSERT_EQ((double)10, (double)metacall_value_to_double(param1)); + metacall_value_destroy(param1); } @@ -144,8 +145,8 @@ TEST_F(metacall_node_class_test, DefaultConstructor) ASSERT_EQ((int)0, int(retcode)); void *param2 = metacall_object_get(new_object, "b"); - ASSERT_EQ((enum metacall_value_id)METACALL_LONG, (enum metacall_value_id)metacall_value_id(param2)); - ASSERT_EQ((long)124124L, (long)metacall_value_to_long(param2)); + ASSERT_EQ((enum metacall_value_id)METACALL_DOUBLE, (enum metacall_value_id)metacall_value_id(param2)); + ASSERT_EQ((double)124124, (double)metacall_value_to_double(param2)); metacall_value_destroy(param2); } @@ -165,10 +166,47 @@ TEST_F(metacall_node_class_test, DefaultConstructor) metacall_value_destroy(Fibonacci); } + //Value to napi class test { - void *param1 = metacallv_object(new_object, "return_bye", metacall_null_args, 0); - ASSERT_EQ((std::string) "bye LBryan", (std::string)metacall_value_to_string(param1)); - metacall_value_destroy(param1); + { + void *args = metacall_value_create_string("b", 1); + void *param1 = metacallv_object(new_object, "test_value_to_napi_class_get", &args, 1); + ASSERT_EQ((double)999999, (double)metacall_value_to_double(param1)); + metacall_value_destroy(param1); + } + + { + char str[] = "test value class to napi."; + void *args[] = { + metacall_value_create_string("a", 1), + metacall_value_create_string(str, sizeof(str)) + }; + + void *param1 = metacallv_object(new_object, "test_value_to_napi_class_set", args, sizeof(args) / sizeof(args[0])); + ASSERT_NE((void *)NULL, (void *)param1); + metacall_value_destroy(param1); + + void *arg = metacall_value_create_string("a", 1); + void *param2 = metacallv_object(new_object, "test_value_to_napi_class_get", &arg, 1); + ASSERT_EQ((std::string) str, (std::string)metacall_value_to_string(param2)); + metacall_value_destroy(param2); + } + + { + const void *method_args[] = { + metacall_value_create_int(4), + metacall_value_create_int(7) + }; + + void *args[] = { + metacall_value_create_string("check_args", 10), + metacall_value_create_array(method_args, 2) + }; + + void *param1 = metacallv_object(new_object, "test_value_to_napi_class_method_invoke", args, sizeof(args) / sizeof(args[0])); + ASSERT_EQ((double)15, (double)metacall_value_to_double(param1)); + metacall_value_destroy(param1); + } } metacall_value_destroy(new_object_v);