[engine] [cocos2d-x] [jsb-adapter] 适配引擎 v2.4.12 版本

This commit is contained in:
SmallMain
2023-10-30 22:32:32 +08:00
parent 2508616ad9
commit 0092eb9f05
787 changed files with 206249 additions and 422 deletions

View File

@@ -0,0 +1,238 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "Class.h"
#include <string>
#include "CommonHeader.h"
#include "ScriptEngine.h"
#include "Utils.h"
namespace se {
napi_value *Class::_exports = nullptr;
std::vector<Class *> __allClasses;
Class::Class() {
__allClasses.push_back(this);
};
Class::~Class() {
}
/* static */
Class *Class::create(const std::string &clsName, se::Object *parent, Object *parentProto, napi_callback ctor) {
Class *cls = new Class();
if (cls != nullptr && !cls->init(clsName, parent, parentProto, ctor)) {
delete cls;
cls = nullptr;
}
return cls;
}
Class* Class::create(const std::initializer_list<const char *> &classPath, se::Object *parent, Object *parentProto, napi_callback ctor) {
se::AutoHandleScope scope;
se::Object *currentParent = parent;
se::Value tmp;
for (auto i = 0; i < classPath.size() - 1; i++) {
bool ok = currentParent->getProperty(*(classPath.begin() + i), &tmp);
assert(ok); // class or namespace in path is not defined
currentParent = tmp.toObject();
}
return create(*(classPath.end() - 1), currentParent, parentProto, ctor);
}
bool Class::init(const std::string &clsName, Object *parent, Object *parentProto, napi_callback ctor) {
_name = clsName;
_parent = parent;
if (_parent != nullptr)
_parent->incRef();
_parentProto = parentProto;
if (_parentProto != nullptr)
_parentProto->incRef();
if (ctor) {
_ctorFunc = ctor;
}
return true;
}
napi_value Class::_defaultCtor(napi_env env, napi_callback_info info) {
LOGE("check default ctor called");
return nullptr;
}
void Class::defineProperty(const char* name, napi_callback g, napi_callback s) {
_properties.push_back({name, nullptr, nullptr, g, s, 0, napi_default_jsproperty, 0});
}
void Class::defineProperty(const std::initializer_list<const char *> &names, napi_callback g, napi_callback s) {
for (const auto *name : names) {
defineProperty(name, g, s);
}
}
void Class::defineStaticProperty(const char* name, napi_callback g, napi_callback s) {
if(g != nullptr && s != nullptr)
_properties.push_back({name, nullptr, nullptr, g, s, 0, napi_static, 0});
}
void Class::defineFunction(const char* name, napi_callback func) {
// When Napi defines a function, it needs to add the enum attribute, otherwise JS cannot traverse the function
_properties.push_back({name, nullptr, func, nullptr, nullptr, nullptr, napi_default_jsproperty, nullptr});
}
void Class::defineStaticFunction(const char* name, napi_callback func) {
_properties.push_back({name, nullptr, func, nullptr, nullptr, 0, napi_property_attributes((int)napi_static|(int)napi_writable), 0});
}
void Class::defineFinalizeFunction(napi_finalize func) {
assert(func != nullptr);
_finalizeFunc = func;
}
napi_finalize Class::_getFinalizeFunction() const {
return _finalizeFunc;
}
bool Class::install() {
napi_value cons;
napi_status status;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_define_class(ScriptEngine::getEnv(), _name.c_str(), -1, _ctorFunc, nullptr, _properties.size(), _properties.data(), &cons));
if (_parentProto) {
inherit(ScriptEngine::getEnv(), cons, _parentProto->_getJSObject());
}
NODE_API_CALL(status, ScriptEngine::getEnv(),
napi_create_reference(ScriptEngine::getEnv(), cons, 1, &_constructor));
NODE_API_CALL(status, ScriptEngine::getEnv(),
napi_set_named_property(ScriptEngine::getEnv(), _parent->_getJSObject(), _name.c_str(), cons));
napi_value proto;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_named_property(ScriptEngine::getEnv(), cons, "prototype", &proto));
if (status == napi_ok) {
_proto = Object::_createJSObject(ScriptEngine::getEnv(), proto, nullptr);
_proto->root();
}
return true;
}
napi_status Class::inherit(napi_env env, napi_value subclass, napi_value superProto) {
napi_value global, objectClass, setProto;
napi_value argv[2];
napi_value callbackResult = nullptr;
napi_get_global(env, &global);
napi_status status = napi_get_named_property(env, global, "Object", &objectClass);
if (status != napi_ok) {
return napi_ok;
}
status = napi_get_named_property(env, objectClass, "setPrototypeOf", &setProto);
if (status != napi_ok) {
return napi_ok;
}
status = napi_get_named_property(env, subclass, "prototype", &argv[0]);
if (status != napi_ok) {
return napi_ok;
}
argv[1] = superProto;
status = napi_call_function(env, objectClass, setProto, 2, argv, &callbackResult);
if (status != napi_ok) {
return napi_ok;
}
return napi_ok;
}
napi_value Class::_createJSObjectWithClass(Class *cls) {
napi_value obj = nullptr;
napi_status status;
assert(cls);
napi_value clsCtor = cls->_getCtorFunc();
if (!clsCtor) {
LOGE("get ctor func err");
return nullptr;
}
se::ScriptEngine::getInstance()->_setNeedCallConstructor(false);
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_new_instance( ScriptEngine::getEnv(), clsCtor, 0, nullptr, &obj));
se::ScriptEngine::getInstance()->_setNeedCallConstructor(true);
return obj;
}
Object *Class::getProto() const {
//not impl
return _proto;
}
napi_ref Class::_getCtorRef() const {
return _constructor;
}
napi_value Class::_getCtorFunc() const {
assert(_constructor);
napi_value result = nullptr;
napi_status status;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_reference_value(ScriptEngine::getEnv(), _constructor, &result));
return result;
}
void Class::_setCtor(Object *obj) {
assert(!_ctor.has_value());
_ctor = obj;
if (obj != nullptr) {
obj->root();
obj->incRef();
}
}
void Class::destroy() {
SAFE_DEC_REF(_parent);
SAFE_DEC_REF(_proto);
SAFE_DEC_REF(_parentProto);
if (_ctor.has_value()) {
if (_ctor.value() != nullptr) {
_ctor.value()->unroot();
_ctor.value()->decRef();
}
_ctor.reset();
}
}
void Class::cleanup() {
for (auto cls : __allClasses) {
cls->destroy();
}
se::ScriptEngine::getInstance()->addAfterCleanupHook([]() {
for (auto cls : __allClasses) {
delete cls;
}
__allClasses.clear();
});
}
}; // namespace se

View File

@@ -0,0 +1,81 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <string>
#include <optional>
#include "CommonHeader.h"
#include "Object.h"
namespace se {
class Class {
public:
static Class *create(const std::string &clsName, se::Object *parent, Object *parentProto, napi_callback ctor = nullptr);
static Class *create(const std::initializer_list<const char *> &classPath, se::Object *parent, Object *parentProto, napi_callback ctor = nullptr);
void defineFunction(const char* name, napi_callback func);
void defineProperty(const char* name, napi_callback g, napi_callback s);
void defineProperty(const std::initializer_list<const char *> &names, napi_callback g, napi_callback s);
void defineStaticFunction(const char* name, napi_callback func);
void defineStaticProperty(const char* name, napi_callback g, napi_callback s);
static napi_value _createJSObjectWithClass(Class *cls);
void defineFinalizeFunction(napi_finalize func);
napi_finalize _getFinalizeFunction() const;
Object * getProto() const;
bool install();
napi_status inherit(napi_env env, napi_value subclass, napi_value superclass);
napi_ref _getCtorRef() const;
napi_value _getCtorFunc() const;
const char * getName() const { return _name.c_str(); }
static void setExports(napi_value *expPtr) { _exports = expPtr; }
static void cleanup();
// Private API used in wrapper
void _setCtor(Object *obj); // NOLINT(readability-identifier-naming)
inline const std::optional<Object *> &_getCtor() const { return _ctor; } // NOLINT(readability-identifier-naming)
private:
Class();
~Class();
bool init(const std::string &clsName, Object *parent, Object *parentProto, napi_callback ctor = nullptr);
void destroy();
static napi_value _defaultCtor(napi_env env, napi_callback_info info);
private:
std::optional<Object *> _ctor;
static napi_value * _exports;
std::string _name;
Object * _parent = nullptr;
Object * _proto = nullptr;
Object * _parentProto = nullptr;
napi_callback _ctorFunc = Class::_defaultCtor;
napi_ref _constructor = nullptr;
std::vector<napi_property_descriptor> _properties;
napi_finalize _finalizeFunc = nullptr;
};
}; // namespace se

View File

