11cb0ef41Sopenharmony_ci#define NAPI_VERSION 9
21cb0ef41Sopenharmony_ci#include <assert.h>
31cb0ef41Sopenharmony_ci#include <js_native_api.h>
41cb0ef41Sopenharmony_ci#include <stdlib.h>
51cb0ef41Sopenharmony_ci#include "../common.h"
61cb0ef41Sopenharmony_ci#include "../entry_point.h"
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_cistatic int test_value = 1;
91cb0ef41Sopenharmony_cistatic int finalize_count = 0;
101cb0ef41Sopenharmony_cistatic napi_ref test_reference = NULL;
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cistatic napi_value GetFinalizeCount(napi_env env, napi_callback_info info) {
131cb0ef41Sopenharmony_ci  napi_value result;
141cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_create_int32(env, finalize_count, &result));
151cb0ef41Sopenharmony_ci  return result;
161cb0ef41Sopenharmony_ci}
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cistatic void FinalizeExternal(napi_env env, void* data, void* hint) {
191cb0ef41Sopenharmony_ci  int *actual_value = data;
201cb0ef41Sopenharmony_ci  NODE_API_ASSERT_RETURN_VOID(env, actual_value == &test_value,
211cb0ef41Sopenharmony_ci      "The correct pointer was passed to the finalizer");
221cb0ef41Sopenharmony_ci  finalize_count++;
231cb0ef41Sopenharmony_ci}
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_cistatic napi_value CreateExternal(napi_env env, napi_callback_info info) {
261cb0ef41Sopenharmony_ci  int* data = &test_value;
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci  napi_value result;
291cb0ef41Sopenharmony_ci  NODE_API_CALL(env,
301cb0ef41Sopenharmony_ci      napi_create_external(env,
311cb0ef41Sopenharmony_ci                           data,
321cb0ef41Sopenharmony_ci                           NULL, /* finalize_cb */
331cb0ef41Sopenharmony_ci                           NULL, /* finalize_hint */
341cb0ef41Sopenharmony_ci                           &result));
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  finalize_count = 0;
371cb0ef41Sopenharmony_ci  return result;
381cb0ef41Sopenharmony_ci}
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_cistatic napi_value CreateSymbol(napi_env env, napi_callback_info info) {
411cb0ef41Sopenharmony_ci  size_t argc = 1;
421cb0ef41Sopenharmony_ci  napi_value args[1];
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
451cb0ef41Sopenharmony_ci  NODE_API_ASSERT(
461cb0ef41Sopenharmony_ci      env, argc == 1, "Expect one argument only (symbol description)");
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  napi_value result_symbol;
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_create_symbol(env, args[0], &result_symbol));
511cb0ef41Sopenharmony_ci  return result_symbol;
521cb0ef41Sopenharmony_ci}
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_cistatic napi_value CreateSymbolFor(napi_env env, napi_callback_info info) {
551cb0ef41Sopenharmony_ci  size_t argc = 1;
561cb0ef41Sopenharmony_ci  napi_value args[1];
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  char description[256];
591cb0ef41Sopenharmony_ci  size_t description_length;
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
621cb0ef41Sopenharmony_ci  NODE_API_ASSERT(
631cb0ef41Sopenharmony_ci      env, argc == 1, "Expect one argument only (symbol description)");
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  NODE_API_CALL(
661cb0ef41Sopenharmony_ci      env,
671cb0ef41Sopenharmony_ci      napi_get_value_string_utf8(
681cb0ef41Sopenharmony_ci          env, args[0], description, sizeof(description), &description_length));
691cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env,
701cb0ef41Sopenharmony_ci                  description_length <= 255,
711cb0ef41Sopenharmony_ci                  "Cannot accommodate descriptions longer than 255 bytes");
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  napi_value result_symbol;
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  NODE_API_CALL(env,
761cb0ef41Sopenharmony_ci                node_api_symbol_for(
771cb0ef41Sopenharmony_ci                    env, description, description_length, &result_symbol));
781cb0ef41Sopenharmony_ci  return result_symbol;
791cb0ef41Sopenharmony_ci}
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_cistatic napi_value CreateSymbolForEmptyString(napi_env env, napi_callback_info info) {
821cb0ef41Sopenharmony_ci  napi_value result_symbol;
831cb0ef41Sopenharmony_ci  NODE_API_CALL(env, node_api_symbol_for(env, NULL, 0, &result_symbol));
841cb0ef41Sopenharmony_ci  return result_symbol;
851cb0ef41Sopenharmony_ci}
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_cistatic napi_value CreateSymbolForIncorrectLength(napi_env env, napi_callback_info info) {
881cb0ef41Sopenharmony_ci  napi_value result_symbol;
891cb0ef41Sopenharmony_ci  NODE_API_CALL(env, node_api_symbol_for(env, NULL, 5, &result_symbol));
901cb0ef41Sopenharmony_ci  return result_symbol;
911cb0ef41Sopenharmony_ci}
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_cistatic napi_value
941cb0ef41Sopenharmony_ciCreateExternalWithFinalize(napi_env env, napi_callback_info info) {
951cb0ef41Sopenharmony_ci  napi_value result;
961cb0ef41Sopenharmony_ci  NODE_API_CALL(env,
971cb0ef41Sopenharmony_ci      napi_create_external(env,
981cb0ef41Sopenharmony_ci                           &test_value,
991cb0ef41Sopenharmony_ci                           FinalizeExternal,
1001cb0ef41Sopenharmony_ci                           NULL, /* finalize_hint */
1011cb0ef41Sopenharmony_ci                           &result));
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  finalize_count = 0;
1041cb0ef41Sopenharmony_ci  return result;
1051cb0ef41Sopenharmony_ci}
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_cistatic napi_value CheckExternal(napi_env env, napi_callback_info info) {
1081cb0ef41Sopenharmony_ci  size_t argc = 1;
1091cb0ef41Sopenharmony_ci  napi_value arg;
1101cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL));
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, argc == 1, "Expected one argument.");
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci  napi_valuetype argtype;
1151cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_typeof(env, arg, &argtype));
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, argtype == napi_external, "Expected an external value.");
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  void* data;
1201cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_get_value_external(env, arg, &data));
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, data != NULL && *(int*)data == test_value,
1231cb0ef41Sopenharmony_ci      "An external data value of 1 was expected.");
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  return NULL;
1261cb0ef41Sopenharmony_ci}
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_cistatic napi_value CreateReference(napi_env env, napi_callback_info info) {
1291cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, test_reference == NULL,
1301cb0ef41Sopenharmony_ci      "The test allows only one reference at a time.");
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  size_t argc = 2;
1331cb0ef41Sopenharmony_ci  napi_value args[2];
1341cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
1351cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, argc == 2, "Expected two arguments.");
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  uint32_t initial_refcount;
1381cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_get_value_uint32(env, args[1], &initial_refcount));
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  NODE_API_CALL(env,
1411cb0ef41Sopenharmony_ci      napi_create_reference(env, args[0], initial_refcount, &test_reference));
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, test_reference != NULL,
1441cb0ef41Sopenharmony_ci      "A reference should have been created.");
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  return NULL;
1471cb0ef41Sopenharmony_ci}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_cistatic napi_value DeleteReference(napi_env env, napi_callback_info info) {
1501cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, test_reference != NULL,
1511cb0ef41Sopenharmony_ci      "A reference must have been created.");
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_delete_reference(env, test_reference));
1541cb0ef41Sopenharmony_ci  test_reference = NULL;
1551cb0ef41Sopenharmony_ci  return NULL;
1561cb0ef41Sopenharmony_ci}
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_cistatic napi_value IncrementRefcount(napi_env env, napi_callback_info info) {
1591cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, test_reference != NULL,
1601cb0ef41Sopenharmony_ci      "A reference must have been created.");
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  uint32_t refcount;
1631cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_reference_ref(env, test_reference, &refcount));
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci  napi_value result;
1661cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_create_uint32(env, refcount, &result));
1671cb0ef41Sopenharmony_ci  return result;
1681cb0ef41Sopenharmony_ci}
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_cistatic napi_value DecrementRefcount(napi_env env, napi_callback_info info) {
1711cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, test_reference != NULL,
1721cb0ef41Sopenharmony_ci      "A reference must have been created.");
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  uint32_t refcount;
1751cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_reference_unref(env, test_reference, &refcount));
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  napi_value result;
1781cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_create_uint32(env, refcount, &result));
1791cb0ef41Sopenharmony_ci  return result;
1801cb0ef41Sopenharmony_ci}
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_cistatic napi_value GetReferenceValue(napi_env env, napi_callback_info info) {
1831cb0ef41Sopenharmony_ci  NODE_API_ASSERT(env, test_reference != NULL,
1841cb0ef41Sopenharmony_ci      "A reference must have been created.");
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  napi_value result;
1871cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_get_reference_value(env, test_reference, &result));
1881cb0ef41Sopenharmony_ci  return result;
1891cb0ef41Sopenharmony_ci}
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_cistatic void DeleteBeforeFinalizeFinalizer(
1921cb0ef41Sopenharmony_ci    napi_env env, void* finalize_data, void* finalize_hint) {
1931cb0ef41Sopenharmony_ci  napi_ref* ref = (napi_ref*)finalize_data;
1941cb0ef41Sopenharmony_ci  napi_value value;
1951cb0ef41Sopenharmony_ci  assert(napi_get_reference_value(env, *ref, &value) == napi_ok);
1961cb0ef41Sopenharmony_ci  assert(value == NULL);
1971cb0ef41Sopenharmony_ci  napi_delete_reference(env, *ref);
1981cb0ef41Sopenharmony_ci  free(ref);
1991cb0ef41Sopenharmony_ci}
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_cistatic napi_value ValidateDeleteBeforeFinalize(napi_env env, napi_callback_info info) {
2021cb0ef41Sopenharmony_ci  napi_value wrapObject;
2031cb0ef41Sopenharmony_ci  size_t argc = 1;
2041cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &wrapObject, NULL, NULL));
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci  napi_ref* ref_t = malloc(sizeof(napi_ref));
2071cb0ef41Sopenharmony_ci  NODE_API_CALL(env,
2081cb0ef41Sopenharmony_ci      napi_wrap(
2091cb0ef41Sopenharmony_ci          env, wrapObject, ref_t, DeleteBeforeFinalizeFinalizer, NULL, NULL));
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  // Create a reference that will be eligible for collection at the same
2121cb0ef41Sopenharmony_ci  // time as the wrapped object by passing in the same wrapObject.
2131cb0ef41Sopenharmony_ci  // This means that the FinalizeOrderValidation callback may be run
2141cb0ef41Sopenharmony_ci  // before the finalizer for the newly created reference (there is a finalizer
2151cb0ef41Sopenharmony_ci  // behind the scenes even though it cannot be passed to napi_create_reference)
2161cb0ef41Sopenharmony_ci  // The Finalizer for the wrap (which is different than the finalizer
2171cb0ef41Sopenharmony_ci  // for the reference) calls napi_delete_reference validating that
2181cb0ef41Sopenharmony_ci  // napi_delete_reference can be called before the finalizer for the
2191cb0ef41Sopenharmony_ci  // reference runs.
2201cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_create_reference(env, wrapObject, 0, ref_t));
2211cb0ef41Sopenharmony_ci  return wrapObject;
2221cb0ef41Sopenharmony_ci}
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ciEXTERN_C_START
2251cb0ef41Sopenharmony_cinapi_value Init(napi_env env, napi_value exports) {
2261cb0ef41Sopenharmony_ci  napi_property_descriptor descriptors[] = {
2271cb0ef41Sopenharmony_ci      DECLARE_NODE_API_GETTER("finalizeCount", GetFinalizeCount),
2281cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("createExternal", CreateExternal),
2291cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("createExternalWithFinalize",
2301cb0ef41Sopenharmony_ci                                CreateExternalWithFinalize),
2311cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("checkExternal", CheckExternal),
2321cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("createReference", CreateReference),
2331cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("createSymbol", CreateSymbol),
2341cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("createSymbolFor", CreateSymbolFor),
2351cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("createSymbolForEmptyString",
2361cb0ef41Sopenharmony_ci                                CreateSymbolForEmptyString),
2371cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("createSymbolForIncorrectLength",
2381cb0ef41Sopenharmony_ci                                CreateSymbolForIncorrectLength),
2391cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("deleteReference", DeleteReference),
2401cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("incrementRefcount", IncrementRefcount),
2411cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("decrementRefcount", DecrementRefcount),
2421cb0ef41Sopenharmony_ci      DECLARE_NODE_API_GETTER("referenceValue", GetReferenceValue),
2431cb0ef41Sopenharmony_ci      DECLARE_NODE_API_PROPERTY("validateDeleteBeforeFinalize",
2441cb0ef41Sopenharmony_ci                                ValidateDeleteBeforeFinalize),
2451cb0ef41Sopenharmony_ci  };
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci  NODE_API_CALL(env, napi_define_properties(
2481cb0ef41Sopenharmony_ci      env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors));
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  return exports;
2511cb0ef41Sopenharmony_ci}
2521cb0ef41Sopenharmony_ciEXTERN_C_END
253