11cb0ef41Sopenharmony_ci#include <js_native_api.h> 21cb0ef41Sopenharmony_ci#include <stdint.h> 31cb0ef41Sopenharmony_ci#include <stdio.h> 41cb0ef41Sopenharmony_ci#include <stdlib.h> 51cb0ef41Sopenharmony_ci#include <string.h> 61cb0ef41Sopenharmony_ci#include "../common.h" 71cb0ef41Sopenharmony_ci#include "../entry_point.h" 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_citypedef struct { 101cb0ef41Sopenharmony_ci int32_t finalize_count; 111cb0ef41Sopenharmony_ci napi_ref js_func; 121cb0ef41Sopenharmony_ci} FinalizerData; 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cistatic void finalizerOnlyCallback(node_api_nogc_env env, 151cb0ef41Sopenharmony_ci void* finalize_data, 161cb0ef41Sopenharmony_ci void* finalize_hint) { 171cb0ef41Sopenharmony_ci FinalizerData* data = (FinalizerData*)finalize_data; 181cb0ef41Sopenharmony_ci int32_t count = ++data->finalize_count; 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci // It is safe to access instance data 211cb0ef41Sopenharmony_ci NODE_API_NOGC_CALL_RETURN_VOID(env, 221cb0ef41Sopenharmony_ci napi_get_instance_data(env, (void**)&data)); 231cb0ef41Sopenharmony_ci NODE_API_NOGC_ASSERT_RETURN_VOID(count = data->finalize_count, 241cb0ef41Sopenharmony_ci "Expected to be the same FinalizerData"); 251cb0ef41Sopenharmony_ci} 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_cistatic void finalizerCallingJSCallback(napi_env env, 281cb0ef41Sopenharmony_ci void* finalize_data, 291cb0ef41Sopenharmony_ci void* finalize_hint) { 301cb0ef41Sopenharmony_ci napi_value js_func, undefined; 311cb0ef41Sopenharmony_ci FinalizerData* data = (FinalizerData*)finalize_data; 321cb0ef41Sopenharmony_ci NODE_API_CALL_RETURN_VOID( 331cb0ef41Sopenharmony_ci env, napi_get_reference_value(env, data->js_func, &js_func)); 341cb0ef41Sopenharmony_ci NODE_API_CALL_RETURN_VOID(env, napi_get_undefined(env, &undefined)); 351cb0ef41Sopenharmony_ci NODE_API_CALL_RETURN_VOID( 361cb0ef41Sopenharmony_ci env, napi_call_function(env, undefined, js_func, 0, NULL, NULL)); 371cb0ef41Sopenharmony_ci NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, data->js_func)); 381cb0ef41Sopenharmony_ci data->js_func = NULL; 391cb0ef41Sopenharmony_ci ++data->finalize_count; 401cb0ef41Sopenharmony_ci} 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci// Schedule async finalizer to run JavaScript-touching code. 431cb0ef41Sopenharmony_cistatic void finalizerWithJSCallback(node_api_nogc_env env, 441cb0ef41Sopenharmony_ci void* finalize_data, 451cb0ef41Sopenharmony_ci void* finalize_hint) { 461cb0ef41Sopenharmony_ci NODE_API_NOGC_CALL_RETURN_VOID( 471cb0ef41Sopenharmony_ci env, 481cb0ef41Sopenharmony_ci node_api_post_finalizer( 491cb0ef41Sopenharmony_ci env, finalizerCallingJSCallback, finalize_data, finalize_hint)); 501cb0ef41Sopenharmony_ci} 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_cistatic void finalizerWithFailedJSCallback(node_api_nogc_env nogc_env, 531cb0ef41Sopenharmony_ci void* finalize_data, 541cb0ef41Sopenharmony_ci void* finalize_hint) { 551cb0ef41Sopenharmony_ci // Intentionally cast to a napi_env to test the fatal failure. 561cb0ef41Sopenharmony_ci napi_env env = (napi_env)nogc_env; 571cb0ef41Sopenharmony_ci napi_value obj; 581cb0ef41Sopenharmony_ci FinalizerData* data = (FinalizerData*)finalize_data; 591cb0ef41Sopenharmony_ci ++data->finalize_count; 601cb0ef41Sopenharmony_ci NODE_API_CALL_RETURN_VOID(env, napi_create_object(env, &obj)); 611cb0ef41Sopenharmony_ci} 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_cistatic napi_value addFinalizer(napi_env env, napi_callback_info info) { 641cb0ef41Sopenharmony_ci size_t argc = 1; 651cb0ef41Sopenharmony_ci napi_value argv[1] = {0}; 661cb0ef41Sopenharmony_ci FinalizerData* data; 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); 691cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data)); 701cb0ef41Sopenharmony_ci NODE_API_CALL(env, 711cb0ef41Sopenharmony_ci napi_add_finalizer( 721cb0ef41Sopenharmony_ci env, argv[0], data, finalizerOnlyCallback, NULL, NULL)); 731cb0ef41Sopenharmony_ci return NULL; 741cb0ef41Sopenharmony_ci} 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci// This finalizer is going to call JavaScript from finalizer and succeed. 771cb0ef41Sopenharmony_cistatic napi_value addFinalizerWithJS(napi_env env, napi_callback_info info) { 781cb0ef41Sopenharmony_ci size_t argc = 2; 791cb0ef41Sopenharmony_ci napi_value argv[2] = {0}; 801cb0ef41Sopenharmony_ci napi_valuetype arg_type; 811cb0ef41Sopenharmony_ci FinalizerData* data; 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); 841cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data)); 851cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_typeof(env, argv[1], &arg_type)); 861cb0ef41Sopenharmony_ci NODE_API_ASSERT( 871cb0ef41Sopenharmony_ci env, arg_type == napi_function, "Expected function as the second arg"); 881cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_create_reference(env, argv[1], 1, &data->js_func)); 891cb0ef41Sopenharmony_ci NODE_API_CALL(env, 901cb0ef41Sopenharmony_ci napi_add_finalizer( 911cb0ef41Sopenharmony_ci env, argv[0], data, finalizerWithJSCallback, NULL, NULL)); 921cb0ef41Sopenharmony_ci return NULL; 931cb0ef41Sopenharmony_ci} 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci// This finalizer is going to call JavaScript from finalizer and fail. 961cb0ef41Sopenharmony_cistatic napi_value addFinalizerFailOnJS(napi_env env, napi_callback_info info) { 971cb0ef41Sopenharmony_ci size_t argc = 1; 981cb0ef41Sopenharmony_ci napi_value argv[1] = {0}; 991cb0ef41Sopenharmony_ci FinalizerData* data; 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); 1021cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data)); 1031cb0ef41Sopenharmony_ci NODE_API_CALL( 1041cb0ef41Sopenharmony_ci env, 1051cb0ef41Sopenharmony_ci napi_add_finalizer( 1061cb0ef41Sopenharmony_ci env, argv[0], data, finalizerWithFailedJSCallback, NULL, NULL)); 1071cb0ef41Sopenharmony_ci return NULL; 1081cb0ef41Sopenharmony_ci} 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_cistatic napi_value getFinalizerCallCount(napi_env env, napi_callback_info info) { 1111cb0ef41Sopenharmony_ci size_t argc = 1; 1121cb0ef41Sopenharmony_ci napi_value argv[1]; 1131cb0ef41Sopenharmony_ci FinalizerData* data; 1141cb0ef41Sopenharmony_ci napi_value result; 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); 1171cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_get_instance_data(env, (void**)&data)); 1181cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_create_int32(env, data->finalize_count, &result)); 1191cb0ef41Sopenharmony_ci return result; 1201cb0ef41Sopenharmony_ci} 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_cistatic void finalizeData(napi_env env, void* data, void* hint) { 1231cb0ef41Sopenharmony_ci free(data); 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ciEXTERN_C_START 1271cb0ef41Sopenharmony_cinapi_value Init(napi_env env, napi_value exports) { 1281cb0ef41Sopenharmony_ci FinalizerData* data = (FinalizerData*)malloc(sizeof(FinalizerData)); 1291cb0ef41Sopenharmony_ci NODE_API_ASSERT(env, data != NULL, "Failed to allocate memory"); 1301cb0ef41Sopenharmony_ci memset(data, 0, sizeof(FinalizerData)); 1311cb0ef41Sopenharmony_ci NODE_API_CALL(env, napi_set_instance_data(env, data, finalizeData, NULL)); 1321cb0ef41Sopenharmony_ci napi_property_descriptor descriptors[] = { 1331cb0ef41Sopenharmony_ci DECLARE_NODE_API_PROPERTY("addFinalizer", addFinalizer), 1341cb0ef41Sopenharmony_ci DECLARE_NODE_API_PROPERTY("addFinalizerWithJS", addFinalizerWithJS), 1351cb0ef41Sopenharmony_ci DECLARE_NODE_API_PROPERTY("addFinalizerFailOnJS", addFinalizerFailOnJS), 1361cb0ef41Sopenharmony_ci DECLARE_NODE_API_PROPERTY("getFinalizerCallCount", 1371cb0ef41Sopenharmony_ci getFinalizerCallCount)}; 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci NODE_API_CALL( 1401cb0ef41Sopenharmony_ci env, 1411cb0ef41Sopenharmony_ci napi_define_properties(env, 1421cb0ef41Sopenharmony_ci exports, 1431cb0ef41Sopenharmony_ci sizeof(descriptors) / sizeof(*descriptors), 1441cb0ef41Sopenharmony_ci descriptors)); 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci return exports; 1471cb0ef41Sopenharmony_ci} 1481cb0ef41Sopenharmony_ciEXTERN_C_END 149