@@ -0,0 +1,74 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <napi/native_api.h>
#include "native_common.h"
// Empty value so that macros here are able to return NULL or void
#define NODE_API_RETVAL_NOTHING // Intentionally blank #define
// Returns NULL on failed assertion.
// This is meant to be used inside napi_callback methods.
#define NODE_API_ASSERT(env, assertion, message) \
NODE_API_ASSERT_BASE(env, assertion, message, NULL)
// Returns empty on failed assertion.
// This is meant to be used inside functions with void return type.
#define NODE_API_ASSERT_RETURN_VOID(env, assertion, message) \
NODE_API_ASSERT_BASE(env, assertion, message, NODE_API_RETVAL_NOTHING)
#define NODE_API_CALL_BASE(env, the_call, ret_val) \
do { \
if ((the_call) != napi_ok) { \
assert(false); \
} \
} while (0)
// Returns nullptr if the_call doesn't return napi_ok.
#define NODE_API_CALL(status, env, the_call) \
status = the_call; \
if (status != napi_ok) \
LOGI("error:%d", status); \
NODE_API_CALL_BASE(env, status, nullptr)
// Returns empty if the_call doesn't return napi_ok.
#define NODE_API_CALL_RETURN_VOID(env, the_call) \
NODE_API_CALL_BASE(env, the_call, NODE_API_RETVAL_NOTHING)
#define DECLARE_NODE_API_PROPERTY(name, func) \
{ (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr }
#define DECLARE_NODE_API_GETTER(name, func) \
{ (name), nullptr, nullptr, (func), nullptr, nullptr, napi_default, nullptr }
void add_returned_status(napi_env env,
const char* key,
napi_value object,
char* expected_message,
napi_status expected_status,
napi_status actual_status);
void add_last_status(napi_env env, const char* key, napi_value return_value);

View File

@@ -0,0 +1,145 @@
/****************************************************************************
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "HelperMacros.h"
#include "../State.hpp"
#include "Class.h"
#include "Object.h"
#include "ScriptEngine.h"
#include "Utils.h"
SE_HOT napi_value jsbFunctionWrapper(napi_env env, napi_callback_info info, se_function_ptr func, const char *funcName) {
napi_status status;
bool ret = false;
napi_value _this;
se::ValueArray seArgs;
seArgs.reserve(15);
size_t argc = 15;
napi_value args[15];
NODE_API_CALL(status, env, napi_get_cb_info(env, info, &argc, args, &_this, NULL));
void* nativeThisObject = nullptr;
status = napi_unwrap(env, _this, &nativeThisObject);
se::internal::jsToSeArgs(argc, args, &seArgs);
se::State state(nativeThisObject, seArgs);
ret = func(state);
if (!ret) {
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
return nullptr;
}
napi_value retVal;
if (se::internal::setReturnValue(state.rval(), retVal))
return retVal;
return nullptr;
}
SE_HOT void jsbFinalizeWrapper(void *thisObject, se_function_ptr func, const char *funcName) {
se::State state(reinterpret_cast<se::Object *>(thisObject));
bool ret = func(state);
if (!ret) {
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
}
}
SE_HOT napi_value jsbConstructorWrapper(napi_env env, napi_callback_info info, se_function_ptr func, se_finalize_ptr finalizeCb, se::Class *cls, const char *funcName) {
napi_status status;
bool ret = false;
napi_value _this;
se::ValueArray seArgs;
seArgs.reserve(10);
size_t argc = 10;
napi_value args[10];
NODE_API_CALL(status, env, napi_get_cb_info(env, info, &argc, args, &_this, NULL));
if (!se::ScriptEngine::getInstance()->_needCallConstructor()) {
return _this;
}
se::internal::jsToSeArgs(argc, args, &seArgs);
se::Object *thisObject = se::Object::_createJSObject(env, _this, cls);
thisObject->_setFinalizeCallback(finalizeCb);
se::State state(thisObject, seArgs);
ret = func(state);
if (!ret) {
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
}
se::Value property;
bool foundCtor = false;
if (!cls->_getCtor().has_value()) {
foundCtor = thisObject->getProperty("_ctor", &property, true);
if (foundCtor) {
cls->_setCtor(property.toObject());
} else {
cls->_setCtor(nullptr);
}
} else {
auto *ctorObj = cls->_getCtor().value();
if (ctorObj != nullptr) {
property.setObject(ctorObj);
foundCtor = true;
}
}
if (foundCtor) {
property.toObject()->call(seArgs, thisObject);
}
return _this;
}
SE_HOT napi_value jsbGetterWrapper(napi_env env, napi_callback_info info, se_function_ptr func, const char *funcName) {
napi_value _this;
napi_status status;
NODE_API_CALL(status, env,
napi_get_cb_info(env, info, nullptr, nullptr, &_this, nullptr));
void* obj = nullptr;
status = napi_unwrap(env, _this, &obj);
se::State state(obj);
bool ret = func(state);
if (!ret) {
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
return nullptr;
}
napi_value retVal;
se::internal::setReturnValue(state.rval(), retVal);
return retVal;
}
SE_HOT napi_value jsbSetterWrapper(napi_env env, napi_callback_info info, se_function_ptr func, const char *funcName) {
napi_status status;
size_t argc = 1;
napi_value args[1];
napi_value _this;
se::Value data;
NODE_API_CALL(status, env, napi_get_cb_info(env, info, &argc, args, &_this, nullptr));
se::internal::jsToSeValue(args[0], &data);
se::ValueArray args2;
args2.reserve(10);
args2.push_back(std::move(data));
void* nativeThisObject = nullptr;
status = napi_unwrap(env, _this, &nativeThisObject);
se::State state(nativeThisObject, args2);
bool ret = func(state);
if (!ret) {
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", funcName, __FILE__, __LINE__);
}
return nullptr;
}

View File

@@ -0,0 +1,153 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "CommonHeader.h"
#if !defined(_WIN)
#include <hilog/log.h>
#ifndef LOGI
#define LOGI(...) ((void) OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "HMG_LOG", __VA_ARGS__))
#define LOGW(...) ((void) OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, "HMG_LOG", __VA_ARGS__))
#define LOGE(...) ((void) OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "HMG_LOG", __VA_ARGS__))
#define LOGD(...) ((void) OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, "HMG_LOG", __VA_ARGS__))
#endif
#else
#define LOGI
#define LOGW
#define LOGE
#endif
namespace se {
class Class;
class Object;
class State;
} // namespace se
using se_function_ptr = bool (*)(se::State &state);
using se_finalize_ptr = void (*)(napi_env env, void *nativeObject, void *hint);
napi_value jsbFunctionWrapper(napi_env, napi_callback_info,
se_function_ptr,
const char *);
void jsbFinalizeWrapper(void *thisObject,
se_function_ptr,
const char *);
napi_value jsbConstructorWrapper(napi_env, napi_callback_info,
se_function_ptr,
se_finalize_ptr finalizeCb,
se::Class *,
const char *);
napi_value jsbGetterWrapper(napi_env, napi_callback_info,
se_function_ptr,
const char *);
napi_value jsbSetterWrapper(napi_env, napi_callback_info,
se_function_ptr,
const char *);
#ifdef __GNUC__
#define SE_UNUSED __attribute__((unused))
#define SE_HOT __attribute__((hot))
#else
#define SE_UNUSED
#define SE_HOT
#endif
template <typename T, typename STATE>
constexpr inline T *SE_THIS_OBJECT(STATE &s) { // NOLINT(readability-identifier-naming)
return reinterpret_cast<T *>(s.nativeThisObject());
}
#define SAFE_INC_REF(obj) \
if (obj != nullptr) obj->incRef()
#define SAFE_DEC_REF(obj) \
if ((obj) != nullptr) { \
(obj)->decRef(); \
(obj) = nullptr; \
}
#define _SE(name) name##Registry // NOLINT(readability-identifier-naming, bugprone-reserved-identifier)
#define SE_QUOTEME_(x) #x // NOLINT(readability-identifier-naming)
#define SE_QUOTEME(x) SE_QUOTEME_(x)
#define SE_REPORT_ERROR(fmt, ...) SE_LOGE("[ERROR] (" __FILE__ ", " SE_QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__)
#define SE_BIND_PROP_GET_IMPL(funcName, postFix) \
napi_value funcName##postFix##Registry(napi_env env, napi_callback_info info) { \
return jsbGetterWrapper(env, info, funcName, #funcName); \
}
#define SE_BIND_PROP_GET(funcName) SE_BIND_PROP_GET_IMPL(funcName, )
#define SE_BIND_FUNC_AS_PROP_GET(funcName) SE_BIND_PROP_GET_IMPL(funcName, _asGetter)
#define SE_BIND_PROP_SET_IMPL(funcName, postFix) \
napi_value funcName##postFix##Registry(napi_env env, napi_callback_info info) { \
return jsbSetterWrapper(env, info, funcName, #funcName); \
}
#define SE_BIND_PROP_SET(funcName) SE_BIND_PROP_SET_IMPL(funcName, )
#define SE_BIND_FUNC_AS_PROP_SET(funcName) SE_BIND_PROP_SET_IMPL(funcName, _asSetter)
#define SE_DECLARE_FUNC(funcName) \
napi_value funcName##Registry(napi_env env, napi_callback_info info)
#define SE_BIND_FUNC(funcName) \
napi_value funcName##Registry( \
napi_env env, napi_callback_info info) { \
return jsbFunctionWrapper(env, info, funcName, #funcName); \
}
#define SE_BIND_FUNC_FAST(funcName) \
napi_value funcName##Registry(napi_env env, napi_callback_info info) { \
napi_status status; \
napi_value _this; \
size_t argc = 10; \
napi_value args[10]; \
void* nativeThisObject = nullptr; \
NODE_API_CALL(status, env, napi_get_cb_info(env, info, &argc, args, &_this, NULL)); \
status = napi_unwrap(env, _this, &nativeThisObject); \
auto *nativeObject = nativeThisObject != nullptr ? nativeThisObject->getPrivateData() : nullptr; \
funcName(nativeObject); \
return nullptr; \
}
#define SE_BIND_CTOR(funcName, cls, finalizeCb) \
napi_value funcName##Registry( \
napi_env env, napi_callback_info info) { \
return jsbConstructorWrapper(env, info, funcName, _SE(finalizeCb), cls, #funcName); \
}
#define SE_BIND_SUB_CLS_CTOR SE_BIND_CTOR
#define SE_DECLARE_FINALIZE_FUNC(funcName) \
void funcName##Registry( \
napi_env env, void *nativeObject, void * /*finalize_hint*/);
#define SE_BIND_FINALIZE_FUNC(funcName) \
void funcName##Registry( \
napi_env env, void *nativeObject, void *hint /*finalize_hint*/) { \
if (nativeObject == nullptr) { \
return; \
} \
jsbFinalizeWrapper(nativeObject, funcName, #funcName); \
}

View File

@@ -0,0 +1,738 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "Object.h"
#include <memory>
#include <unordered_map>
#include "../MappingUtils.hpp"
#include "Class.h"
#include "ScriptEngine.h"
#include "Utils.h"
#define MAX_STRING_LEN 512
namespace se {
std::unique_ptr<std::unordered_map<Object*, void*>> __objectMap; // Currently, the value `void*` is always nullptr
Object::Object() {}
Object::~Object() {
if (__objectMap) {
__objectMap->erase(this);
}
}
Object* Object::createObjectWithClass(Class* cls) {
napi_value jsobj = Class::_createJSObjectWithClass(cls);
Object* obj = Object::_createJSObject(ScriptEngine::getEnv(), jsobj, cls);
return obj;
}
bool Object::setProperty(const char* name, const Value& data) {
napi_status status;
napi_value jsVal;
internal::seToJsValue(data, &jsVal);
NODE_API_CALL(status, _env, napi_set_named_property(_env, _objRef.getValue(_env), name, jsVal));
return status == napi_ok;
}
bool Object::getProperty(const char* name, Value* d) {
napi_status status;
napi_value jsVal;
Value data;
NODE_API_CALL(status, _env, napi_get_named_property(_env, _objRef.getValue(_env), name, &jsVal));
if (status == napi_ok) {
internal::jsToSeValue(jsVal, &data);
*d = data;
if (data.isUndefined()) {
return false;
}
return true;
}
return false;
}
bool Object::deleteProperty(const char *name) {
napi_status status;
napi_value key;
NODE_API_CALL(status, _env, napi_get_named_property(_env, _objRef.getValue(_env), name, &key));
if (status != napi_ok) {
return false;
}
bool ret = false;
NODE_API_CALL(status, _env, napi_delete_property(_env, _objRef.getValue(_env), key, &ret));
return ret;
}
bool Object::isArray() const {
napi_status status;
bool ret = false;
NODE_API_CALL(status, _env, napi_is_array(_env, _objRef.getValue(_env), &ret));
return ret;
}
bool Object::getArrayLength(uint32_t* length) const {
napi_status status;
uint32_t len = 0;
NODE_API_CALL(status, _env, napi_get_array_length(_env, _objRef.getValue(_env), &len));
if (length) {
*length = len;
}
return true;
}
bool Object::getArrayElement(uint32_t index, Value* data) const {
napi_status status;
napi_value val;
NODE_API_CALL(status, _env, napi_get_element(_env, _objRef.getValue(_env), index, &val));
internal::jsToSeValue(val, data);
return true;
}
bool Object::setArrayElement(uint32_t index, const Value& data) {
napi_status status;
napi_value val;
internal::seToJsValue(data, &val);
NODE_API_CALL(status, _env, napi_set_element(_env, _objRef.getValue(_env), index, val));
return true;
}
bool Object::isTypedArray() const {
napi_status status;
bool ret = false;
NODE_API_CALL(status, _env, napi_is_typedarray(_env, _objRef.getValue(_env), &ret));
return ret;
}
bool Object::isProxy() const {
//return const_cast<Object *>(this)->_obj.handle(__isolate)->IsProxy();
// todo:
return false;
}
Object::TypedArrayType Object::getTypedArrayType() const {
napi_status status;
napi_typedarray_type type;
napi_value inputBuffer;
size_t byteOffset;
size_t length;
NODE_API_CALL(status, _env, napi_get_typedarray_info(_env, _objRef.getValue(_env), &type, &length, NULL, &inputBuffer, &byteOffset));
TypedArrayType ret = TypedArrayType::NONE;
switch (type) {
case napi_int8_array:
ret = TypedArrayType::INT8;
break;
case napi_uint8_array:
ret = TypedArrayType::UINT8;
break;
case napi_uint8_clamped_array:
ret = TypedArrayType::UINT8_CLAMPED;
break;
case napi_int16_array:
ret = TypedArrayType::INT16;
break;
case napi_uint16_array:
ret = TypedArrayType::UINT16;
break;
case napi_int32_array:
ret = TypedArrayType::INT32;
break;
case napi_uint32_array:
ret = TypedArrayType::UINT32;
break;
case napi_float32_array:
ret = TypedArrayType::FLOAT32;
break;
case napi_float64_array:
ret = TypedArrayType::FLOAT64;
break;
default:
break;
}
return ret;
}
bool Object::getTypedArrayData(uint8_t** ptr, size_t* length) const {
napi_status status;
napi_typedarray_type type;
napi_value inputBuffer;
size_t byteOffset;
size_t byteLength;
void* data = nullptr;
NODE_API_CALL(status, _env, napi_get_typedarray_info(_env, _objRef.getValue(_env), &type, &byteLength, &data, &inputBuffer, &byteOffset));
*ptr = (uint8_t*)(data);
if (length) {
*length = byteLength;
}
return true;
}
bool Object::isArrayBuffer() const {
bool ret = false;
napi_status status;
NODE_API_CALL(status, _env, napi_is_arraybuffer(_env, _objRef.getValue(_env), &ret));
return ret;
}
bool Object::getArrayBufferData(uint8_t** ptr, size_t* length) const {
napi_status status;
size_t len = 0;
NODE_API_CALL(status, _env, napi_get_arraybuffer_info(_env, _objRef.getValue(_env), reinterpret_cast<void**>(ptr), &len));
if (length) {
*length = len;
}
return true;
}
Object* Object::createTypedArray(Object::TypedArrayType type, const void* data, size_t byteLength) {
napi_status status;
if (type == TypedArrayType::NONE) {
SE_LOGE("Don't pass se::Object::TypedArrayType::NONE to createTypedArray API!");
return nullptr;
}
if (type == TypedArrayType::UINT8_CLAMPED) {
SE_LOGE("Doesn't support to create Uint8ClampedArray with Object::createTypedArray API!");
return nullptr;
}
napi_typedarray_type napiType;
napi_value outputBuffer;
void* outputPtr = nullptr;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_arraybuffer(ScriptEngine::getEnv(), byteLength, &outputPtr, &outputBuffer));
if (outputPtr && data && byteLength > 0) {
memcpy(outputPtr, data, byteLength);
}
size_t sizeOfEle = 0;
switch (type) {
case TypedArrayType::INT8:
napiType = napi_int8_array;
sizeOfEle = 1;
break;
case TypedArrayType::UINT8:
napiType = napi_uint8_array;
sizeOfEle = 1;
break;
case TypedArrayType::INT16:
napiType = napi_int16_array;
sizeOfEle = 2;
break;
case TypedArrayType::UINT16:
napiType = napi_uint16_array;
sizeOfEle = 2;
break;
case TypedArrayType::INT32:
napiType = napi_int32_array;
sizeOfEle = 4;
break;
case TypedArrayType::UINT32:
napiType = napi_uint32_array;
sizeOfEle = 4;
break;
case TypedArrayType::FLOAT32:
napiType = napi_float32_array;
sizeOfEle = 4;
break;
case TypedArrayType::FLOAT64:
napiType = napi_float64_array;
sizeOfEle = 8;
break;
default:
assert(false); // Should never go here.
break;
}
size_t eleCounts = byteLength / sizeOfEle;
napi_value outputArray;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_typedarray(ScriptEngine::getEnv(), napiType, eleCounts, outputBuffer, 0, &outputArray));
Object* obj = Object::_createJSObject(ScriptEngine::getEnv(), outputArray, nullptr);
return obj;
}
Object* Object::createTypedArrayWithBuffer(TypedArrayType type, const Object *obj) {
return Object::createTypedArrayWithBuffer(type, obj, 0);
}
Object* Object::createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset) {
size_t byteLength{0};
uint8_t *skip{nullptr};
if (obj->getArrayBufferData(&skip, &byteLength)) {
return Object::createTypedArrayWithBuffer(type, obj, offset, byteLength - offset);
}
assert(false);
return nullptr;
}
Object* Object::createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset, size_t byteLength) {
if (type == TypedArrayType::NONE) {
SE_LOGE("Don't pass se::Object::TypedArrayType::NONE to createTypedArray API!");
return nullptr;
}
if (type == TypedArrayType::UINT8_CLAMPED) {
SE_LOGE("Doesn't support to create Uint8ClampedArray with Object::createTypedArray API!");
return nullptr;
}
assert(obj->isArrayBuffer());
napi_status status;
napi_value outputBuffer = obj->_getJSObject();
napi_typedarray_type napiType;
size_t sizeOfEle = 0;
switch (type) {
case TypedArrayType::INT8:
napiType = napi_int8_array;
sizeOfEle = 1;
break;
case TypedArrayType::UINT8:
napiType = napi_uint8_array;
sizeOfEle = 1;
break;
case TypedArrayType::INT16:
napiType = napi_int8_array;
sizeOfEle = 2;
case TypedArrayType::UINT16:
napiType = napi_uint8_array;
sizeOfEle = 2;
break;
case TypedArrayType::INT32:
napiType = napi_int32_array;
sizeOfEle = 4;
case TypedArrayType::UINT32:
napiType = napi_uint32_array;
sizeOfEle = 4;
case TypedArrayType::FLOAT32:
napiType = napi_float32_array;
sizeOfEle = 4;
break;
case TypedArrayType::FLOAT64:
napiType = napi_float64_array;
sizeOfEle = 8;
break;
default:
assert(false); // Should never go here.
break;
}
size_t eleCounts = byteLength / sizeOfEle;
napi_value outputArray;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_typedarray(ScriptEngine::getEnv(), napiType, eleCounts, outputBuffer, offset, &outputArray));
return Object::_createJSObject(ScriptEngine::getEnv(), outputArray, nullptr);
}
Object* Object::createExternalArrayBufferObject(void *contents, size_t byteLength, BufferContentsFreeFunc freeFunc, void *freeUserData) {
napi_status status;
napi_value result;
if (freeFunc) {
struct ExternalArrayBufferCallbackParams* param = new (struct ExternalArrayBufferCallbackParams);
param->func = freeFunc;
param->contents = contents;
param->byteLength = byteLength;
param->userData = freeUserData;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_external_arraybuffer(
ScriptEngine::getEnv(), contents, byteLength, [](napi_env env, void* finalize_data, void* finalize_hint) {
if (finalize_hint) {
struct ExternalArrayBufferCallbackParams* param = reinterpret_cast<struct ExternalArrayBufferCallbackParams *>(finalize_hint);
param->func(param->contents, param->byteLength, param->userData);
delete param;
}
},
reinterpret_cast<void*>(param), &result));
} else {
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_external_arraybuffer(
ScriptEngine::getEnv(), contents, byteLength, nullptr,
freeUserData, &result));
}
Object* obj = Object::_createJSObject(ScriptEngine::getEnv(), result, nullptr);
return obj;
}
bool Object::isFunction() const {
napi_valuetype valuetype0;
napi_status status;
NODE_API_CALL(status, _env, napi_typeof(_env, _objRef.getValue(_env), &valuetype0));
return (valuetype0 == napi_function);
}
bool Object::defineFunction(const char* funcName, napi_callback func) {
napi_value fn;
napi_status status;
NODE_API_CALL(status, _env, napi_create_function(_env, funcName, NAPI_AUTO_LENGTH, func, NULL, &fn));
NODE_API_CALL(status, _env, napi_set_named_property(_env, _objRef.getValue(_env), funcName, fn));
return true;
}
bool Object::defineProperty(const char* name, napi_callback getter, napi_callback setter) {
napi_status status;
napi_property_descriptor properties[] = {{name, nullptr, nullptr, getter, setter, 0, napi_default, 0}};
status = napi_define_properties(_env, _objRef.getValue(_env), sizeof(properties) / sizeof(napi_property_descriptor), properties);
if (status == napi_ok) {
return true;
}
return false;
}
Object* Object::_createJSObject(napi_env env, napi_value js_object, Class* cls) { // NOLINT(readability-identifier-naming)
Object* ret = new Object();
if (!ret->init(env, js_object, cls)) {
delete ret;
ret = nullptr;
}
return ret;
}
Object* Object::createPlainObject() {
napi_value result;
napi_status status;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_object(ScriptEngine::getEnv(), &result));
Object* obj = _createJSObject(ScriptEngine::getEnv(), result, nullptr);
return obj;
}
Object* Object::createArrayObject(size_t length) {
napi_value result;
napi_status status;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_array_with_length(ScriptEngine::getEnv(), length, &result));
Object* obj = _createJSObject(ScriptEngine::getEnv(), result, nullptr);
return obj;
}
Object* Object::createArrayBufferObject(const void* data, size_t byteLength) {
napi_value result;
napi_status status;
void* retData;
Object* obj = nullptr;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_arraybuffer(ScriptEngine::getEnv(), byteLength, &retData, &result));
if (status == napi_ok) {
if (data) {
memcpy(retData, data, byteLength);
}
obj = _createJSObject(ScriptEngine::getEnv(), result, nullptr);
}
return obj;
}
bool Object::getAllKeys(std::vector<std::string>* allKeys) const {
napi_status status;
napi_value names;
NODE_API_CALL(status, _env, napi_get_property_names(_env, _objRef.getValue(_env), &names));
if (status != napi_ok) {
return false;
}
uint32_t name_len = 0;
NODE_API_CALL(status, _env, napi_get_array_length(_env, names, &name_len));
for (uint32_t i = 0; i < name_len; i++) {
napi_value val;
NODE_API_CALL(status, _env, napi_get_element(_env, names, i, &val));
if (status == napi_ok) {
char buffer[MAX_STRING_LEN];
size_t result = 0;
NODE_API_CALL(status, _env, napi_get_value_string_utf8(_env, val, buffer, MAX_STRING_LEN, &result));
if (result > 0) {
allKeys->push_back(buffer);
}
}
}
return true;
}
bool Object::init(napi_env env, napi_value js_object, Class* cls) {
assert(env);
_cls = cls;
_env = env;
_objRef.initWeakref(env, js_object);
if (__objectMap) {
assert(__objectMap->find(this) == __objectMap->end());
__objectMap->emplace(this, nullptr);
}
napi_status status;
return true;
}
bool Object::call(const ValueArray& args, Object* thisObject, Value* rval) {
size_t argc = 0;
std::vector<napi_value> argv;
argv.reserve(10);
argc = args.size();
internal::seToJsArgs(_env, args, &argv);
napi_value return_val;
napi_status status;
assert(isFunction());
napi_value thisObj = thisObject ? thisObject->_getJSObject() : nullptr;
status =
napi_call_function(_env, thisObj, _getJSObject(), argc, argv.data(), &return_val);
if (rval) {
internal::jsToSeValue(return_val, rval);
}
return true;
}
void Object::_setFinalizeCallback(napi_finalize finalizeCb) {
assert(finalizeCb != nullptr);
_finalizeCb = finalizeCb;
}
void Object::setPrivateData(void* data){
assert(_privateData == nullptr);
assert(NativePtrToObjectMap::find(data) == NativePtrToObjectMap::end());
napi_status status;
NativePtrToObjectMap::emplace(data, this);
_privateData = data;
//issue https://github.com/nodejs/node/issues/23999
auto tmpThis = _objRef.getValue(_env);
//_objRef.deleteRef();
napi_ref result = nullptr;
NODE_API_CALL(status, _env,
napi_wrap(_env, tmpThis, data, weakCallback,
(void*)this /* finalize_hint */, &result));
//_objRef.setWeakref(_env, result);
setProperty("__native_ptr__", se::Value(static_cast<long>(reinterpret_cast<uintptr_t>(data))));
}
void* Object::getPrivateData() const{
napi_status status;
void* data;
auto tmpThis = _objRef.getValue(_env);
status = napi_unwrap(_env, tmpThis, &data);
const_cast<Object*>(this)->_privateData = data;
return _privateData;
}
bool Object::attachObject(Object* obj) {
assert(obj);
Object* global = ScriptEngine::getInstance()->getGlobalObject();
Value jsbVal;
if (!global->getProperty("jsb", &jsbVal)) {
return false;
}
Object* jsbObj = jsbVal.toObject();
Value func;
if (!jsbObj->getProperty("registerNativeRef", &func)) {
return false;
}
ValueArray args;
args.push_back(Value(this));
args.push_back(Value(obj));
func.toObject()->call(args, global);
return true;
}
bool Object::detachObject(Object* obj) {
assert(obj);
Object* global = ScriptEngine::getInstance()->getGlobalObject();
Value jsbVal;
if (!global->getProperty("jsb", &jsbVal)) {
return false;
}
Object* jsbObj = jsbVal.toObject();
Value func;
if (!jsbObj->getProperty("unregisterNativeRef", &func)) {
return false;
}
ValueArray args;
args.push_back(Value(this));
args.push_back(Value(obj));
func.toObject()->call(args, global);
return true;
}
std::string Object::toString() const {
std::string ret;
napi_status status;
if (isFunction() || isArray() || isTypedArray()) {
napi_value result;
NODE_API_CALL(status, _env, napi_coerce_to_string(_env, _objRef.getValue(_env), &result));
char buffer[MAX_STRING_LEN];
size_t result_t = 0;
NODE_API_CALL(status, _env, napi_get_value_string_utf8(_env, result, buffer, MAX_STRING_LEN, &result_t));
ret = buffer;
} else if (isArrayBuffer()) {
ret = "[object ArrayBuffer]";
} else {
ret = "[object Object]";
}
return ret;
}
void Object::root() {
napi_status status;
if (_rootCount == 0) {
uint32_t result = 0;
_objRef.incRef(_env);
//NODE_API_CALL(status, _env, napi_reference_ref(_env, _wrapper, &result));
}
++_rootCount;
}
void Object::unroot() {
napi_status status;
if (_rootCount > 0) {
--_rootCount;
if (_rootCount == 0) {
_objRef.decRef(_env);
}
}
}
bool Object::isRooted() const {
return _rootCount > 0;
}
Class* Object::_getClass() const {
return _cls;
}
Object* Object::getObjectWithPtr(void* ptr) {
Object* obj = nullptr;
auto iter = NativePtrToObjectMap::find(ptr);
if (iter != NativePtrToObjectMap::end()) {
obj = iter->second;
obj->incRef();
}
return obj;
}
napi_value Object::_getJSObject() const {
return _objRef.getValue(_env);
}
void Object::weakCallback(napi_env env, void* nativeObject, void* finalizeHint /*finalize_hint*/) {
if (finalizeHint) {
if (nativeObject == nullptr) {
return;
}
void *rawPtr = reinterpret_cast<Object*>(finalizeHint)->_privateData;
Object* seObj = reinterpret_cast<Object*>(finalizeHint);
if (seObj->_onCleaingPrivateData) { //called by cleanPrivateData, not release seObj;
return;
}
if (seObj->_clearMappingInFinalizer && rawPtr != nullptr) {
auto iter = NativePtrToObjectMap::find(rawPtr);
if (iter != NativePtrToObjectMap::end()) {
NativePtrToObjectMap::erase(iter);
} else {
SE_LOGE("not find ptr in NativePtrToObjectMap");
}
}
// TODO: remove test code before releasing.
const char* clsName = seObj->_getClass()->getName();
SE_LOGE("weakCallback class name:%s, ptr:%p", clsName, rawPtr);
if (seObj->_finalizeCb != nullptr) {
seObj->_finalizeCb(env, finalizeHint, finalizeHint);
} else {
assert(seObj->_getClass() != nullptr);
if (seObj->_getClass()->_getFinalizeFunction() != nullptr) {
seObj->_getClass()->_getFinalizeFunction()(env, finalizeHint, finalizeHint);
}
}
seObj->decRef();
}
}
void Object::setup() {
__objectMap = std::make_unique<std::unordered_map<Object*, void*>>();
}
void Object::cleanup() {
void* nativeObj = nullptr;
Object* obj = nullptr;
Class* cls = nullptr;
const auto& nativePtrToObjectMap = NativePtrToObjectMap::instance();
for (const auto& e : nativePtrToObjectMap) {
nativeObj = e.first;
obj = e.second;
if (obj->_finalizeCb != nullptr) {
obj->_finalizeCb(ScriptEngine::getEnv(), nativeObj, nullptr);
} else {
if (obj->_getClass() != nullptr) {
if (obj->_getClass()->_getFinalizeFunction() != nullptr) {
obj->_getClass()->_getFinalizeFunction()(ScriptEngine::getEnv(), nativeObj, nullptr);
}
}
}
obj->decRef();
}
NativePtrToObjectMap::clear();
if (__objectMap) {
for (const auto& e : *__objectMap) {
obj = e.first;
cls = obj->_getClass();
obj->_rootCount = 0;
}
}
__objectMap.reset();
}
Object* Object::createJSONObject(const std::string& jsonStr) {
//not impl
return nullptr;
}
void Object::clearPrivateData(bool clearMapping) {
if (_privateData != nullptr) {
napi_status status;
void* result = nullptr;
auto tmpThis = _objRef.getValue(_env);
_onCleaingPrivateData = true;
if (clearMapping) {
NativePtrToObjectMap::erase(_privateData);
}
NODE_API_CALL(status, _env, napi_remove_wrap(_env, tmpThis, &result));
_privateData = nullptr;
_onCleaingPrivateData = false;
}
}
Object* Object::createUTF8String(const std::string& str) {
napi_status status;
napi_value result;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_string_utf8(ScriptEngine::getEnv(),str.c_str(),NAPI_AUTO_LENGTH,&result));
Object* obj = _createJSObject(ScriptEngine::getEnv(), result, nullptr);
return obj;
}
} // namespace se

