no message
This commit is contained in:
63
cocos/bindings/jswrapper/sm/Base.h
Normal file
63
cocos/bindings/jswrapper/sm/Base.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef UINT64_C
|
||||
#define UINT64_C(value) __CONCAT(value, ULL)
|
||||
#endif
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "js/Array.h"
|
||||
#include "js/ArrayBuffer.h"
|
||||
#include "js/BigInt.h"
|
||||
#include "js/BuildId.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/ContextOptions.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "js/Equality.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/Initialization.h"
|
||||
#include "js/JSON.h"
|
||||
#include "js/LocaleSensitive.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/Warnings.h"
|
||||
#include "js/experimental/TypedData.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "../PrivateObject.h"
|
||||
#include "HelperMacros.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "base/std/container/string.h"
|
||||
242
cocos/bindings/jswrapper/sm/Class.cpp
Normal file
242
cocos/bindings/jswrapper/sm/Class.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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 "Class.h"
|
||||
#include "Object.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
|
||||
namespace se {
|
||||
|
||||
// --- Global Lookup for Constructor Functions
|
||||
|
||||
namespace {
|
||||
// std::unordered_map<std::string, Class *> __clsMap;
|
||||
JSContext *__cx = nullptr;
|
||||
|
||||
bool empty_constructor(JSContext *cx, uint32_t argc, JS::Value *vp) {
|
||||
assert(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
ccstd::vector<Class *> __allClasses;
|
||||
|
||||
} // namespace
|
||||
|
||||
Class::Class()
|
||||
: _parent(nullptr),
|
||||
_proto(nullptr),
|
||||
_parentProto(nullptr),
|
||||
_ctor(nullptr),
|
||||
_finalizeOp(nullptr) {
|
||||
memset(&_jsCls, 0, sizeof(_jsCls));
|
||||
memset(&_classOps, 0, sizeof(_classOps));
|
||||
|
||||
__allClasses.push_back(this);
|
||||
}
|
||||
|
||||
Class::~Class() {
|
||||
}
|
||||
|
||||
Class *Class::create(const char *className, Object *obj, Object *parentProto, JSNative ctor) {
|
||||
Class *cls = ccnew Class();
|
||||
if (cls != nullptr && !cls->init(className, obj, parentProto, ctor)) {
|
||||
delete cls;
|
||||
cls = nullptr;
|
||||
}
|
||||
return cls;
|
||||
}
|
||||
|
||||
Class *Class::create(const std::initializer_list<const char *> &classPath, se::Object *parent, Object *parentProto, JSNative 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);
|
||||
CC_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 char *clsName, Object *parent, Object *parentProto, JSNative ctor) {
|
||||
_name = clsName;
|
||||
|
||||
_parent = parent;
|
||||
if (_parent != nullptr)
|
||||
_parent->incRef();
|
||||
|
||||
_parentProto = parentProto;
|
||||
if (_parentProto != nullptr)
|
||||
_parentProto->incRef();
|
||||
|
||||
_ctor = ctor;
|
||||
if (_ctor == nullptr) {
|
||||
_ctor = empty_constructor;
|
||||
}
|
||||
|
||||
// SE_LOGD("Class init ( %s ) ...\n", clsName);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Class::destroy() {
|
||||
SAFE_DEC_REF(_parent);
|
||||
SAFE_DEC_REF(_proto);
|
||||
SAFE_DEC_REF(_parentProto);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void Class::onTraceCallback(JSTracer *trc, JSObject *obj) {
|
||||
auto *seObj = reinterpret_cast<Object *>(internal::SE_JS_GetPrivate(obj, 1));
|
||||
if (seObj != nullptr) {
|
||||
JS::TraceEdge(trc, &seObj->_heap, "seObj");
|
||||
}
|
||||
}
|
||||
|
||||
bool Class::install() {
|
||||
// assert(__clsMap.find(_name) == __clsMap.end());
|
||||
//
|
||||
// __clsMap.emplace(_name, this);
|
||||
|
||||
_jsCls.name = _name;
|
||||
_jsCls.flags = JSCLASS_USERBIT1 | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_FOREGROUND_FINALIZE; //IDEA: Use JSCLASS_BACKGROUND_FINALIZE to improve GC performance
|
||||
if (_finalizeOp != nullptr) {
|
||||
_classOps.finalize = _finalizeOp;
|
||||
} else {
|
||||
_classOps.finalize = [](JSFreeOp *fop, JSObject *obj) {};
|
||||
}
|
||||
|
||||
_classOps.trace = Class::onTraceCallback;
|
||||
|
||||
_jsCls.cOps = &_classOps;
|
||||
|
||||
JSObject *parentObj = _parentProto != nullptr ? _parentProto->_getJSObject() : nullptr;
|
||||
JS::RootedObject parentProto(__cx, parentObj);
|
||||
JS::RootedObject parent(__cx, _parent->_getJSObject());
|
||||
|
||||
_funcs.push_back(JS_FS_END);
|
||||
_properties.push_back(JS_PS_END);
|
||||
_staticFuncs.push_back(JS_FS_END);
|
||||
_staticProperties.push_back(JS_PS_END);
|
||||
|
||||
JS::RootedObject jsobj(__cx, JS_InitClass(__cx, parent, parentProto, &_jsCls, _ctor, 0, _properties.data(), _funcs.data(), _staticProperties.data(), _staticFuncs.data()));
|
||||
if (jsobj != nullptr) {
|
||||
_proto = Object::_createJSObject(nullptr, jsobj);
|
||||
// SE_LOGD("_proto: %p, name: %s\n", _proto, _name);
|
||||
_proto->root();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Class::defineFunction(const char *name, JSNative func) {
|
||||
JSFunctionSpec cb = JS_FN(name, func, 0, JSPROP_ENUMERATE);
|
||||
_funcs.push_back(cb);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Class::defineProperty(const char *name, JSNative getter, JSNative setter) {
|
||||
JSPropertySpec property = JS_PSGS(name, getter, setter, JSPROP_ENUMERATE);
|
||||
_properties.push_back(property);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Class::defineProperty(const std::initializer_list<const char *> &names, JSNative getter, JSNative setter) {
|
||||
bool ret = true;
|
||||
for (const auto *name : names) {
|
||||
ret &= defineProperty(name, getter, setter);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Class::defineStaticFunction(const char *name, JSNative func) {
|
||||
JSFunctionSpec cb = JS_FN(name, func, 0, JSPROP_ENUMERATE);
|
||||
_staticFuncs.push_back(cb);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Class::defineStaticProperty(const char *name, JSNative getter, JSNative setter) {
|
||||
JSPropertySpec property = JS_PSGS(name, getter, setter, JSPROP_ENUMERATE);
|
||||
_staticProperties.push_back(property);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Class::defineFinalizeFunction(JSFinalizeOp func) {
|
||||
_finalizeOp = func;
|
||||
return true;
|
||||
}
|
||||
|
||||
// JSObject* Class::_createJSObject(const std::string &clsName, Class** outCls)
|
||||
// {
|
||||
// auto iter = __clsMap.find(clsName);
|
||||
// if (iter == __clsMap.end())
|
||||
// {
|
||||
// *outCls = nullptr;
|
||||
// return nullptr;
|
||||
// }
|
||||
//
|
||||
// Class* thiz = iter->second;
|
||||
// JS::RootedObject obj(__cx, _createJSObjectWithClass(thiz));
|
||||
// *outCls = thiz;
|
||||
// return obj;
|
||||
// }
|
||||
|
||||
void Class::_createJSObjectWithClass(Class *cls, JS::MutableHandleObject outObj) {
|
||||
JSObject *proto = cls->_proto != nullptr ? cls->_proto->_getJSObject() : nullptr;
|
||||
JS::RootedObject jsProto(__cx, proto);
|
||||
outObj.set(JS_NewObjectWithGivenProto(__cx, &cls->_jsCls, jsProto));
|
||||
}
|
||||
|
||||
void Class::setContext(JSContext *cx) {
|
||||
__cx = cx;
|
||||
}
|
||||
|
||||
Object *Class::getProto() {
|
||||
return _proto;
|
||||
}
|
||||
|
||||
JSFinalizeOp Class::_getFinalizeCb() const {
|
||||
return _finalizeOp;
|
||||
}
|
||||
|
||||
void Class::cleanup() {
|
||||
for (auto cls : __allClasses) {
|
||||
cls->destroy();
|
||||
}
|
||||
|
||||
se::ScriptEngine::getInstance()->addAfterCleanupHook([]() {
|
||||
for (auto cls : __allClasses) {
|
||||
delete cls;
|
||||
}
|
||||
__allClasses.clear();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace se
|
||||
|
||||
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
157
cocos/bindings/jswrapper/sm/Class.h
Normal file
157
cocos/bindings/jswrapper/sm/Class.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
|
||||
#include "Base.h"
|
||||
|
||||
namespace se {
|
||||
|
||||
class Object;
|
||||
|
||||
/**
|
||||
* se::Class represents a definition of how to create a native binding object.
|
||||
*/
|
||||
class Class final {
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a class used for creating relevant native binding objects.
|
||||
* @param[in] className A null-terminated UTF8 string containing the class's name.
|
||||
* @param[in] obj The object that current class proto object attaches to. Should not be nullptr.
|
||||
* @param[in] parentProto The parent proto object that current class inherits from. Passing nullptr means a new class has no parent.
|
||||
* @param[in] ctor A callback to invoke when your constructor is used in a 'new' expression. Pass nullptr to use the default object constructor.
|
||||
* @return A class instance used for creating relevant native binding objects.
|
||||
* @note Don't need to delete the pointer return by this method, it's managed internally.
|
||||
*/
|
||||
static Class *create(const char *className, Object *obj, Object *parentProto, JSNative ctor);
|
||||
static Class *create(const std::initializer_list<const char *> &classPath, se::Object *parent, Object *parentProto, JSNative ctor);
|
||||
|
||||
/**
|
||||
* @brief Defines a member function with a callback. Each objects created by class will have this function property.
|
||||
* @param[in] name A null-terminated UTF8 string containing the function name.
|
||||
* @param[in] func A callback to invoke when the property is called as a function.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool defineFunction(const char *name, JSNative func);
|
||||
|
||||
/**
|
||||
* @brief Defines a property with accessor callbacks. Each objects created by class will have this property.
|
||||
* @param[in] name A null-terminated UTF8 string containing the property name.
|
||||
* @param[in] getter A callback to invoke when the property is read.
|
||||
* @param[in] setter A callback to invoke when the property is set.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool defineProperty(const char *name, JSNative getter, JSNative setter);
|
||||
bool defineProperty(const std::initializer_list<const char *> &names, JSNative getter, JSNative setter);
|
||||
|
||||
/**
|
||||
* @brief Defines a static function with a callback. Only JavaScript constructor object will have this function.
|
||||
* @param[in] name A null-terminated UTF8 string containing the function name.
|
||||
* @param[in] func A callback to invoke when the constructor's property is called as a function.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool defineStaticFunction(const char *name, JSNative func);
|
||||
|
||||
/**
|
||||
* @brief Defines a static property with accessor callbacks. Only JavaScript constructor object will have this property.
|
||||
* @param[in] name A null-terminated UTF8 string containing the property name.
|
||||
* @param[in] getter A callback to invoke when the constructor's property is read.
|
||||
* @param[in] setter A callback to invoke when the constructor's property is set.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool defineStaticProperty(const char *name, JSNative getter, JSNative setter);
|
||||
|
||||
/**
|
||||
* @brief Defines the finalize function with a callback.
|
||||
* @param[in] func The callback to invoke when a JavaScript object is garbage collected.
|
||||
* @return true if succeed, otherwise false.
|
||||
*/
|
||||
bool defineFinalizeFunction(JSFinalizeOp func);
|
||||
|
||||
/**
|
||||
* @brief Installs class to JavaScript VM.
|
||||
* @return true if succeed, otherwise false.
|
||||
* @note After this method, an object could be created by `var foo = new Foo();`.
|
||||
*/
|
||||
bool install();
|
||||
|
||||
/**
|
||||
* @brief Gets the proto object of this class.
|
||||
* @return The proto object of this class.
|
||||
* @note Don't need to be released in user code.
|
||||
*/
|
||||
Object *getProto();
|
||||
|
||||
/**
|
||||
* @brief Gets the class name.
|
||||
* @return The class name.
|
||||
*/
|
||||
const char *getName() const { return _name; }
|
||||
|
||||
// Private API used in wrapper
|
||||
JSFinalizeOp _getFinalizeCb() const;
|
||||
//
|
||||
private:
|
||||
Class();
|
||||
~Class();
|
||||
|
||||
bool init(const char *clsName, Object *obj, Object *parentProto, JSNative ctor);
|
||||
void destroy();
|
||||
|
||||
// static JSObject* _createJSObject(const std::string &clsName, Class** outCls);
|
||||
static void _createJSObjectWithClass(Class *cls, JS::MutableHandleObject outObj);
|
||||
|
||||
static void setContext(JSContext *cx);
|
||||
static void cleanup();
|
||||
|
||||
static void onTraceCallback(JSTracer *trc, JSObject *obj);
|
||||
|
||||
const char *_name;
|
||||
Object *_parent;
|
||||
Object *_proto;
|
||||
Object *_parentProto;
|
||||
|
||||
JSNative _ctor;
|
||||
|
||||
JSClass _jsCls;
|
||||
JSClassOps _classOps;
|
||||
|
||||
ccstd::vector<JSFunctionSpec> _funcs;
|
||||
ccstd::vector<JSFunctionSpec> _staticFuncs;
|
||||
ccstd::vector<JSPropertySpec> _properties;
|
||||
ccstd::vector<JSPropertySpec> _staticProperties;
|
||||
JSFinalizeOp _finalizeOp;
|
||||
|
||||
friend class ScriptEngine;
|
||||
friend class Object;
|
||||
};
|
||||
|
||||
} // namespace se
|
||||
|
||||
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
81
cocos/bindings/jswrapper/sm/HelperMacros.cpp
Normal file
81
cocos/bindings/jswrapper/sm/HelperMacros.cpp
Normal 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 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"
|
||||
|
||||
#if defined(RECORD_JSB_INVOKING)
|
||||
|
||||
namespace {
|
||||
bool cmp(const std::pair<const char *, std::tuple<int, uint64_t>> &a, const std::pair<const char *, std::tuple<int, uint64_t>> &b) {
|
||||
return std::get<1>(a.second) > std::get<1>(b.second);
|
||||
}
|
||||
unsigned int __jsbInvocationCount; // NOLINT(readability-identifier-naming)
|
||||
ccstd::unordered_map<char const *, std::tuple<int, uint64_t>> __jsbFunctionInvokedRecords; // NOLINT(readability-identifier-naming)
|
||||
} // namespace
|
||||
|
||||
JsbInvokeScopeT::JsbInvokeScopeT(const char *functionName) : _functionName(functionName) {
|
||||
_start = std::chrono::high_resolution_clock::now();
|
||||
__jsbInvocationCount++;
|
||||
}
|
||||
JsbInvokeScopeT::~JsbInvokeScopeT() {
|
||||
auto &ref = __jsbFunctionInvokedRecords[_functionName];
|
||||
std::get<0>(ref) += 1;
|
||||
std::get<1>(ref) += std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - _start).count();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void printJSBInvokeAtFrame(int n) {
|
||||
#if defined(RECORD_JSB_INVOKING)
|
||||
static int cnt = 0;
|
||||
cnt += 1;
|
||||
if (cnt % n == 0) {
|
||||
printJSBInvoke();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void clearRecordJSBInvoke() {
|
||||
#if defined(RECORD_JSB_INVOKING)
|
||||
__jsbInvocationCount = 0;
|
||||
__jsbFunctionInvokedRecords.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
void printJSBInvoke() {
|
||||
#if defined(RECORD_JSB_INVOKING)
|
||||
static ccstd::vector<std::pair<const char *, std::tuple<int, uint64_t>>> pairs;
|
||||
for (const auto &it : __jsbFunctionInvokedRecords) {
|
||||
pairs.emplace_back(it); //NOLINT
|
||||
}
|
||||
|
||||
std::sort(pairs.begin(), pairs.end(), cmp);
|
||||
cc::Log::logMessage(cc::LogType::KERNEL, cc::LogLevel::LEVEL_DEBUG, "Start print JSB function record info....... %d times", __jsbInvocationCount);
|
||||
for (const auto &pair : pairs) {
|
||||
cc::Log::logMessage(cc::LogType::KERNEL, cc::LogLevel::LEVEL_DEBUG, "\t%s takes %.3lf ms, invoked %u times,", pair.first, std::get<1>(pair.second) / 1000000.0, std::get<0>(pair.second));
|
||||
}
|
||||
pairs.clear();
|
||||
cc::Log::logMessage(cc::LogType::KERNEL, cc::LogLevel::LEVEL_DEBUG, "End print JSB function record info.......\n");
|
||||
#endif
|
||||
}
|
||||
249
cocos/bindings/jswrapper/sm/HelperMacros.h
Normal file
249
cocos/bindings/jswrapper/sm/HelperMacros.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../ValueArrayPool.h"
|
||||
#include "../config.h"
|
||||
|
||||
//#define RECORD_JSB_INVOKING
|
||||
|
||||
#ifndef CC_DEBUG
|
||||
#undef RECORD_JSB_INVOKING
|
||||
#endif
|
||||
|
||||
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
|
||||
#if defined(RECORD_JSB_INVOKING)
|
||||
|
||||
class JsbInvokeScopeT {
|
||||
public:
|
||||
JsbInvokeScopeT(const char *functionName);
|
||||
~JsbInvokeScopeT();
|
||||
|
||||
private:
|
||||
const char *_functionName;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> _start;
|
||||
};
|
||||
#define JsbInvokeScope(arg) JsbInvokeScopeT invokeScope(arg); // NOLINT(readability-identifier-naming)
|
||||
|
||||
#else
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
#define JsbInvokeScope(arg) \
|
||||
do { \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T, typename STATE>
|
||||
constexpr inline T *SE_THIS_OBJECT(STATE &s) { // NOLINT(readability-identifier-naming)
|
||||
return reinterpret_cast<T *>(s.nativeThisObject());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr typename std::enable_if<std::is_enum<T>::value, char *>::type SE_UNDERLYING_TYPE_NAME() { // NOLINT(readability-identifier-naming)
|
||||
return typeid(std::underlying_type_t<T>).name();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr typename std::enable_if<!std::is_enum<T>::value, char *>::type SE_UNDERLYING_TYPE_NAME() { // NOLINT(readability-identifier-naming)
|
||||
return typeid(T).name();
|
||||
}
|
||||
|
||||
void clearRecordJSBInvoke();
|
||||
|
||||
void printJSBInvoke();
|
||||
|
||||
void printJSBInvokeAtFrame(int n);
|
||||
|
||||
#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
|
||||
|
||||
#define SE_DECLARE_FUNC(funcName) \
|
||||
bool funcName##Registry(JSContext *_cx, unsigned argc, JS::Value *_vp)
|
||||
|
||||
#define SE_BIND_FUNC(funcName) \
|
||||
bool funcName##Registry(JSContext *_cx, unsigned argc, JS::Value *_vp) { \
|
||||
JsbInvokeScope(#funcName); \
|
||||
bool ret = false; \
|
||||
JS::CallArgs _argv = JS::CallArgsFromVp(argc, _vp); \
|
||||
JS::RootedObject _thizObj(_cx); \
|
||||
_argv.computeThis(_cx, &_thizObj); \
|
||||
bool needDeleteValueArray{false}; \
|
||||
se::ValueArray &args = se::gValueArrayPool.get(argc, needDeleteValueArray); \
|
||||
se::CallbackDepthGuard depthGuard{args, se::gValueArrayPool._depth, needDeleteValueArray}; \
|
||||
se::internal::jsToSeArgs(_cx, argc, _argv, args); \
|
||||
se::PrivateObjectBase *privateObject = static_cast<se::PrivateObjectBase *>(se::internal::getPrivate(_cx, _thizObj, 0)); \
|
||||
se::Object *thisObject = reinterpret_cast<se::Object *>(se::internal::getPrivate(_cx, _thizObj, 1)); \
|
||||
se::State state(thisObject, privateObject, args); \
|
||||
ret = funcName(state); \
|
||||
if (!ret) { \
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", #funcName, __FILE__, __LINE__); \
|
||||
} \
|
||||
se::internal::setReturnValue(_cx, state.rval(), _argv); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define SE_BIND_FUNC_FAST(funcName) \
|
||||
bool funcName##Registry(JSContext *_cx, unsigned argc, JS::Value *_vp) { \
|
||||
JS::CallArgs _argv = JS::CallArgsFromVp(argc, _vp); \
|
||||
JS::RootedObject _thizObj(_cx); \
|
||||
_argv.computeThis(_cx, &_thizObj); \
|
||||
auto *privateObject = static_cast<se::PrivateObjectBase *>(se::internal::SE_JS_GetPrivate(_thizObj, 0)); \
|
||||
funcName(privateObject->getRaw()); \
|
||||
_argv.rval().setUndefined(); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define SE_DECLARE_FINALIZE_FUNC(funcName) \
|
||||
void funcName##Registry(JSFreeOp *_fop, JSObject *_obj);
|
||||
|
||||
#define SE_BIND_FINALIZE_FUNC(funcName) \
|
||||
void funcName##Registry(JSFreeOp *_fop, JSObject *_obj) { \
|
||||
JsbInvokeScope(#funcName); \
|
||||
se::PrivateObjectBase *privateObject = static_cast<se::PrivateObjectBase *>(se::internal::SE_JS_GetPrivate(_obj, 0)); \
|
||||
se::Object *seObj = static_cast<se::Object *>(se::internal::SE_JS_GetPrivate(_obj, 1)); \
|
||||
bool ret = false; \
|
||||
if (privateObject == nullptr) \
|
||||
return; \
|
||||
se::State state(privateObject); \
|
||||
ret = funcName(state); \
|
||||
if (!ret) { \
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", #funcName, __FILE__, __LINE__); \
|
||||
} \
|
||||
if (seObj->isClearMappingInFinalizer() && privateObject != nullptr) { \
|
||||
void *nativeObj = privateObject->getRaw(); \
|
||||
auto iter = se::NativePtrToObjectMap::find(nativeObj); \
|
||||
if (iter != se::NativePtrToObjectMap::end()) { \
|
||||
se::NativePtrToObjectMap::erase(iter); \
|
||||
} \
|
||||
} \
|
||||
seObj->decRef(); \
|
||||
}
|
||||
|
||||
#define SE_BIND_CTOR(funcName, cls, finalizeCb) \
|
||||
bool funcName##Registry(JSContext *_cx, unsigned argc, JS::Value *_vp) { \
|
||||
JsbInvokeScope(#funcName); \
|
||||
bool ret = false; \
|
||||
JS::CallArgs _argv = JS::CallArgsFromVp(argc, _vp); \
|
||||
bool needDeleteValueArray{false}; \
|
||||
se::ValueArray &args = se::gValueArrayPool.get(argc, needDeleteValueArray); \
|
||||
se::CallbackDepthGuard depthGuard{args, se::gValueArrayPool._depth, needDeleteValueArray}; \
|
||||
se::internal::jsToSeArgs(_cx, argc, _argv, args); \
|
||||
se::Object *thisObject = se::Object::_createJSObjectForConstructor(cls, _argv); \
|
||||
thisObject->_setFinalizeCallback(finalizeCb##Registry); \
|
||||
_argv.rval().setObject(*thisObject->_getJSObject()); \
|
||||
se::State state(thisObject, args); \
|
||||
ret = funcName(state); \
|
||||
if (ret) { \
|
||||
se::Value _property; \
|
||||
bool _found = false; \
|
||||
_found = thisObject->getProperty("_ctor", &_property); \
|
||||
if (_found) _property.toObject()->call(args, thisObject); \
|
||||
} else { \
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", #funcName, __FILE__, __LINE__); \
|
||||
} \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define SE_BIND_PROP_GET_IMPL(funcName, postFix) \
|
||||
bool funcName##postFix##Registry(JSContext *_cx, unsigned argc, JS::Value *_vp) { \
|
||||
JsbInvokeScope(#funcName); \
|
||||
bool ret = false; \
|
||||
JS::CallArgs _argv = JS::CallArgsFromVp(argc, _vp); \
|
||||
JS::RootedObject _thizObj(_cx); \
|
||||
_argv.computeThis(_cx, &_thizObj); \
|
||||
se::PrivateObjectBase *privateObject = static_cast<se::PrivateObjectBase *>(se::internal::getPrivate(_cx, _thizObj, 0)); \
|
||||
se::Object *thisObject = reinterpret_cast<se::Object *>(se::internal::getPrivate(_cx, _thizObj, 1)); \
|
||||
se::State state(thisObject, privateObject); \
|
||||
ret = funcName(state); \
|
||||
if (!ret) { \
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", #funcName, __FILE__, __LINE__); \
|
||||
} \
|
||||
se::internal::setReturnValue(_cx, state.rval(), _argv); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#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) \
|
||||
bool funcName##postFix##Registry(JSContext *_cx, unsigned _argc, JS::Value *_vp) { \
|
||||
JsbInvokeScope(#funcName); \
|
||||
bool ret = false; \
|
||||
JS::CallArgs _argv = JS::CallArgsFromVp(_argc, _vp); \
|
||||
JS::RootedObject _thizObj(_cx); \
|
||||
_argv.computeThis(_cx, &_thizObj); \
|
||||
se::PrivateObjectBase *privateObject = static_cast<se::PrivateObjectBase *>(se::internal::getPrivate(_cx, _thizObj, 0)); \
|
||||
se::Object *thisObject = reinterpret_cast<se::Object *>(se::internal::getPrivate(_cx, _thizObj, 1)); \
|
||||
bool needDeleteValueArray{false}; \
|
||||
se::ValueArray &args = se::gValueArrayPool.get(1, needDeleteValueArray); \
|
||||
se::CallbackDepthGuard depthGuard{args, se::gValueArrayPool._depth, needDeleteValueArray}; \
|
||||
se::Value &data{args[0]}; \
|
||||
se::internal::jsToSeValue(_cx, _argv[0], &data); \
|
||||
se::State state(thisObject, privateObject, args); \
|
||||
ret = funcName(state); \
|
||||
if (!ret) { \
|
||||
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", #funcName, __FILE__, __LINE__); \
|
||||
} \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#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_TYPE_NAME(t) typeid(t).name()
|
||||
|
||||
#define SE_QUOTEME_(x) #x
|
||||
#define SE_QUOTEME(x) SE_QUOTEME_(x)
|
||||
|
||||
#define SE_REPORT_ERROR(fmt, ...) \
|
||||
SE_LOGD("ERROR (" __FILE__ ", " SE_QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__); \
|
||||
JS_ReportErrorUTF8(se::ScriptEngine::getInstance()->_getContext(), fmt, ##__VA_ARGS__)
|
||||
|
||||
#if CC_DEBUG > 0
|
||||
|
||||
#define SE_ASSERT(cond, fmt, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
SE_LOGE("ASSERT (" __FILE__ ", " SE_QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__); \
|
||||
assert(false); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#else
|
||||
|
||||
#define SE_ASSERT(cond, fmt, ...)
|
||||
|
||||
#endif // #if CC_DEBUG > 0
|
||||
|
||||
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
780
cocos/bindings/jswrapper/sm/Object.cpp
Normal file
780
cocos/bindings/jswrapper/sm/Object.cpp
Normal file
@@ -0,0 +1,780 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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 "Object.h"
|
||||
|
||||
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
|
||||
#include "../MappingUtils.h"
|
||||
#include "Class.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace se {
|
||||
|
||||
std::unordered_map<Object *, void *> __objectMap; // Currently, the value `void*` is always nullptr
|
||||
|
||||
namespace {
|
||||
JSContext *__cx = nullptr;
|
||||
} // namespace
|
||||
|
||||
Object::Object()
|
||||
: _privateObject(nullptr),
|
||||
_cls(nullptr),
|
||||
_finalizeCb(nullptr),
|
||||
_rootCount(0) {
|
||||
_currentVMId = ScriptEngine::getInstance()->getVMId();
|
||||
}
|
||||
|
||||
Object::~Object() {
|
||||
if (_cls == nullptr) {
|
||||
unroot();
|
||||
}
|
||||
|
||||
if (_rootCount > 0) {
|
||||
unprotect();
|
||||
}
|
||||
|
||||
auto iter = __objectMap.find(this);
|
||||
if (iter != __objectMap.end()) {
|
||||
__objectMap.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
bool Object::init(Class *cls, JSObject *obj) {
|
||||
_cls = cls;
|
||||
_heap = obj;
|
||||
|
||||
assert(__objectMap.find(this) == __objectMap.end());
|
||||
__objectMap.emplace(this, nullptr);
|
||||
|
||||
if (_cls == nullptr) {
|
||||
root();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Object *Object::_createJSObject(Class *cls, JSObject *obj) {
|
||||
Object *ret = ccnew Object();
|
||||
if (!ret->init(cls, obj)) {
|
||||
delete ret;
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Object *Object::_createJSObjectForConstructor(Class *cls, const JS::CallArgs &args) {
|
||||
Object *ret = ccnew Object();
|
||||
JS::RootedObject obj(__cx, JS_NewObjectForConstructor(__cx, &cls->_jsCls, args));
|
||||
if (!ret->init(cls, obj)) {
|
||||
delete ret;
|
||||
ret = nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Object *Object::createPlainObject() {
|
||||
Object *obj = Object::_createJSObject(nullptr, JS_NewPlainObject(__cx));
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object *Object::createObjectWithClass(Class *cls) {
|
||||
JS::RootedObject jsobj(__cx);
|
||||
Class::_createJSObjectWithClass(cls, &jsobj);
|
||||
Object *obj = Object::_createJSObject(cls, jsobj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object *Object::getObjectWithPtr(void *ptr) {
|
||||
Object *obj = nullptr;
|
||||
auto iter = NativePtrToObjectMap::find(ptr);
|
||||
if (iter != NativePtrToObjectMap::end()) {
|
||||
obj = iter->second;
|
||||
obj->incRef();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object *Object::createArrayObject(size_t length) {
|
||||
JS::RootedObject jsobj(__cx, JS::NewArrayObject(__cx, length));
|
||||
Object *obj = Object::_createJSObject(nullptr, jsobj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object *Object::createArrayBufferObject(const void *data, size_t byteLength) {
|
||||
Object *obj = nullptr;
|
||||
|
||||
if (byteLength > 0 && data != nullptr) {
|
||||
mozilla::UniquePtr<uint8_t[], JS::FreePolicy> jsBuf(
|
||||
js_pod_arena_malloc<uint8_t>(js::ArrayBufferContentsArena, byteLength));
|
||||
if (!jsBuf)
|
||||
return nullptr;
|
||||
|
||||
memcpy(jsBuf.get(), data, byteLength);
|
||||
JS::RootedObject jsobj(__cx, JS::NewArrayBufferWithContents(__cx, byteLength, jsBuf.get()));
|
||||
if (jsobj) {
|
||||
// If JS::NewArrayBufferWithContents returns non-null, the ownership of
|
||||
// the data is transfered to obj, so we release the ownership here.
|
||||
mozilla::Unused << jsBuf.release();
|
||||
|
||||
obj = Object::_createJSObject(nullptr, jsobj);
|
||||
}
|
||||
} else {
|
||||
JS::RootedObject jsobj(__cx, JS::NewArrayBuffer(__cx, byteLength));
|
||||
if (jsobj) {
|
||||
obj = Object::_createJSObject(nullptr, jsobj);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* static */
|
||||
Object *Object::createExternalArrayBufferObject(void *contents, size_t byteLength, BufferContentsFreeFunc freeFunc, void *freeUserData /* = nullptr*/) {
|
||||
struct BackingStoreUserData {
|
||||
BufferContentsFreeFunc freeFunc;
|
||||
void *freeUserData;
|
||||
size_t byteLength;
|
||||
};
|
||||
|
||||
auto *userData = ccnew BackingStoreUserData();
|
||||
userData->freeFunc = freeFunc;
|
||||
userData->freeUserData = freeUserData;
|
||||
userData->byteLength = byteLength;
|
||||
|
||||
Object *obj = nullptr;
|
||||
JS::RootedObject jsobj(__cx, JS::NewExternalArrayBuffer(
|
||||
__cx, byteLength, contents,
|
||||
[](void *data, void *deleterData) {
|
||||
auto *userData = reinterpret_cast<BackingStoreUserData *>(deleterData);
|
||||
userData->freeFunc(data, userData->byteLength, userData->freeUserData);
|
||||
delete userData;
|
||||
},
|
||||
userData));
|
||||
if (jsobj) {
|
||||
obj = Object::_createJSObject(nullptr, jsobj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
Object *Object::createTypedArray(TypedArrayType type, const void *data, 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;
|
||||
}
|
||||
|
||||
#define CREATE_TYPEDARRAY(_type_, _data, _byteLength, count) \
|
||||
{ \
|
||||
void *tmpData = nullptr; \
|
||||
JS::RootedObject arr(__cx, JS_New##_type_##Array(__cx, (uint32_t)(count))); \
|
||||
bool isShared = false; \
|
||||
if (_data != nullptr) { \
|
||||
JS::AutoCheckCannotGC nogc; \
|
||||
tmpData = JS_Get##_type_##ArrayData(arr, &isShared, nogc); \
|
||||
memcpy(tmpData, (const void *)_data, (_byteLength)); \
|
||||
} \
|
||||
Object *obj = Object::_createJSObject(nullptr, arr); \
|
||||
return obj; \
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TypedArrayType::INT8:
|
||||
CREATE_TYPEDARRAY(Int8, data, byteLength, byteLength);
|
||||
case TypedArrayType::INT16:
|
||||
CREATE_TYPEDARRAY(Int16, data, byteLength, byteLength / 2);
|
||||
case TypedArrayType::INT32:
|
||||
CREATE_TYPEDARRAY(Int32, data, byteLength, byteLength / 4);
|
||||
case TypedArrayType::UINT8:
|
||||
CREATE_TYPEDARRAY(Uint8, data, byteLength, byteLength);
|
||||
case TypedArrayType::UINT16:
|
||||
CREATE_TYPEDARRAY(Uint16, data, byteLength, byteLength / 2);
|
||||
case TypedArrayType::UINT32:
|
||||
CREATE_TYPEDARRAY(Uint32, data, byteLength, byteLength / 4);
|
||||
case TypedArrayType::FLOAT32:
|
||||
CREATE_TYPEDARRAY(Float32, data, byteLength, byteLength / 4);
|
||||
case TypedArrayType::FLOAT64:
|
||||
CREATE_TYPEDARRAY(Float64, data, byteLength, byteLength / 8);
|
||||
default:
|
||||
assert(false); // Should never go here.
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
#undef CREATE_TYPEDARRAY
|
||||
}
|
||||
|
||||
/* static */
|
||||
Object *Object::createTypedArrayWithBuffer(TypedArrayType type, const Object *obj) {
|
||||
return Object::createTypedArrayWithBuffer(type, obj, 0);
|
||||
}
|
||||
|
||||
/* static */
|
||||
Object *Object::createTypedArrayWithBuffer(TypedArrayType type, const Object *obj, size_t offset) {
|
||||
size_t byteLength{0};
|
||||
uint8_t *skip{nullptr};
|
||||
obj->getTypedArrayData(&skip, &byteLength);
|
||||
return Object::createTypedArrayWithBuffer(type, obj, offset, byteLength - offset);
|
||||
}
|
||||
|
||||
/* static */
|
||||
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());
|
||||
JS::RootedObject jsobj(__cx, obj->_getJSObject());
|
||||
|
||||
switch (type) {
|
||||
case TypedArrayType::INT8: {
|
||||
JS::RootedObject typeArray(__cx, JS_NewInt8ArrayWithBuffer(__cx, jsobj, offset, byteLength));
|
||||
return Object::_createJSObject(nullptr, typeArray);
|
||||
}
|
||||
case TypedArrayType::INT16: {
|
||||
JS::RootedObject typeArray(__cx, JS_NewInt16ArrayWithBuffer(__cx, jsobj, offset, byteLength / 2));
|
||||
return Object::_createJSObject(nullptr, typeArray);
|
||||
}
|
||||
case TypedArrayType::INT32: {
|
||||
JS::RootedObject typeArray(__cx, JS_NewInt32ArrayWithBuffer(__cx, jsobj, offset, byteLength / 4));
|
||||
return Object::_createJSObject(nullptr, typeArray);
|
||||
}
|
||||
case TypedArrayType::UINT8: {
|
||||
JS::RootedObject typeArray(__cx, JS_NewUint8ArrayWithBuffer(__cx, jsobj, offset, byteLength));
|
||||
return Object::_createJSObject(nullptr, typeArray);
|
||||
}
|
||||
case TypedArrayType::UINT16: {
|
||||
JS::RootedObject typeArray(__cx, JS_NewUint16ArrayWithBuffer(__cx, jsobj, offset, byteLength / 2));
|
||||
return Object::_createJSObject(nullptr, typeArray);
|
||||
}
|
||||
case TypedArrayType::UINT32: {
|
||||
JS::RootedObject typeArray(__cx, JS_NewUint32ArrayWithBuffer(__cx, jsobj, offset, byteLength / 4));
|
||||
return Object::_createJSObject(nullptr, typeArray);
|
||||
}
|
||||
case TypedArrayType::FLOAT32: {
|
||||
JS::RootedObject typeArray(__cx, JS_NewFloat32ArrayWithBuffer(__cx, jsobj, offset, byteLength / 4));
|
||||
return Object::_createJSObject(nullptr, typeArray);
|
||||
}
|
||||
case TypedArrayType::FLOAT64: {
|
||||
JS::RootedObject typeArray(__cx, JS_NewFloat64ArrayWithBuffer(__cx, jsobj, offset, byteLength / 8));
|
||||
return Object::_createJSObject(nullptr, typeArray);
|
||||
}
|
||||
default:
|
||||
assert(false); // Should never go here.
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Object *Object::createUint8TypedArray(uint8_t *data, size_t dataCount) {
|
||||
return createTypedArray(TypedArrayType::UINT8, data, dataCount);
|
||||
}
|
||||
|
||||
Object *Object::createJSONObject(const std::string &jsonStr) {
|
||||
Value strVal(jsonStr);
|
||||
JS::RootedValue jsStr(__cx);
|
||||
internal::seToJsValue(__cx, strVal, &jsStr);
|
||||
JS::RootedValue jsObj(__cx);
|
||||
JS::RootedString rootedStr(__cx, jsStr.toString());
|
||||
Object *obj = nullptr;
|
||||
if (JS_ParseJSON(__cx, rootedStr, &jsObj)) {
|
||||
obj = Object::_createJSObject(nullptr, jsObj.toObjectOrNull());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Object::_setFinalizeCallback(JSFinalizeOp finalizeCb) {
|
||||
_finalizeCb = finalizeCb;
|
||||
}
|
||||
|
||||
bool Object::getProperty(const char *name, Value *data, bool cachePropertyName) {
|
||||
assert(data != nullptr);
|
||||
data->setUndefined();
|
||||
|
||||
JSObject *jsobj = _getJSObject();
|
||||
if (jsobj == nullptr)
|
||||
return false;
|
||||
|
||||
JS::RootedObject object(__cx, jsobj);
|
||||
|
||||
bool found = false;
|
||||
bool ok = JS_HasProperty(__cx, object, name, &found);
|
||||
|
||||
if (!ok || !found) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::RootedValue rcValue(__cx);
|
||||
ok = JS_GetProperty(__cx, object, name, &rcValue);
|
||||
|
||||
if (ok && data) {
|
||||
internal::jsToSeValue(__cx, rcValue, data);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Object::setProperty(const char *name, const Value &v) {
|
||||
JS::RootedObject object(__cx, _getJSObject());
|
||||
|
||||
JS::RootedValue value(__cx);
|
||||
internal::seToJsValue(__cx, v, &value);
|
||||
return JS_SetProperty(__cx, object, name, value);
|
||||
}
|
||||
|
||||
bool Object::defineProperty(const char *name, JSNative getter, JSNative setter) {
|
||||
JS::RootedObject jsObj(__cx, _getJSObject());
|
||||
return JS_DefineProperty(__cx, jsObj, name, getter, setter, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
bool Object::defineOwnProperty(const char *name, const se::Value &value, bool writable, bool enumerable, bool configurable) {
|
||||
JS::RootedObject jsObj(__cx, _getJSObject());
|
||||
JS::RootedValue jsVal(__cx);
|
||||
internal::seToJsValue(__cx, value, &jsVal);
|
||||
|
||||
unsigned attrs = 0;
|
||||
if (!writable) {
|
||||
attrs |= JSPROP_READONLY;
|
||||
}
|
||||
if (enumerable) {
|
||||
attrs |= JSPROP_ENUMERATE;
|
||||
}
|
||||
if (!configurable) {
|
||||
attrs |= JSPROP_PERMANENT;
|
||||
}
|
||||
|
||||
return JS_DefineProperty(__cx, jsObj, name, jsVal, attrs);
|
||||
}
|
||||
|
||||
bool Object::call(const ValueArray &args, Object *thisObject, Value *rval /* = nullptr*/) {
|
||||
assert(isFunction());
|
||||
|
||||
JS::RootedValueVector jsarr(__cx);
|
||||
jsarr.reserve(args.size());
|
||||
internal::seToJsArgs(__cx, args, &jsarr);
|
||||
|
||||
JS::RootedObject contextObject(__cx);
|
||||
if (thisObject != nullptr) {
|
||||
contextObject.set(thisObject->_getJSObject());
|
||||
}
|
||||
|
||||
JSObject *funcObj = _getJSObject();
|
||||
JS::RootedValue func(__cx, JS::ObjectValue(*funcObj));
|
||||
JS::RootedValue rcValue(__cx);
|
||||
|
||||
JSAutoRealm autoRealm(__cx, func.toObjectOrNull());
|
||||
bool ok = JS_CallFunctionValue(__cx, contextObject, func, jsarr, &rcValue);
|
||||
|
||||
if (ok) {
|
||||
if (rval != nullptr)
|
||||
internal::jsToSeValue(__cx, rcValue, rval);
|
||||
} else {
|
||||
se::ScriptEngine::getInstance()->clearException();
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Object::defineFunction(const char *funcName, JSNative func) {
|
||||
JS::RootedObject object(__cx, _getJSObject());
|
||||
JSFunction *jsFunc = JS_DefineFunction(__cx, object, funcName, func, 0, JSPROP_ENUMERATE);
|
||||
return jsFunc != nullptr;
|
||||
}
|
||||
|
||||
bool Object::getArrayLength(uint32_t *length) const {
|
||||
assert(length != nullptr);
|
||||
if (!isArray())
|
||||
return false;
|
||||
|
||||
JS::RootedObject object(__cx, _getJSObject());
|
||||
if (JS::GetArrayLength(__cx, object, length))
|
||||
return true;
|
||||
|
||||
*length = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Object::getArrayElement(uint32_t index, Value *data) const {
|
||||
assert(data != nullptr);
|
||||
if (!isArray())
|
||||
return false;
|
||||
|
||||
JS::RootedObject object(__cx, _getJSObject());
|
||||
JS::RootedValue rcValue(__cx);
|
||||
if (JS_GetElement(__cx, object, index, &rcValue)) {
|
||||
internal::jsToSeValue(__cx, rcValue, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
data->setUndefined();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Object::setArrayElement(uint32_t index, const Value &data) {
|
||||
if (!isArray())
|
||||
return false;
|
||||
|
||||
JS::RootedValue jsval(__cx);
|
||||
internal::seToJsValue(__cx, data, &jsval);
|
||||
JS::RootedObject thisObj(__cx, _getJSObject());
|
||||
return JS_SetElement(__cx, thisObj, index, jsval);
|
||||
}
|
||||
|
||||
bool Object::isFunction() const {
|
||||
return JS_ObjectIsFunction(_getJSObject());
|
||||
}
|
||||
|
||||
bool Object::_isNativeFunction(JSNative func) const {
|
||||
JSObject *obj = _getJSObject();
|
||||
return JS_ObjectIsFunction(obj) && JS_IsNativeFunction(obj, func);
|
||||
}
|
||||
|
||||
bool Object::isTypedArray() const {
|
||||
return JS_IsTypedArrayObject(_getJSObject());
|
||||
}
|
||||
|
||||
Object::TypedArrayType Object::getTypedArrayType() const {
|
||||
TypedArrayType ret = TypedArrayType::NONE;
|
||||
JSObject *obj = _getJSObject();
|
||||
if (JS_IsInt8Array(obj))
|
||||
ret = TypedArrayType::INT8;
|
||||
else if (JS_IsInt16Array(obj))
|
||||
ret = TypedArrayType::INT16;
|
||||
else if (JS_IsInt32Array(obj))
|
||||
ret = TypedArrayType::INT32;
|
||||
else if (JS_IsUint8Array(obj))
|
||||
ret = TypedArrayType::UINT8;
|
||||
else if (JS_IsUint8ClampedArray(obj))
|
||||
ret = TypedArrayType::UINT8_CLAMPED;
|
||||
else if (JS_IsUint16Array(obj))
|
||||
ret = TypedArrayType::UINT16;
|
||||
else if (JS_IsUint32Array(obj))
|
||||
ret = TypedArrayType::UINT32;
|
||||
else if (JS_IsFloat32Array(obj))
|
||||
ret = TypedArrayType::FLOAT32;
|
||||
else if (JS_IsFloat64Array(obj))
|
||||
ret = TypedArrayType::FLOAT64;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Object::getTypedArrayData(uint8_t **ptr, size_t *length) const {
|
||||
assert(JS_IsArrayBufferViewObject(_getJSObject()));
|
||||
bool isShared = false;
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (ptr != nullptr) {
|
||||
*ptr = (uint8_t *)JS_GetArrayBufferViewData(_getJSObject(), &isShared, nogc);
|
||||
}
|
||||
|
||||
if (length != nullptr) {
|
||||
*length = JS_GetArrayBufferViewByteLength(_getJSObject());
|
||||
}
|
||||
return (*ptr != nullptr);
|
||||
}
|
||||
|
||||
bool Object::isArray() const {
|
||||
JS::RootedValue value(__cx, JS::ObjectValue(*_getJSObject()));
|
||||
bool isArray = false;
|
||||
return JS::IsArrayObject(__cx, value, &isArray) && isArray;
|
||||
}
|
||||
|
||||
bool Object::isArrayBuffer() const {
|
||||
return JS::IsArrayBufferObject(_getJSObject());
|
||||
}
|
||||
|
||||
bool Object::getArrayBufferData(uint8_t **ptr, size_t *length) const {
|
||||
assert(isArrayBuffer());
|
||||
|
||||
bool isShared = false;
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (ptr != nullptr) {
|
||||
*ptr = (uint8_t *)JS::GetArrayBufferData(_getJSObject(), &isShared, nogc);
|
||||
}
|
||||
|
||||
if (length != nullptr) {
|
||||
*length = JS::GetArrayBufferByteLength(_getJSObject());
|
||||
}
|
||||
return (*ptr != nullptr);
|
||||
}
|
||||
|
||||
bool Object::getAllKeys(ccstd::vector<std::string> *allKeys) const {
|
||||
assert(allKeys != nullptr);
|
||||
JS::RootedObject jsobj(__cx, _getJSObject());
|
||||
JS::Rooted<JS::IdVector> props(__cx, JS::IdVector(__cx));
|
||||
if (!JS_Enumerate(__cx, jsobj, &props))
|
||||
return false;
|
||||
|
||||
ccstd::vector<std::string> keys;
|
||||
for (size_t i = 0, length = props.length(); i < length; ++i) {
|
||||
JS::RootedId id(__cx, props[i]);
|
||||
JS::RootedValue keyVal(__cx);
|
||||
JS_IdToValue(__cx, id, &keyVal);
|
||||
|
||||
if (JSID_IS_STRING(id)) {
|
||||
JS::RootedString rootedKeyVal(__cx, keyVal.toString());
|
||||
allKeys->push_back(internal::jsToStdString(__cx, rootedKeyVal));
|
||||
} else if (JSID_IS_INT(id)) {
|
||||
char buf[50] = {0};
|
||||
snprintf(buf, sizeof(buf), "%d", keyVal.toInt32());
|
||||
allKeys->push_back(buf);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Object::setPrivateObject(PrivateObjectBase *data) {
|
||||
assert(_privateObject == nullptr);
|
||||
#if CC_DEBUG
|
||||
//assert(NativePtrToObjectMap::find(data->getRaw()) == NativePtrToObjectMap::end());
|
||||
auto it = NativePtrToObjectMap::find(data->getRaw());
|
||||
if (it != NativePtrToObjectMap::end()) {
|
||||
auto *pri = it->second->getPrivateObject();
|
||||
SE_LOGE("Already exists object %s/[%s], trying to add %s/[%s]\n", pri->getName(), typeid(*pri).name(), data->getName(), typeid(*data).name());
|
||||
#if JSB_TRACK_OBJECT_CREATION
|
||||
SE_LOGE(" previous object created at %s\n", it->second->_objectCreationStackFrame.c_str());
|
||||
#endif
|
||||
assert(false);
|
||||
}
|
||||
#endif
|
||||
JS::RootedObject obj(__cx, _getJSObject());
|
||||
internal::setPrivate(__cx, obj, data, this, &_internalData, _finalizeCb); //TODO(cjh): how to use _internalData?
|
||||
NativePtrToObjectMap::emplace(data->getRaw(), this);
|
||||
_privateObject = data;
|
||||
}
|
||||
|
||||
PrivateObjectBase *Object::getPrivateObject() const {
|
||||
if (_privateObject == nullptr) {
|
||||
JS::RootedObject obj(__cx, _getJSObject());
|
||||
const_cast<Object *>(this)->_privateObject = static_cast<PrivateObjectBase *>(internal::getPrivate(__cx, obj, 0));
|
||||
}
|
||||
return _privateObject;
|
||||
}
|
||||
|
||||
void Object::clearPrivateData(bool clearMapping) {
|
||||
if (_privateObject != nullptr) {
|
||||
if (clearMapping) {
|
||||
NativePtrToObjectMap::erase(_privateObject->getRaw());
|
||||
}
|
||||
JS::RootedObject obj(__cx, _getJSObject());
|
||||
internal::clearPrivate(__cx, obj);
|
||||
delete _privateObject;
|
||||
_privateObject = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::setContext(JSContext *cx) {
|
||||
__cx = cx;
|
||||
}
|
||||
|
||||
// static
|
||||
void Object::cleanup() {
|
||||
for (const auto &e : __objectMap) {
|
||||
e.first->reset();
|
||||
}
|
||||
|
||||
ScriptEngine::getInstance()->addAfterCleanupHook([]() {
|
||||
__objectMap.clear();
|
||||
const auto &instance = NativePtrToObjectMap::instance();
|
||||
for (const auto &e : instance) {
|
||||
e.second->decRef();
|
||||
}
|
||||
NativePtrToObjectMap::clear();
|
||||
__cx = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
JSObject *Object::_getJSObject() const {
|
||||
return isRooted() ? _root.get() : _heap.get();
|
||||
}
|
||||
|
||||
void Object::root() {
|
||||
if (_rootCount == 0) {
|
||||
protect();
|
||||
}
|
||||
++_rootCount;
|
||||
}
|
||||
|
||||
void Object::unroot() {
|
||||
if (_rootCount > 0) {
|
||||
--_rootCount;
|
||||
if (_rootCount == 0) {
|
||||
unprotect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Object::protect() {
|
||||
assert(_root == nullptr);
|
||||
assert(_heap != JS::SafelyInitialized<JSObject *>::create());
|
||||
|
||||
_root.init(__cx, _heap);
|
||||
_heap.set(JS::SafelyInitialized<JSObject *>::create());
|
||||
}
|
||||
|
||||
void Object::unprotect() {
|
||||
if (!_root.initialized())
|
||||
return;
|
||||
|
||||
assert(_currentVMId == ScriptEngine::getInstance()->getVMId());
|
||||
assert(_heap == JS::SafelyInitialized<JSObject *>::create());
|
||||
_heap = _root.get();
|
||||
_root.reset();
|
||||
}
|
||||
|
||||
void Object::reset() {
|
||||
_root.reset();
|
||||
_heap = JS::SafelyInitialized<JSObject *>::create();
|
||||
}
|
||||
|
||||
void Object::onTraceCallback(JSTracer *trc, void *data) {
|
||||
auto *thiz = reinterpret_cast<Object *>(data);
|
||||
thiz->trace(trc);
|
||||
}
|
||||
|
||||
/* Tracing makes no sense in the rooted case, because JS::PersistentRooted
|
||||
* already takes care of that. */
|
||||
void Object::trace(JSTracer *tracer) {
|
||||
assert(!isRooted());
|
||||
JS::TraceEdge(tracer, &_heap, "seobj tracing");
|
||||
}
|
||||
|
||||
/* If not tracing, then you must call this method during GC in order to
|
||||
* update the object's location if it was moved, or null it out if it was
|
||||
* finalized. If the object was finalized, returns true. */
|
||||
bool Object::updateAfterGC(JSTracer *trc, void *data) {
|
||||
assert(!isRooted());
|
||||
bool isGarbageCollected = false;
|
||||
internal::PrivateData *internalData = nullptr;
|
||||
|
||||
JSObject *oldPtr = _heap.unbarrieredGet();
|
||||
if (_heap.unbarrieredGet() != nullptr)
|
||||
JS_UpdateWeakPointerAfterGC(trc, &_heap);
|
||||
|
||||
JSObject *newPtr = _heap.unbarrieredGet();
|
||||
|
||||
// IDEA: test to see ggc
|
||||
if (oldPtr != nullptr && newPtr != nullptr) {
|
||||
assert(oldPtr == newPtr);
|
||||
}
|
||||
isGarbageCollected = (newPtr == nullptr);
|
||||
if (isGarbageCollected && internalData != nullptr) {
|
||||
free(internalData);
|
||||
}
|
||||
return isGarbageCollected;
|
||||
}
|
||||
|
||||
bool Object::isRooted() const {
|
||||
return _rootCount > 0;
|
||||
}
|
||||
|
||||
bool Object::strictEquals(Object *o) const {
|
||||
JSObject *thisObj = _getJSObject();
|
||||
JSObject *oThisObj = o->_getJSObject();
|
||||
if ((thisObj == nullptr || oThisObj == nullptr) && thisObj != oThisObj)
|
||||
return false;
|
||||
|
||||
assert(thisObj);
|
||||
assert(oThisObj);
|
||||
JS::RootedValue v1(__cx, JS::ObjectValue(*_getJSObject()));
|
||||
JS::RootedValue v2(__cx, JS::ObjectValue(*o->_getJSObject()));
|
||||
bool same = false;
|
||||
bool ok = JS::SameValue(__cx, v1, v2, &same);
|
||||
return ok && same;
|
||||
}
|
||||
|
||||
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;
|
||||
if (isFunction() || isArray() || isTypedArray()) {
|
||||
JS::RootedValue val(__cx, JS::ObjectOrNullValue(_getJSObject()));
|
||||
internal::forceConvertJsValueToStdString(__cx, val, &ret);
|
||||
} else if (isArrayBuffer()) {
|
||||
ret = "[object ArrayBuffer]";
|
||||
} else {
|
||||
ret = "[object Object]";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace se
|
||||
|
||||
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
458
cocos/bindings/jswrapper/sm/Object.h
Normal file
458
cocos/bindings/jswrapper/sm/Object.h
Normal file
@@ -0,0 +1,458 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
|
||||
#include "../RefCounter.h"
|
||||
#include "../Value.h"
|
||||
#include "Base.h"
|
||||
|
||||
namespace se {
|
||||
|
||||
class Class;
|
||||
|
||||
namespace internal {
|
||||
struct PrivateData;
|
||||
}
|
||||
|
||||
/**
|
||||
* se::Object represents JavaScript Object.
|
||||
*/
|
||||
class Object final : public RefCounter {
|
||||
public:
|
||||
/**
|
||||
* @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 Typed Array Object with uint8 format 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 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.
|
||||
* @deprecated This method is deprecated, please use `se::Object::createTypedArray` instead.
|
||||
*/
|
||||
SE_DEPRECATED_ATTRIBUTE static Object *createUint8TypedArray(uint8_t *data, size_t byteLength);
|
||||
|
||||
enum class TypedArrayType {
|
||||
NONE,
|
||||
INT8,
|
||||
INT16,
|
||||
INT32,
|
||||
UINT8,
|
||||
UINT8_CLAMPED,
|
||||
UINT16,
|
||||
UINT32,
|
||||
FLOAT32,
|
||||
FLOAT64
|
||||
};
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Creates a JavaScript Typed Array Object with a se::Object, which is a ArrayBuffer,
|
||||
if provide a null pointer,then will create a empty JavaScript Typed Array Object.
|
||||
* @param[in] type The format of typed array.
|
||||
* @param[in] obj A ArrayBuffer to TypedArray.
|
||||
* @param[in] offset Offset of ArrayBuffer to create with.
|
||||
* @param[in] byteLength The number of bytes pointed to by the parameter bytes.
|
||||
* @return A JavaScript Typed Array Object which refers to the ArrayBuffer Object, or nullptr if there is an error.
|
||||
* @note The return value (non-null) has to be released manually.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
using BufferContentsFreeFunc = void (*)(void *contents, size_t byteLength, void *userData);
|
||||
static Object *createExternalArrayBufferObject(void *contents, size_t nbytes, BufferContentsFreeFunc freeFunc, void *freeUserData = nullptr);
|
||||
|
||||
/**
|
||||
* @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 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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
inline bool getProperty(const char *name, Value *data) {
|
||||
return getProperty(name, data, false);
|
||||
}
|
||||
|
||||
bool getProperty(const char *name, Value *data, bool cachePropertyName);
|
||||
|
||||
inline bool getProperty(const std::string &name, Value *value) {
|
||||
return getProperty(name.c_str(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 &value);
|
||||
|
||||
inline bool setProperty(const std::string &name, const Value &value) {
|
||||
return setProperty(name.c_str(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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, JSNative getter, JSNative setter);
|
||||
|
||||
bool defineOwnProperty(const char *name, const se::Value &value, bool writable = true, bool enumerable = true, bool configurable = true);
|
||||
|
||||
/**
|
||||
* @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, JSNative func);
|
||||
|
||||
/**
|
||||
* @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 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 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 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 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(ccstd::vector<std::string> *allKeys) const;
|
||||
|
||||
void setPrivateObject(PrivateObjectBase *data);
|
||||
PrivateObjectBase *getPrivateObject() const;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
inline void *getPrivateData() const {
|
||||
return _privateObject ? _privateObject->getRaw() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
template <typename T>
|
||||
inline void setPrivateData(T *data) {
|
||||
static_assert(!std::is_void<T>::value, "void * is not allowed for private data");
|
||||
setPrivateObject(se::make_shared_private_object(data));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T *getTypedPrivateData() const {
|
||||
return reinterpret_cast<T *>(getPrivateData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
inline void setClearMappingInFinalizer(bool v) { _clearMappingInFinalizer = v; }
|
||||
inline bool isClearMappingInFinalizer() const { return _clearMappingInFinalizer; }
|
||||
|
||||
/**
|
||||
* @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 Tests whether two objects are strict equal, as compared by the JS === operator.
|
||||
* @param[in] o The object to be tested with this object.
|
||||
* @return true if the two values are strict equal, otherwise false.
|
||||
*/
|
||||
bool strictEquals(Object *o) const;
|
||||
|
||||
/**
|
||||
* @brief Attaches an object to current object.
|
||||
* @param[in] obj The object to be attached.
|
||||
* @return true if succeed, otherwise false.
|
||||
* @note This method will set `obj` as a property of current object, therefore the lifecycle of child object will depend on current object,
|
||||
* which means `obj` may be garbage collected only after current object is garbage collected.
|
||||
* It's normally used in binding a native callback method. For example:
|
||||
|
||||
```javascript
|
||||
var self = this;
|
||||
someObject.setCallback(function(){}, self);
|
||||
```
|
||||
|
||||
```c++
|
||||
static bool SomeObject_setCallback(se::State& s)
|
||||
{
|
||||
SomeObject* cobj = (SomeObject*)s.nativeThisObject();
|
||||
const auto& args = s.args();
|
||||
size_t argc = args.size();
|
||||
if (argc == 2) {
|
||||
std::function<void()> arg0;
|
||||
do {
|
||||
if (args[0].isObject() && args[0].toObject()->isFunction())
|
||||
{
|
||||
se::Value jsThis(args[1]);
|
||||
se::Value jsFunc(args[0]);
|
||||
|
||||
jsThis.toObject()->attachObject(jsFunc.toObject());
|
||||
|
||||
auto lambda = [=]() -> void {
|
||||
...
|
||||
// Call jsFunc stuff...
|
||||
...
|
||||
};
|
||||
arg0 = lambda;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg0 = nullptr;
|
||||
}
|
||||
} while(false);
|
||||
SE_PRECONDITION2(ok, false, "Error processing arguments");
|
||||
cobj->setCallback(arg0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
||||
*/
|
||||
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 Returns the string for describing current object.
|
||||
* @return The string for describing current object.
|
||||
*/
|
||||
std::string toString() const;
|
||||
|
||||
// Private API used in wrapper
|
||||
static Object *_createJSObject(Class *cls, JSObject *obj);
|
||||
static Object *_createJSObjectForConstructor(Class *cls, const JS::CallArgs &args);
|
||||
void _setFinalizeCallback(JSFinalizeOp finalizeCb);
|
||||
bool _isNativeFunction(JSNative func) const;
|
||||
JSObject *_getJSObject() const;
|
||||
Class *_getClass() const { return _cls; }
|
||||
//
|
||||
|
||||
private:
|
||||
Object();
|
||||
bool init(Class *cls, JSObject *obj);
|
||||
virtual ~Object();
|
||||
|
||||
static void setContext(JSContext *cx);
|
||||
static void cleanup();
|
||||
static void onTraceCallback(JSTracer *trc, void *data);
|
||||
|
||||
void trace(JSTracer *tracer);
|
||||
bool updateAfterGC(JSTracer *trc, void *data);
|
||||
|
||||
void protect();
|
||||
void unprotect();
|
||||
void reset();
|
||||
|
||||
JS::Heap<JSObject *> _heap; /* should be untouched if in rooted mode */
|
||||
JS::PersistentRootedObject _root; /* should be null if not in rooted mode */
|
||||
|
||||
PrivateObjectBase *_privateObject{nullptr};
|
||||
internal::PrivateData *_internalData{nullptr};
|
||||
|
||||
Class *_cls{nullptr};
|
||||
JSFinalizeOp _finalizeCb{nullptr};
|
||||
|
||||
uint32_t _rootCount{0};
|
||||
uint32_t _currentVMId{0};
|
||||
|
||||
bool _clearMappingInFinalizer{true};
|
||||
|
||||
friend class ScriptEngine;
|
||||
friend class Class;
|
||||
};
|
||||
|
||||
extern std::unordered_map<Object *, void *> __objectMap; // Currently, the value `void*` is always nullptr
|
||||
|
||||
} // namespace se
|
||||
|
||||
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
1150
cocos/bindings/jswrapper/sm/ScriptEngine.cpp
Normal file
1150
cocos/bindings/jswrapper/sm/ScriptEngine.cpp
Normal file
File diff suppressed because it is too large
Load Diff
347
cocos/bindings/jswrapper/sm/ScriptEngine.h
Normal file
347
cocos/bindings/jswrapper/sm/ScriptEngine.h
Normal file
@@ -0,0 +1,347 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
|
||||
#include "Base.h"
|
||||
|
||||
namespace se {
|
||||
|
||||
class Object;
|
||||
class Class;
|
||||
class Value;
|
||||
|
||||
/**
|
||||
* A stack-allocated class that governs a number of local handles.
|
||||
* It's only implemented for v8 wrapper now.
|
||||
* Other script engine wrappers have empty implementation for this class.
|
||||
* It's used at the beginning of executing any wrapper API.
|
||||
*/
|
||||
class AutoHandleScope {
|
||||
public:
|
||||
AutoHandleScope();
|
||||
~AutoHandleScope();
|
||||
};
|
||||
|
||||
/**
|
||||
* ScriptEngine is a sington which represents a context of JavaScript VM.
|
||||
*/
|
||||
class ScriptEngine final {
|
||||
public:
|
||||
/**
|
||||
* @brief Gets or creates the instance of script engine.
|
||||
* @return The script engine instance.
|
||||
*/
|
||||
static ScriptEngine *getInstance();
|
||||
|
||||
/**
|
||||
* @brief Destroys the instance of script engine.
|
||||
*/
|
||||
static void destroyInstance();
|
||||
|
||||
/**
|
||||
* @brief Gets the global object of JavaScript VM.
|
||||
* @return The se::Object stores the global JavaScript object.
|
||||
*/
|
||||
Object *getGlobalObject();
|
||||
|
||||
typedef bool (*RegisterCallback)(Object *);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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 Executes a utf-8 string buffer which contains JavaScript code.
|
||||
* @param[in] scriptStr 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] rval 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 *scriptStr, ssize_t length = -1, Value *rval = nullptr, const char *fileName = nullptr);
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
assert(false);
|
||||
return false;
|
||||
} //cjh
|
||||
|
||||
/**
|
||||
* @brief Grab a snapshot of the current JavaScript execution stack.
|
||||
* @return current stack trace string
|
||||
*/
|
||||
std::string getCurrentStackTrace() { return ""; } //cjh
|
||||
|
||||
/**
|
||||
* Delegate class for file operation
|
||||
*/
|
||||
class FileOperationDelegate {
|
||||
public:
|
||||
FileOperationDelegate()
|
||||
: onGetDataFromFile(nullptr),
|
||||
onGetStringFromFile(nullptr),
|
||||
onCheckFileExist(nullptr),
|
||||
onGetFullPath(nullptr) {}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Sets the delegate for file operation.
|
||||
* @param delegate[in] The delegate instance for file operation.
|
||||
*/
|
||||
void setFileOperationDelegate(const FileOperationDelegate &delegate);
|
||||
|
||||
/**
|
||||
* @brief Gets the delegate for file operation.
|
||||
* @return The delegate for file operation
|
||||
*/
|
||||
const FileOperationDelegate &getFileOperationDelegate() const;
|
||||
|
||||
/**
|
||||
* @brief Executes a file which contains JavaScript code.
|
||||
* @param[in] path Script file path.
|
||||
* @param[in] rval 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 *rval = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Tests whether script engine is doing garbage collection.
|
||||
* @return true if it's in garbage collection, otherwise false.
|
||||
*/
|
||||
bool isGarbageCollecting();
|
||||
|
||||
/**
|
||||
* @brief Performs a JavaScript garbage collection.
|
||||
*/
|
||||
void garbageCollect() { JS_GC(_cx); }
|
||||
|
||||
/**
|
||||
* @brief Tests whether script engine is being cleaned up.
|
||||
* @return true if it's in cleaning up, otherwise false.
|
||||
*/
|
||||
bool isInCleanup() { return _isInCleanup; }
|
||||
|
||||
/**
|
||||
* @brief Tests whether script engine is valid.
|
||||
* @return true if it's valid, otherwise false.
|
||||
*/
|
||||
bool isValid() { return _isValid; }
|
||||
|
||||
/**
|
||||
* @brief Throw JS exception
|
||||
*/
|
||||
void throwException(const std::string &errorMessage) { assert(false); } //cjh
|
||||
|
||||
/**
|
||||
* @brief Clears all exceptions.
|
||||
*/
|
||||
void clearException();
|
||||
|
||||
using ExceptionCallback = std::function<void(const char *, const char *, const char *)>; // location, message, stack
|
||||
|
||||
/**
|
||||
* @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 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 Gets the start time of script engine.
|
||||
* @return The start time of script engine.
|
||||
*/
|
||||
const std::chrono::steady_clock::time_point &getStartTime() const { return _startTime; }
|
||||
|
||||
/**
|
||||
* @brief Enables JavaScript debugger
|
||||
* @param[in] serverAddr The address of debugger server.
|
||||
* @param[in] port The port of debugger server will use.
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* @brief Gets script virtual machine instance ID. Default value is 1, increase by 1 if `init` is invoked.
|
||||
*/
|
||||
uint32_t getVMId() const { return _vmId; }
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Handle all exceptions throwed by promise
|
||||
*/
|
||||
void handlePromiseExceptions();
|
||||
|
||||
// Private API used in wrapper
|
||||
JSContext *_getContext() { return _cx; }
|
||||
void _setGarbageCollecting(bool isGarbageCollecting);
|
||||
void _debugProcessInput(const std::string &str);
|
||||
//
|
||||
private:
|
||||
ScriptEngine();
|
||||
~ScriptEngine();
|
||||
|
||||
static void onWeakPointerCompartmentCallback(JSTracer *trc, JS::Compartment *comp, void *data);
|
||||
static void onWeakPointerZoneGroupCallback(JSTracer *trc, void *data);
|
||||
|
||||
bool getScript(const std::string &path, JS::MutableHandleScript script);
|
||||
bool compileScript(const std::string &path, JS::MutableHandleScript script);
|
||||
|
||||
JSContext *_cx;
|
||||
JS::Realm *_oldCompartment;
|
||||
|
||||
Object *_globalObj;
|
||||
Object *_debugGlobalObj;
|
||||
|
||||
FileOperationDelegate _fileOperationDelegate;
|
||||
|
||||
ccstd::vector<RegisterCallback> _registerCallbackArray;
|
||||
ccstd::vector<RegisterCallback> _permRegisterCallbackArray;
|
||||
std::chrono::steady_clock::time_point _startTime;
|
||||
|
||||
ccstd::vector<std::function<void()>> _beforeInitHookArray;
|
||||
ccstd::vector<std::function<void()>> _afterInitHookArray;
|
||||
|
||||
ccstd::vector<std::function<void()>> _beforeCleanupHookArray;
|
||||
ccstd::vector<std::function<void()>> _afterCleanupHookArray;
|
||||
|
||||
ExceptionCallback _exceptionCallback;
|
||||
// name ~> JSScript map
|
||||
std::unordered_map<std::string, JS::PersistentRootedScript *> _filenameScriptMap;
|
||||
|
||||
std::string _debuggerServerAddr;
|
||||
uint32_t _debuggerServerPort;
|
||||
|
||||
uint32_t _vmId;
|
||||
|
||||
bool _isGarbageCollecting;
|
||||
bool _isValid;
|
||||
bool _isInCleanup;
|
||||
bool _isErrorHandleWorking;
|
||||
};
|
||||
|
||||
} // namespace se
|
||||
|
||||
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
34
cocos/bindings/jswrapper/sm/SeApi.h
Normal file
34
cocos/bindings/jswrapper/sm/SeApi.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../State.h"
|
||||
#include "../Value.h"
|
||||
#include "Class.h"
|
||||
#include "HelperMacros.h"
|
||||
#include "Object.h"
|
||||
#include "ScriptEngine.h"
|
||||
#include "Utils.h"
|
||||
207
cocos/bindings/jswrapper/sm/Utils.cpp
Normal file
207
cocos/bindings/jswrapper/sm/Utils.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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 "Utils.h"
|
||||
|
||||
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
|
||||
#include "Class.h"
|
||||
#include "Object.h"
|
||||
#include "ScriptEngine.h"
|
||||
|
||||
namespace se {
|
||||
|
||||
namespace internal {
|
||||
|
||||
void *SE_JS_GetPrivate(JSObject *obj, uint32_t slot) {
|
||||
assert(slot >= 0 && slot < 2);
|
||||
const auto &v = JS::GetReservedSlot(obj, slot);
|
||||
return v.isNullOrUndefined() ? nullptr : v.toPrivate();
|
||||
}
|
||||
|
||||
void SE_JS_SetPrivate(JSObject *obj, uint32_t slot, void *data) {
|
||||
assert(slot >= 0 && slot < 2);
|
||||
JS::SetReservedSlot(obj, slot, JS::PrivateValue(data));
|
||||
}
|
||||
|
||||
bool isJSBClass(JSObject *obj) {
|
||||
const JSClass *cls = JS::GetClass(obj);
|
||||
return (cls->flags & (JSCLASS_HAS_RESERVED_SLOTS(2)) && (cls->flags & JSCLASS_USERBIT1));
|
||||
}
|
||||
|
||||
void forceConvertJsValueToStdString(JSContext *cx, JS::HandleValue jsval, std::string *ret) {
|
||||
assert(ret != nullptr);
|
||||
JS::RootedString jsStr(cx, JS::ToString(cx, jsval));
|
||||
*ret = jsToStdString(cx, jsStr);
|
||||
}
|
||||
|
||||
std::string jsToStdString(JSContext *cx, JS::HandleString jsStr) {
|
||||
JS::UniqueChars str = JS_EncodeStringToUTF8(cx, jsStr);
|
||||
std::string ret(str.get());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void jsToSeArgs(JSContext *cx, int argc, const JS::CallArgs &argv, ValueArray &outArr) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
jsToSeValue(cx, argv[i], &outArr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void seToJsArgs(JSContext *cx, const ValueArray &args, JS::RootedValueVector *outArr) {
|
||||
for (const auto &arg : args) {
|
||||
JS::RootedValue v(cx);
|
||||
seToJsValue(cx, arg, &v);
|
||||
outArr->append(v);
|
||||
}
|
||||
}
|
||||
|
||||
void seToJsValue(JSContext *cx, const Value &arg, JS::MutableHandleValue outVal) {
|
||||
switch (arg.getType()) {
|
||||
case Value::Type::Number: {
|
||||
JS::RootedValue value(cx);
|
||||
value.setDouble(arg.toNumber());
|
||||
outVal.set(value);
|
||||
} break;
|
||||
|
||||
case Value::Type::String: {
|
||||
JS::UTF8Chars utf8Str(arg.toString().c_str(), arg.toString().length());
|
||||
JSString *string = JS_NewStringCopyUTF8N(cx, utf8Str);
|
||||
JS::RootedValue value(cx);
|
||||
value.setString(string);
|
||||
outVal.set(value);
|
||||
} break;
|
||||
|
||||
case Value::Type::Boolean: {
|
||||
JS::RootedValue value(cx);
|
||||
value.setBoolean(arg.toBoolean());
|
||||
outVal.set(value);
|
||||
} break;
|
||||
|
||||
case Value::Type::Object: {
|
||||
JS::RootedValue value(cx, JS::ObjectValue(*arg.toObject()->_getJSObject()));
|
||||
outVal.set(value);
|
||||
} break;
|
||||
|
||||
case Value::Type::Null: {
|
||||
JS::RootedValue value(cx);
|
||||
value.setNull();
|
||||
outVal.set(value);
|
||||
} break;
|
||||
|
||||
case Value::Type::Undefined: {
|
||||
JS::RootedValue value(cx);
|
||||
value.setUndefined();
|
||||
outVal.set(value);
|
||||
} break;
|
||||
case Value::Type::BigInt: {
|
||||
JS::RootedValue value(cx);
|
||||
JS::BigInt *bi = JS::NumberToBigInt(cx, arg.toUint64());
|
||||
outVal.setBigInt(bi);
|
||||
} break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void jsToSeValue(JSContext *cx, JS::HandleValue jsval, Value *v) {
|
||||
if (jsval.isNumber()) {
|
||||
v->setNumber(jsval.toNumber());
|
||||
} else if (jsval.isString()) {
|
||||
JS::RootedString jsstr(cx, jsval.toString());
|
||||
v->setString(jsToStdString(cx, jsstr));
|
||||
} else if (jsval.isBoolean()) {
|
||||
v->setBoolean(jsval.toBoolean());
|
||||
} else if (jsval.isObject()) {
|
||||
Object *object = nullptr;
|
||||
|
||||
JS::RootedObject jsobj(cx, jsval.toObjectOrNull());
|
||||
PrivateObjectBase *privateObject = static_cast<PrivateObjectBase *>(internal::getPrivate(cx, jsobj, 0));
|
||||
void *nativeObj = privateObject ? privateObject->getRaw() : nullptr;
|
||||
bool needRoot = false;
|
||||
if (nativeObj != nullptr) {
|
||||
object = Object::getObjectWithPtr(nativeObj);
|
||||
}
|
||||
|
||||
if (object == nullptr) {
|
||||
object = Object::_createJSObject(nullptr, jsobj);
|
||||
needRoot = true;
|
||||
}
|
||||
v->setObject(object, needRoot);
|
||||
object->decRef();
|
||||
} else if (jsval.isNull()) {
|
||||
v->setNull();
|
||||
} else if (jsval.isUndefined()) {
|
||||
v->setUndefined();
|
||||
} else if (jsval.isBigInt()) {
|
||||
v->setUint64(JS::ToBigUint64(jsval.toBigInt()));
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void setReturnValue(JSContext *cx, const Value &data, const JS::CallArgs &argv) {
|
||||
JS::RootedValue rval(cx);
|
||||
seToJsValue(cx, data, &rval);
|
||||
argv.rval().set(rval);
|
||||
}
|
||||
|
||||
bool hasPrivate(JSContext *cx, JS::HandleObject obj) {
|
||||
return isJSBClass(obj);
|
||||
}
|
||||
|
||||
void *getPrivate(JSContext *cx, JS::HandleObject obj, uint32_t slot) {
|
||||
bool found = isJSBClass(obj);
|
||||
if (found) {
|
||||
return SE_JS_GetPrivate(obj, slot);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setPrivate(JSContext *cx, JS::HandleObject obj, PrivateObjectBase *data, Object *seObj, PrivateData **outInternalData, JSFinalizeOp finalizeCb) {
|
||||
bool found = isJSBClass(obj);
|
||||
assert(found);
|
||||
if (found) {
|
||||
SE_JS_SetPrivate(obj, 0, data);
|
||||
SE_JS_SetPrivate(obj, 1, seObj);
|
||||
if (outInternalData != nullptr) {
|
||||
*outInternalData = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clearPrivate(JSContext *cx, JS::HandleObject obj) {
|
||||
bool found = isJSBClass(obj);
|
||||
if (found) {
|
||||
SE_JS_SetPrivate(obj, 0, nullptr);
|
||||
SE_JS_SetPrivate(obj, 1, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace se
|
||||
|
||||
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
70
cocos/bindings/jswrapper/sm/Utils.h
Normal file
70
cocos/bindings/jswrapper/sm/Utils.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-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.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
|
||||
#include "Base.h"
|
||||
|
||||
#include "../Value.h"
|
||||
|
||||
namespace se {
|
||||
|
||||
class Class;
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct PrivateData {
|
||||
PrivateObjectBase *data{nullptr};
|
||||
Object *seObj{nullptr};
|
||||
JSFinalizeOp finalizeCb{nullptr};
|
||||
};
|
||||
|
||||
void forceConvertJsValueToStdString(JSContext *cx, JS::HandleValue jsval, std::string *ret);
|
||||
std::string jsToStdString(JSContext *cx, JS::HandleString jsStr);
|
||||
|
||||
void jsToSeArgs(JSContext *cx, int argc, const JS::CallArgs &argv, ValueArray &outArr);
|
||||
void jsToSeValue(JSContext *cx, JS::HandleValue jsval, Value *v);
|
||||
void seToJsArgs(JSContext *cx, const ValueArray &args, JS::RootedValueVector *outArr);
|
||||
void seToJsValue(JSContext *cx, const Value &v, JS::MutableHandleValue outVal);
|
||||
|
||||
void setReturnValue(JSContext *cx, const Value &data, const JS::CallArgs &argv);
|
||||
|
||||
bool hasPrivate(JSContext *cx, JS::HandleObject obj);
|
||||
void *getPrivate(JSContext *cx, JS::HandleObject obj, uint32_t slot);
|
||||
void setPrivate(JSContext *cx, JS::HandleObject obj, PrivateObjectBase *data, Object *seObj, PrivateData **outInternalData, JSFinalizeOp finalizeCb);
|
||||
void clearPrivate(JSContext *cx, JS::HandleObject obj);
|
||||
|
||||
void *SE_JS_GetPrivate(JSObject *obj, uint32_t slot);
|
||||
void SE_JS_SetPrivate(JSObject *obj, uint32_t slot, void *data);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace se
|
||||
|
||||
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
|
||||
Reference in New Issue
Block a user