View File

@@ -0,0 +1,431 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <cassert>
#include "../RefCounter.hpp"
#include "../Value.hpp"
#include "../config.hpp"
#include "CommonHeader.h"
#include "HelperMacros.h"
namespace se {
class Class;
namespace internal {
struct PrivateData;
}
class ObjectRef {
private:
napi_ref _ref = nullptr;
int _refCounts = 0;
napi_env _env = nullptr;
napi_value _obj = nullptr;
public:
~ObjectRef() {
deleteRef();
}
napi_value getValue(napi_env env) const {
napi_value result;
napi_status status;
NODE_API_CALL(status, env, napi_get_reference_value(env, _ref, &result));
assert(status == napi_ok);
assert(result != nullptr);
return result;
}
void initWeakref(napi_env env, napi_value obj) {
assert(_ref == nullptr);
_obj = obj;
_env = env;
napi_create_reference(env, obj, 0, &_ref);
}
void setWeakref(napi_env env, napi_ref ref) {
assert(_ref == nullptr);
_ref = ref;
}
void initStrongRef(napi_env env, napi_value obj) {
assert(_ref == nullptr);
_refCounts = 1;
_obj = obj;
napi_create_reference(env, obj, _refCounts, &_ref);
_env = env;
}
void incRef(napi_env env) {
assert(_refCounts == 0);
if (_refCounts == 0) {
uint32_t result = 0;
_refCounts = 1;
napi_reference_ref(env, _ref, &result);
}
}
void decRef(napi_env env) {
assert(_refCounts == 1);
uint32_t result = 0;
if (_refCounts > 0) {
_refCounts--;
if (_refCounts == 0) {
napi_reference_unref(env, _ref, &result);
}
}
}
void deleteRef() {
_refCounts = 0;
if (!_ref) {
return;
}
napi_delete_reference(_env, _ref);
_ref = nullptr;
}
};
class Object;
class Object : public RefCounter {
public:
enum class TypedArrayType {
NONE,
INT8,
INT16,
INT32,
UINT8,
UINT8_CLAMPED,
UINT16,
UINT32,
FLOAT32,
FLOAT64
};
using BufferContentsFreeFunc = void (*)(void *contents, size_t byteLength, void *userData);
struct ExternalArrayBufferCallbackParams {
BufferContentsFreeFunc func{nullptr};
void *contents{nullptr};
size_t byteLength{0};
void *userData{0};
};
Object();
~Object();
/**
* @brief Sets a property to an object.
* @param[in] name A utf-8 string containing the property's name.
* @param[in] value A value to be used as the property's value.
* @return true if the property is set successfully, otherwise false.
*/
bool setProperty(const char *name, const Value &data);
inline bool setProperty(const std::string &name, const Value &value) {
return setProperty(name.c_str(), value);
}
/**
* @brief Gets a property from an object.
* @param[in] name A utf-8 string containing the property's name.
* @param[out] value The property's value if object has the property, otherwise the undefined value.
* @return true if object has the property, otherwise false.
*/
bool getProperty(const char *name, Value *data);
inline bool getProperty(const char *name, Value *data, bool cachePropertyName) {
return getProperty(name, data);
}
inline bool getProperty(const std::string &name, Value *value) {
return getProperty(name.c_str(), value);
}
/**
* @brief Delete a property of an object.
* @param[in] name A utf-8 string containing the property's name.
* @return true if the property is deleted successfully, otherwise false.
*/
bool deleteProperty(const char *name);
/**
* @brief Gets an object's private data.
* @return A void* that is the object's private data, if the object has private data, otherwise nullptr.
*/
void* getPrivateData() const;
/**
* @brief Sets a pointer to private data on an object.
* @param[in] data A void* to set as the object's private data.
* @note This method will associate private data with se::Object by std::unordered_map::emplace.
* It's used for search a se::Object via a void* private data.
*/
void setPrivateData(void* data);
/**
* @brief Clears private data of an object.
* @param clearMapping Whether to clear the mapping of native object & se::Object.
*/
void clearPrivateData(bool clearMapping = true);
/**
* @brief Sets whether to clear the mapping of native object & se::Object in finalizer
*/
void setClearMappingInFinalizer(bool v) { _clearMappingInFinalizer = v; }
/**
* @brief Tests whether an object is an array.
* @return true if object is an array, otherwise false.
*/
bool isArray() const;
/**
* @brief Gets array length of an array object.
* @param[out] length The array length to be stored. It's set to 0 if there is an error.
* @return true if succeed, otherwise false.
*/
bool getArrayLength(uint32_t *length) const;
/**
* @brief Gets an element from an array object by numeric index.
* @param[in] index An integer value for index.
* @param[out] data The se::Value to be stored for the element in certain index.
* @return true if succeed, otherwise false.
*/
bool getArrayElement(uint32_t index, Value *data) const;
/**
* @brief Sets an element to an array object by numeric index.
* @param[in] index An integer value for index.
* @param[in] data The se::Value to be set to array with certain index.
* @return true if succeed, otherwise false.
*/
bool setArrayElement(uint32_t index, const Value &data);
/** @brief Tests whether an object is a typed array.
* @return true if object is a typed array, otherwise false.
*/
bool isTypedArray() const;
/** @brief Tests whether an object is a proxy object.
* @return true if object is a proxy object, otherwise false.
*/
bool isProxy() const;
/**
* @brief Gets the type of a typed array object.
* @return The type of a typed array object.
*/
TypedArrayType getTypedArrayType() const;
/**
* @brief Gets backing store of a typed array object.
* @param[out] ptr A temporary pointer to the backing store of a JavaScript Typed Array object.
* @param[out] length The byte length of a JavaScript Typed Array object.
* @return true if succeed, otherwise false.
*/
bool getTypedArrayData(uint8_t **ptr, size_t *length) const;
/**
* @brief Tests whether an object is an array buffer object.
* @return true if object is an array buffer object, otherwise false.
*/
bool isArrayBuffer() const;
/**
* @brief Gets buffer data of an array buffer object.
* @param[out] ptr A pointer to the data buffer that serves as the backing store for a JavaScript Typed Array object.
* @param[out] length The number of bytes in a JavaScript data object.
* @return true if succeed, otherwise false.
*/
bool getArrayBufferData(uint8_t **ptr, size_t *length) const;
/**
* @brief Creates a JavaScript Typed Array Object with specified format from an existing pointer,
if provide a null pointer,then will create a empty JavaScript Typed Array Object.
* @param[in] type The format of typed array.
* @param[in] data A pointer to the byte buffer to be used as the backing store of the Typed Array object.
* @param[in] byteLength The number of bytes pointed to by the parameter bytes.
* @return A JavaScript Typed Array Object whose backing store is the same as the one pointed data, or nullptr if there is an error.
* @note The return value (non-null) has to be released manually.
*/
static Object *createTypedArray(TypedArrayType type, const void *data, size_t byteLength);
static Object *createTypedArrayWithBuffer(TypedArrayType type, const Object *obj);
static Object *createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset);
static Object *createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset, size_t byteLength);
static Object *createExternalArrayBufferObject(void *contents, size_t byteLength, BufferContentsFreeFunc freeFunc, void *freeUserData = nullptr);
/**
* @brief Tests whether an object can be called as a function.
* @return true if object can be called as a function, otherwise false.
*/
bool isFunction() const;
/**
* @brief Defines a function with a native callback for an object.
* @param[in] funcName A utf-8 string containing the function name.
* @param[in] func The native callback triggered by JavaScript code.
* @return true if succeed, otherwise false.
*/
bool defineFunction(const char *funcName, napi_callback func);
/**
* @brief Defines a property with native accessor callbacks for an object.
* @param[in] name A utf-8 string containing the property's name.
* @param[in] getter The native callback for getter.
* @param[in] setter The native callback for setter.
* @return true if succeed, otherwise false.
*/
bool defineProperty(const char *name, napi_callback getter, napi_callback setter);
bool attachObject(Object *obj);
/**
* @brief Detaches an object from current object.
* @param[in] obj The object to be detached.
* @return true if succeed, otherwise false.
* @note The attached object will not be released if current object is not garbage collected.
*/
bool detachObject(Object *obj);
/**
* @brief Calls an object as a function.
* @param[in] args A se::Value array of arguments to pass to the function. Pass se::EmptyValueArray if argumentCount is 0.
* @param[in] thisObject The object to use as "this," or NULL to use the global object as "this."
* @param[out] rval The se::Value that results from calling object as a function, passing nullptr if return value is ignored.
* @return true if object is a function and there isn't any errors, otherwise false.
*/
bool call(const ValueArray &args, Object *thisObject, Value *rval = nullptr);
/**
* @brief Creates a JavaScript Native Binding Object from an existing se::Class instance.
* @param[in] cls The se::Class instance which stores native callback informations.
* @return A JavaScript Native Binding Object, or nullptr if there is an error.
* @note The return value (non-null) has to be released manually.
*/
static Object *createObjectWithClass(Class *cls);
static Object *_createJSObject(napi_env env, napi_value js_object, Class *cls);
/**
* @brief Creates a JavaScript Object like `{} or new Object()`.
* @return A JavaScript Object, or nullptr if there is an error.
* @note The return value (non-null) has to be released manually.
*/
static Object *createPlainObject();
/**
* @brief Creates a JavaScript Array Object like `[] or new Array()`.
* @param[in] length The initical length of array.
* @return A JavaScript Array Object, or nullptr if there is an error.
* @note The return value (non-null) has to be released manually.
*/
static Object *createArrayObject(size_t length);
/**
* @brief Creates a JavaScript Array Buffer object from an existing pointer.
* @param[in] bytes A pointer to the byte buffer to be used as the backing store of the Typed Array object.
* @param[in] byteLength The number of bytes pointed to by the parameter bytes.
* @return A Array Buffer Object whose backing store is the same as the one pointed to data, or nullptr if there is an error.
* @note The return value (non-null) has to be released manually.
*/
static Object *createArrayBufferObject(const void *data, size_t byteLength);
/**
* Gets the Proxy Target object
* @param proxy The JavaScript Proxy object.
* @return The target JavaScript object of the parameter.
*/
static Object *createProxyTarget(se::Object *proxy);
/**
* @brief Roots an object from garbage collection.
* @note Use this method when you want to store an object in a global or on the heap, where the garbage collector will not be able to discover your reference to it.
* An object may be rooted multiple times and must be unrooted an equal number of times before becoming eligible for garbage collection.
*/
void root();
/**
* @brief Unroots an object from garbage collection.
* @note An object may be rooted multiple times and must be unrooted an equal number of times before becoming eligible for garbage collection.
*/
void unroot();
/**
* @brief Tests whether an object is rooted.
* @return true if it has been already rooted, otherwise false.
*/
bool isRooted() const;
/**
* @brief Creates a JavaScript Object from a JSON formatted string.
* @param[in] jsonStr The utf-8 string containing the JSON string to be parsed.
* @return A JavaScript Object containing the parsed value, or nullptr if the input is invalid.
* @note The return value (non-null) has to be released manually.
*/
static Object *createJSONObject(const std::string &jsonStr);
/**
* @brief Gets all property names of an object.
* @param[out] allKeys A string vector to store all property names.
* @return true if succeed, otherwise false.
*/
bool getAllKeys(std::vector<std::string> *allKeys) const;
/**
* @brief Gets a se::Object from an existing native object pointer.
* @param[in] ptr The native object pointer associated with the se::Object
* @return A JavaScript Native Binding Object, or nullptr if there is an error.
* @note The return value (non-null) has to be released manually.
*/
static Object *getObjectWithPtr(void *ptr);
Class * _getClass() const; // NOLINT(readability-identifier-naming)
napi_value _getJSObject() const;
void _setFinalizeCallback(napi_finalize finalizeCb); // NOLINT(readability-identifier-naming)
/**
* @brief Returns the string for describing current object.
* @return The string for describing current object.
*/
std::string toString() const;
bool init(napi_env env, napi_value js_object, Class *cls);
static Object *createUTF8String(const std::string& str);
private:
// Object();
// virtual ~Object();
static void weakCallback(napi_env env, void *nativeObject, void * /*finalize_hint*/);
static void setup();
static void cleanup();
private:
ObjectRef _objRef;
napi_finalize _finalizeCb = nullptr;
bool _clearMappingInFinalizer = true;
void* _privateData = nullptr;
napi_env _env = nullptr;
Class * _cls = nullptr;
uint32_t _rootCount = 0;
bool _onCleaingPrivateData = false;
internal::PrivateData* _internalData;
friend class ScriptEngine;
};
}; // namespace se

View File

@@ -0,0 +1,315 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "ScriptEngine.h"
#include <sstream>
#include "../MappingUtils.hpp"
#include "Class.h"
#include "Utils.h"
#include "CommonHeader.h"
#include <napi/native_api.h>
namespace se {
AutoHandleScope::AutoHandleScope() {
napi_open_handle_scope(ScriptEngine::getEnv(), &_handleScope);
}
AutoHandleScope::~AutoHandleScope() {
napi_close_handle_scope(ScriptEngine::getEnv(), _handleScope);
}
ScriptEngine *gSriptEngineInstance = nullptr;
ScriptEngine::ScriptEngine() {};
ScriptEngine::~ScriptEngine() = default;
void ScriptEngine::setFileOperationDelegate(const FileOperationDelegate &delegate) {
_fileOperationDelegate = delegate;
}
const ScriptEngine::FileOperationDelegate &ScriptEngine::getFileOperationDelegate() const {
return _fileOperationDelegate;
}
ScriptEngine *ScriptEngine::getInstance() {
if (gSriptEngineInstance == nullptr) {
gSriptEngineInstance = new ScriptEngine();
}
return gSriptEngineInstance;
}
void ScriptEngine::destroyInstance() {
if (gSriptEngineInstance) {
gSriptEngineInstance->cleanup();
delete gSriptEngineInstance;
gSriptEngineInstance = nullptr;
}
}
bool ScriptEngine::runScript(const std::string &path, Value *ret /* = nullptr */) {
assert(!path.empty());
napi_status status;
napi_value result = nullptr;
LOGD("napi runScript path=%{public}s.",path.c_str());
//NODE_API_CALL(status, ScriptEngine::getEnv(), napi_run_script_path(ScriptEngine::getEnv(), path.c_str(), &result));
if (ret && result) {
internal::jsToSeValue(result, ret);
}
return false;
}
bool ScriptEngine::evalString(const char *scriptStr, ssize_t length, Value *ret, const char *fileName) {
napi_status status;
napi_value script;
napi_value result;
length = length < 0 ? NAPI_AUTO_LENGTH : length;
status = napi_create_string_utf8(ScriptEngine::getEnv(), scriptStr, length, &script);
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_run_script(ScriptEngine::getEnv(), script, &result));
return true;
}
bool ScriptEngine::init() {
napi_status status;
napi_value result;
for (const auto &hook : _beforeInitHookArray) {
hook();
}
Object::setup();
NativePtrToObjectMap::init();
NonRefNativePtrCreatedByCtorMap::init();
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_global(ScriptEngine::getEnv(), &result));
_globalObj = Object::_createJSObject(ScriptEngine::getEnv(), result, nullptr);
_globalObj->root();
_globalObj->setProperty("window", Value(_globalObj));
_globalObj->setProperty("scriptEngineType", se::Value("napi"));
_isValid = true;
for (const auto &hook : _afterInitHookArray) {
hook();
}
_afterInitHookArray.clear();
return _isValid;
}
Object *ScriptEngine::getGlobalObject() const {
return _globalObj;
}
bool ScriptEngine::start() {
bool ok = true;
if (!init()) {
return false;
}
_startTime = std::chrono::steady_clock::now();
for (auto cb : _permRegisterCallbackArray) {
ok = cb(_globalObj);
assert(ok);
if (!ok) {
break;
}
}
for (auto cb : _registerCallbackArray) {
ok = cb(_globalObj);
assert(ok);
if (!ok) {
break;
}
}
// After ScriptEngine is started, _registerCallbackArray isn't needed. Therefore, clear it here.
_registerCallbackArray.clear();
return ok;
}
void ScriptEngine::cleanup() {
if (!_isValid) {
return;
}
SE_LOGD("ScriptEngine::cleanup begin ...\n");
_isInCleanup = true;
for (const auto &hook : _beforeCleanupHookArray) {
hook();
}
_beforeCleanupHookArray.clear();
SAFE_DEC_REF(_globalObj);
Object::cleanup();
Class::cleanup();
garbageCollect();
_globalObj = nullptr;
_isValid = false;
_registerCallbackArray.clear();
for (const auto &hook : _afterCleanupHookArray) {
hook();
}
_afterCleanupHookArray.clear();
_isInCleanup = false;
NativePtrToObjectMap::destroy();
SE_LOGD("ScriptEngine::cleanup end ...\n");
}
void ScriptEngine::addBeforeCleanupHook(const std::function<void()> &hook) {
_beforeCleanupHookArray.push_back(hook);
return;
}
void ScriptEngine::addBeforeInitHook(const std::function<void()> &hook) {
_beforeInitHookArray.push_back(hook);
}
void ScriptEngine::addAfterCleanupHook(const std::function<void()> &hook) {
_afterCleanupHookArray.push_back(hook);
return;
}
void ScriptEngine::addRegisterCallback(RegisterCallback cb) {
assert(std::find(_registerCallbackArray.begin(), _registerCallbackArray.end(), cb) == _registerCallbackArray.end());
_registerCallbackArray.push_back(cb);
}
napi_env ScriptEngine::getEnv() {
return getInstance()->_env;
}
void ScriptEngine::setEnv(napi_env env) {
getInstance()->_env = env;
}
// void ScriptEngine::addPermanentRegisterCallback(RegisterCallback cb) {
// if (std::find(_permRegisterCallbackArray.begin(), _permRegisterCallbackArray.end(), cb) == _permRegisterCallbackArray.end()) {
// _permRegisterCallbackArray.push_back(cb);
// }
// }
void ScriptEngine::setExceptionCallback(const ExceptionCallback &cb) {
//not impl
return;
}
const std::chrono::steady_clock::time_point &ScriptEngine::getStartTime() const {
return _startTime;
}
bool ScriptEngine::isValid() const {
return _isValid;
}
void ScriptEngine::enableDebugger(const std::string &serverAddr, uint32_t port, bool isWait) {
//not impl
return;
}
bool ScriptEngine::saveByteCodeToFile(const std::string &path, const std::string &pathBc) {
//not impl
return true;
}
void ScriptEngine::clearException() {
//not impl
return;
}
void ScriptEngine::garbageCollect() {
//not impl
return;
}
bool ScriptEngine::isGarbageCollecting() const {
return _isGarbageCollecting;
}
void ScriptEngine::_setGarbageCollecting(bool isGarbageCollecting) { //NOLINT(readability-identifier-naming)
_isGarbageCollecting = isGarbageCollecting;
}
void ScriptEngine::setJSExceptionCallback(const ExceptionCallback &cb) {
//not impl
return;
}
void ScriptEngine::addAfterInitHook(const std::function<void()> &hook) {
_afterInitHookArray.push_back(hook);
return;
}
std::string ScriptEngine::getCurrentStackTrace() {
//not impl
return "";
}
void ScriptEngine::_setNeedCallConstructor(bool need) {
_isneedCallConstructor = need;
}
bool ScriptEngine::_needCallConstructor() {
return _isneedCallConstructor;
}
bool ScriptEngine::callFunction(Object *targetObj, const char *funcName, uint32_t argc, Value *args, Value *rval) {
Value objFunc;
if (!targetObj->getProperty(funcName, &objFunc)) {
return false;
}
ValueArray argv;
for (size_t i = 0; i < argc; ++i) {
argv.push_back(args[i]);
}
objFunc.toObject()->call(argv, targetObj, rval);
return true;
}
void ScriptEngine::handlePromiseExceptions() {
//not impl
assert(true);
return;
}
void ScriptEngine::mainLoopUpdate() {
// empty implementation
}
void ScriptEngine::throwException(const std::string &errorMessage) {
napi_status status;
NODE_API_CALL_RETURN_VOID(getEnv(), napi_throw_error(getEnv(), nullptr, errorMessage.c_str()));
}
}; // namespace se

View File

@@ -0,0 +1,307 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <functional>
#include <thread>
#include "../Value.hpp"
#include "../config.hpp"
#include "CommonHeader.h"
using HandleScope = napi_handle_scope;
namespace se {
class AutoHandleScope {
public:
// This interface needs to be implemented in NAPI, similar to V8.
// Ref:https://nodejs.org/docs/latest-v17.x/api/n-api.html#object-lifetime-management
AutoHandleScope();
~AutoHandleScope();
private:
HandleScope _handleScope;
};
// using RegisterCallback = bool (*)(Object *);
using ExceptionCallback = std::function<void(const char *, const char *, const char *)>; // location, message, stack
class ScriptEngine {
public:
/**
* Delegate class for file operation
*/
class FileOperationDelegate {
public:
FileOperationDelegate()
: onGetDataFromFile(nullptr),
onGetStringFromFile(nullptr),
onCheckFileExist(nullptr),
onGetFullPath(nullptr) {}
/**
* @brief Tests whether delegate is valid.
*/
bool isValid() const {
return onGetDataFromFile != nullptr && onGetStringFromFile != nullptr && onCheckFileExist != nullptr && onGetFullPath != nullptr;
}
// path, buffer, buffer size
std::function<void(const std::string &, const std::function<void(const uint8_t *, size_t)> &)> onGetDataFromFile;
// path, return file string content.
std::function<std::string(const std::string &)> onGetStringFromFile;
// path
std::function<bool(const std::string &)> onCheckFileExist;
// path, return full path
std::function<std::string(const std::string &)> onGetFullPath;
};
ScriptEngine();
~ScriptEngine();
/**
* @brief Sets the delegate for file operation.
* @param delegate[in] The delegate instance for file operation.
*/
void setFileOperationDelegate(const FileOperationDelegate &delegate);
/**
* @brief Compile script file into v8::ScriptCompiler::CachedData and save to file.
* @param[in] path The path of script file.
* @param[in] pathBc The location where bytecode file should be written to. The path should be ends with ".bc", which indicates a bytecode file.
* @return true if succeed, otherwise false.
*/
bool saveByteCodeToFile(const std::string &path, const std::string &pathBc);
/**
* @brief Gets the delegate for file operation.
* @return The delegate for file operation
*/
const FileOperationDelegate &getFileOperationDelegate() const;
static ScriptEngine *getInstance();
/**
* @brief Destroys the instance of script engine.
*/
static void destroyInstance();
/**
* @brief Clears all exceptions.
*/
void clearException();
/**
* @brief Sets the callback function while an exception is fired in JS.
* @param[in] cb The callback function to notify that an exception is fired.
*/
void setJSExceptionCallback(const ExceptionCallback &cb);
/**
* @brief Sets the callback function while an exception is fired.
* @param[in] cb The callback function to notify that an exception is fired.
*/
void setExceptionCallback(const ExceptionCallback &cb);
/**
* @brief Grab a snapshot of the current JavaScript execution stack.
* @return current stack trace string
*/
std::string getCurrentStackTrace();
/**
* @brief Executes a utf-8 string buffer which contains JavaScript code.
* @param[in] script A utf-8 string buffer, if it isn't null-terminated, parameter `length` should be assigned and > 0.
* @param[in] length The length of parameter `scriptStr`, it will be set to string length internally if passing < 0 and parameter `scriptStr` is null-terminated.
* @param[in] ret The se::Value that results from evaluating script. Passing nullptr if you don't care about the result.
* @param[in] fileName A string containing a URL for the script's source file. This is used by debuggers and when reporting exceptions. Pass NULL if you do not care to include source file information.
* @return true if succeed, otherwise false.
*/
bool evalString(const char *script, ssize_t length = -1, Value *ret = nullptr, const char *fileName = nullptr);
/**
* @brief Adds a callback for registering a native binding module, which will not be removed by ScriptEngine::cleanup.
* @param[in] cb A callback for registering a native binding module.
* @note This method just add a callback to a vector, callbacks is invoked in `start` method.
*/
// void addPermanentRegisterCallback(RegisterCallback cb);
/**
* @brief Starts the script engine.
* @return true if succeed, otherwise false.
* @note This method will invoke all callbacks of native binding modules by the order of registration.
*/
bool start();
/**
* @brief Initializes script engine.
* @return true if succeed, otherwise false.
* @note This method will create JavaScript context and global object.
*/
bool init();
/**
* @brief Adds a hook function before initializing script engine.
* @param[in] hook A hook function to be invoked before initializing script engine.
* @note Multiple hook functions could be added, they will be invoked by the order of adding.
*/
void addBeforeInitHook(const std::function<void()> &hook);
/**
* @brief Adds a hook function after initializing script engine.
* @param[in] hook A hook function to be invoked before initializing script engine.
* @note Multiple hook functions could be added, they will be invoked by the order of adding.
*/
void addAfterInitHook(const std::function<void()> &hook);
/**
* @brief Cleanups script engine.
* @note This method will removes all objects in JavaScript VM even whose are rooted, then shutdown JavaScript VMf.
*/
void cleanup();
/**
* @brief Adds a hook function before cleanuping script engine.
* @param[in] hook A hook function to be invoked before cleanuping script engine.
* @note Multiple hook functions could be added, they will be invoked by the order of adding.
*/
void addBeforeCleanupHook(const std::function<void()> &hook);
/**
* @brief Adds a hook function after cleanuping script engine.
* @param[in] hook A hook function to be invoked after cleanuping script engine.
* @note Multiple hook functions could be added, they will be invoked by the order of adding.
*/
void addAfterCleanupHook(const std::function<void()> &hook);
/**
* @brief Gets the global object of JavaScript VM.
* @return The se::Object stores the global JavaScript object.
*/
Object *getGlobalObject() const;
typedef bool (*RegisterCallback)(Object*);
static napi_env getEnv();
static void setEnv(napi_env env);
/**
* @brief Adds a callback for registering a native binding module.
* @param[in] cb A callback for registering a native binding module.
* @note This method just add a callback to a vector, callbacks is invoked in `start` method.
*/
void addRegisterCallback(RegisterCallback cb);
const std::chrono::steady_clock::time_point &getStartTime() const;
/**
* @brief Tests whether script engine is doing garbage collection.
* @return true if it's in garbage collection, otherwise false.
*/
bool isGarbageCollecting() const;
/**
* @brief Performs a JavaScript garbage collection.
*/
void garbageCollect();
/**
* @brief Tests whether script engine is being cleaned up.
* @return true if it's in cleaning up, otherwise false.
*/
bool isInCleanup() const { return _isInCleanup; }
/**
* @brief Executes a file which contains JavaScript code.
* @param[in] path Script file path.
* @param[in] ret The se::Value that results from evaluating script. Passing nullptr if you don't care about the result.
* @return true if succeed, otherwise false.
*/
bool runScript(const std::string &path, Value *ret = nullptr);
/**
* @brief Tests whether script engine is valid.
* @return true if it's valid, otherwise false.
*/
bool isValid() const;
/**
* @brief Enables JavaScript debugger
* @param[in] serverAddr The address of debugger server.
* @param[in] isWait Whether wait debugger attach when loading.
*/
void enableDebugger(const std::string &serverAddr, uint32_t port, bool isWait = false);
/**
* @brief Tests whether JavaScript debugger is enabled
* @return true if JavaScript debugger is enabled, otherwise false.
*/
bool isDebuggerEnabled() const;
/**
* @brief Main loop update trigger, it's need to invoked in main thread every frame.
*/
void mainLoopUpdate();
bool runByteCodeFile(const std::string &pathBc, Value *ret /* = nullptr */);
/**
* @brief Throw JS exception
*/
void throwException(const std::string &errorMessage);
/**
* @brief for napi_new_instance, skip constructor.
*/
void _setNeedCallConstructor(bool need);
/**
* @brief for napi_new_instance, skip constructor.
*/
bool _needCallConstructor();
/**
* @brief Fast version of call script function, faster than Object::call
*/
bool callFunction(Object *targetObj, const char *funcName, uint32_t argc, Value *args, Value *rval = nullptr);
void _setGarbageCollecting(bool isGarbageCollecting); // NOLINT(readability-identifier-naming)
void handlePromiseExceptions();
private:
FileOperationDelegate _fileOperationDelegate;
std::vector<RegisterCallback> _registerCallbackArray;
std::vector<RegisterCallback> _permRegisterCallbackArray;
std::vector<std::function<void()>> _beforeInitHookArray;
std::vector<std::function<void()>> _afterInitHookArray;
std::vector<std::function<void()>> _beforeCleanupHookArray;
std::vector<std::function<void()>> _afterCleanupHookArray;
Object * _globalObj = nullptr;
napi_env _env = nullptr;
bool _isValid{false};
bool _isGarbageCollecting{false};
bool _isInCleanup{false};
bool _isErrorHandleWorking{false};
bool _isneedCallConstructor{true};
std::chrono::steady_clock::time_point _startTime;
};
}; // namespace se

View File

@@ -0,0 +1,32 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "Class.h"
#include "HelperMacros.h"
#include "Object.h"
#include "ScriptEngine.h"
#include "Utils.h"

View File

@@ -0,0 +1,195 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "Utils.h"
#include "CommonHeader.h"
#include "ScriptEngine.h"
#include "Class.h"
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
#define MAX_STRING_LENS 1024
namespace se {
namespace internal {
void jsToSeValue(const target_value& value, Value* v) {
assert(v != nullptr);
napi_status status;
napi_valuetype valType;
int64_t iRet = 0;
double dRet = 0.0;
bool bRet = false;
bool lossless = false;
size_t len = 0;
void* privateObjPtr = nullptr;
void* nativePtr = nullptr;
void* privateData = nullptr;
Object* obj = nullptr;
if (!value) {
valType = napi_valuetype::napi_undefined;
}else {
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_typeof(ScriptEngine::getEnv(), value, &valType));
}
switch (valType) {
case napi_valuetype::napi_undefined:
v->setUndefined();
break;
case napi_valuetype::napi_null:
v->setNull();
break;
case napi_valuetype::napi_number:
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_double(ScriptEngine::getEnv(), value, &dRet));
if (status == napi_ok) {
v->setDouble(dRet);
} else {
v->setUndefined();
}
break;
case napi_valuetype::napi_bigint:
//NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_bigint_int64(ScriptEngine::getEnv(), value, &iRet, &lossless));
if (lossless) {
v->setInt64(iRet);
} else {
v->setUndefined();
}
break;
case napi_valuetype::napi_string:
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_string_utf8(ScriptEngine::getEnv(), value, nullptr, 0, &len));
if (status == napi_ok) {
std::string valueStr;
len += 1;
valueStr.resize(len);
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_string_utf8(ScriptEngine::getEnv(), value, const_cast<char*>(valueStr.data()), valueStr.size(), &len));
if (valueStr.length() != len) {
valueStr.resize(len);
}
v->setString(valueStr);
} else {
v->setUndefined();
}
break;
case napi_valuetype::napi_boolean:
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_value_bool(ScriptEngine::getEnv(), value, &bRet));
if (status == napi_ok) {
v->setBoolean(bRet);
} else {
v->setUndefined();
}
break;
case napi_valuetype::napi_object:
case napi_valuetype::napi_function:
status = napi_unwrap(ScriptEngine::getEnv(), value, &privateData);
if (privateData) {
obj = Object::getObjectWithPtr(privateData);
}
if (obj == nullptr) {
obj = Object::_createJSObject(ScriptEngine::getEnv(), value, nullptr);
}
if (obj) {
v->setObject(obj, true);
obj->decRef();
} else {
v->setUndefined();
}
break;
default:
break;
}
}
void jsToSeArgs(size_t argc, target_value* argv, ValueArray* outArr) {
assert(outArr != nullptr);
for (int i = 0; i < argc; i++) {
Value v;
jsToSeValue(argv[i], &v);
outArr->push_back(v);
}
}
bool seToJsValue(const Value& v, target_value* outJsVal) {
assert(outJsVal != nullptr);
bool ret = false;
napi_status status = napi_ok;
switch (v.getType()) {
case Value::Type::Number:
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_double(ScriptEngine::getEnv(), v.toDouble(), outJsVal));
ret = (status == napi_ok);
break;
case Value::Type::String: {
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_string_utf8(ScriptEngine::getEnv(), v.toString().c_str(), v.toString().length(), outJsVal));
ret = (status == napi_ok);
} break;
case Value::Type::Boolean:
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_boolean(ScriptEngine::getEnv(), v.toBoolean(), outJsVal));
ret = (status == napi_ok);
break;
case Value::Type::Object:
*outJsVal = v.toObject()->_getJSObject();
ret = (outJsVal != nullptr);
break;
case Value::Type::Null:
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_null(ScriptEngine::getEnv(), outJsVal));
ret = (status == napi_ok);
break;
case Value::Type::Undefined:
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_get_undefined(ScriptEngine::getEnv(), outJsVal));
ret = (status == napi_ok);
break;
case Value::Type::BigInt:
//NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_bigint_int64(ScriptEngine::getEnv(), v.toInt64(), outJsVal));
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_double(ScriptEngine::getEnv(), v.toDouble(), outJsVal));
ret = (status == napi_ok);
break;
default:
assert(false);
break;
}
//LOGI("type :%d", v.getType());
return ret;
}
void seToJsArgs(napi_env env, const ValueArray& args, std::vector<target_value>* outArr) {
assert(outArr != nullptr);
for (const auto& data : args) {
napi_value jsval;
seToJsValue(data, &jsval);
outArr->push_back(jsval);
}
}
bool setReturnValue(const Value& data, target_value& argv) {
if (data.getType() == Value::Type::BigInt) {
// TODO: fix 'TypeError: Cannot mix BigInt and other types, use explicit conversions' for spine & dragonbones
napi_status status;
NODE_API_CALL(status, ScriptEngine::getEnv(), napi_create_double(ScriptEngine::getEnv(), data.toDouble(), &argv));
return true;
}
return seToJsValue(data, &argv);
}
} // namespace internal
}; // namespace se

View File

@@ -0,0 +1,46 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "../config.hpp"
#include "Object.h"
namespace se {
namespace internal {
using target_value = napi_value;
struct PrivateData {
void * data;
Object *seObj;
};
bool setReturnValue(const Value &data, target_value &argv);
void jsToSeValue(const target_value &value, Value *v);
void jsToSeArgs(size_t argc, target_value *argv, ValueArray *outArr);
bool seToJsValue(const Value &v, target_value *jsval);
void seToJsArgs(napi_env env, const ValueArray &args, std::vector<target_value> *outArr);
} // namespace internal
} // namespace se

View File

@@ -0,0 +1,115 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#ifndef FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H
#define FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H
#define DEPRECATED __attribute__((__deprecated__))
#ifndef NAPI_VERSION
#define NAPI_VERSION 8
#endif
#define NAPI_RETVAL_NOTHING
#define GET_AND_THROW_LAST_ERROR(env) \
do { \
const napi_extended_error_info* errorInfo = nullptr; \
napi_get_last_error_info((env), &errorInfo); \
bool isPending = false; \
napi_is_exception_pending((env), &isPending); \
if (!isPending && errorInfo != nullptr) { \
const char* errorMessage = \
errorInfo->error_message != nullptr ? errorInfo->error_message : "empty error message"; \
napi_throw_error((env), nullptr, errorMessage); \
} \
} while (0)
#define NAPI_ASSERT_BASE(env, assertion, message, retVal) \
do { \
if (!(assertion)) { \
napi_throw_error((env), nullptr, "assertion (" #assertion ") failed: " message); \
return retVal; \
} \
} while (0)
#define NAPI_ASSERT(env, assertion, message) NAPI_ASSERT_BASE(env, assertion, message, nullptr)
#define NAPI_ASSERT_RETURN_VOID(env, assertion, message) NAPI_ASSERT_BASE(env, assertion, message, NAPI_RETVAL_NOTHING)
#define NAPI_CALL_BASE(env, theCall, retVal) \
do { \
if ((theCall) != napi_ok) { \
GET_AND_THROW_LAST_ERROR((env)); \
return retVal; \
} \
} while (0)
#define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr)
#define NAPI_CALL_RETURN_VOID(env, theCall) NAPI_CALL_BASE(env, theCall, NAPI_RETVAL_NOTHING)
#define DECLARE_NAPI_PROPERTY(name, val) \
{ \
(name), nullptr, nullptr, nullptr, nullptr, val, napi_default, nullptr \
}
#define DECLARE_NAPI_STATIC_PROPERTY(name, val) \
{ \
(name), nullptr, nullptr, nullptr, nullptr, val, napi_static, nullptr \
}
#define DECLARE_NAPI_FUNCTION(name, func) \
{ \
(name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \
}
#define DECLARE_NAPI_FUNCTION_WITH_DATA(name, func, data) \
{ \
(name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, data \
}
#define DECLARE_NAPI_STATIC_FUNCTION(name, func) \
{ \
(name), nullptr, (func), nullptr, nullptr, nullptr, napi_static, nullptr \
}
#define DECLARE_NAPI_GETTER(name, getter) \
{ \
(name), nullptr, nullptr, (getter), nullptr, nullptr, napi_default, nullptr \
}
#define DECLARE_NAPI_SETTER(name, setter) \
{ \
(name), nullptr, nullptr, nullptr, (setter), nullptr, napi_default, nullptr \
}
#define DECLARE_NAPI_GETTER_SETTER(name, getter, setter) \
{ \
(name), nullptr, nullptr, (getter), (setter), nullptr, napi_default, nullptr \
}
#endif /* FOUNDATION_ACE_NAPI_INTERFACES_KITS_NAPI_NATIVE_COMMON_H */