初始化

This commit is contained in:
SmallMain
2022-06-25 00:23:03 +08:00
commit ef0589e8e5
2264 changed files with 617829 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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/Initialization.h"
#include "js/Conversions.h"
#include <string>
#include <vector>
#include <unordered_map>
#include <chrono>
#include <functional>
#include <assert.h>
#include "HelperMacros.h"

View File

@@ -0,0 +1,237 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.hpp"
#include "Object.hpp"
#include "Utils.hpp"
#include "ScriptEngine.hpp"
#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;
}
std::vector<Class*> __allClasses;
}
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 = new Class();
if (cls != nullptr && !cls->init(className, obj, parentProto, ctor))
{
delete cls;
cls = nullptr;
}
return cls;
}
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);
}
bool Class::install()
{
// assert(__clsMap.find(_name) == __clsMap.end());
//
// __clsMap.emplace(_name, this);
_jsCls.name = _name;
if (_finalizeOp != nullptr)
{
_jsCls.flags = JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE; //IDEA: Use JSCLASS_BACKGROUND_FINALIZE to improve GC performance
_classOps.finalize = _finalizeOp;
}
else
{
_jsCls.flags = JSCLASS_HAS_PRIVATE;
}
_jsCls.cOps = &_classOps;
JSObject* parentObj = _parentProto != nullptr ? _parentProto->_getJSObject() : nullptr;
JS::RootedObject parent(__cx, _parent->_getJSObject());
JS::RootedObject parentProto(__cx, parentObj);
_funcs.push_back(JS_FS_END);
_properties.push_back(JS_PS_END);
_staticFuncs.push_back(JS_FS_END);
_staticProperties.push_back(JS_PS_END);
JSObject* jsobj = 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_PERMANENT | 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 | JSPROP_PERMANENT);
_properties.push_back(property);
return true;
}
bool Class::defineStaticFunction(const char *name, JSNative func)
{
JSFunctionSpec cb = JS_FN(name, func, 0, JSPROP_PERMANENT | 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 | JSPROP_PERMANENT);
_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;
// }
JSObject* Class::_createJSObjectWithClass(Class* cls)
{
JSObject* proto = cls->_proto != nullptr ? cls->_proto->_getJSObject() : nullptr;
JS::RootedObject jsProto(__cx, proto);
JS::RootedObject obj(__cx, JS_NewObjectWithGivenProto(__cx, &cls->_jsCls, jsProto));
return obj;
}
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

View File

@@ -0,0 +1,154 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.hpp"
#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);
/**
* @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);
/**
* @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 JSObject* _createJSObjectWithClass(Class* cls);
static void setContext(JSContext* cx);
static void cleanup();
const char* _name;
Object* _parent;
Object* _proto;
Object* _parentProto;
JSNative _ctor;
JSClass _jsCls;
JSClassOps _classOps;
std::vector<JSFunctionSpec> _funcs;
std::vector<JSFunctionSpec> _staticFuncs;
std::vector<JSPropertySpec> _properties;
std::vector<JSPropertySpec> _staticProperties;
JSFinalizeOp _finalizeOp;
friend class ScriptEngine;
friend class Object;
};
} // namespace se {
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM

View File

@@ -0,0 +1,203 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.hpp"
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
extern uint32_t __jsbInvocationCount;
#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) \
{ \
++__jsbInvocationCount; \
bool ret = false; \
JS::CallArgs _argv = JS::CallArgsFromVp(argc, _vp); \
JS::Value _thiz = _argv.computeThis(_cx); \
se::ValueArray args; \
se::internal::jsToSeArgs(_cx, argc, _argv, &args); \
JS::RootedObject _thizObj(_cx, _thiz.toObjectOrNull()); \
void* nativeThisObject = se::internal::getPrivate(_cx, _thizObj); \
se::State state(nativeThisObject, 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_DECLARE_FINALIZE_FUNC(funcName) \
void funcName##Registry(JSFreeOp* _fop, JSObject* _obj);
#define SE_BIND_FINALIZE_FUNC(funcName) \
void funcName##Registry(JSFreeOp* _fop, JSObject* _obj) \
{ \
void* nativeThisObject = JS_GetPrivate(_obj); \
bool ret = false; \
if (nativeThisObject == nullptr) \
return;\
se::State state(nativeThisObject); \
ret = funcName(state); \
if (!ret) { \
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", #funcName, __FILE__, __LINE__); \
} \
}
#define SE_BIND_CTOR(funcName, cls, finalizeCb) \
bool funcName##Registry(JSContext* _cx, unsigned argc, JS::Value* _vp) \
{ \
++__jsbInvocationCount; \
bool ret = false; \
JS::CallArgs _argv = JS::CallArgsFromVp(argc, _vp); \
se::ValueArray args; \
se::internal::jsToSeArgs(_cx, argc, _argv, &args); \
se::Object* thisObject = se::Object::createObjectWithClass(cls); \
_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_SUB_CLS_CTOR(funcName, cls, finalizeCb) \
bool funcName##Registry(JSContext* _cx, unsigned argc, JS::Value* _vp) \
{ \
++__jsbInvocationCount; \
bool ret = false; \
JS::CallArgs _argv = JS::CallArgsFromVp(argc, _vp); \
JS::Value _thiz = _argv.computeThis(_cx); \
se::ValueArray args; \
se::internal::jsToSeArgs(_cx, argc, _argv, &args); \
se::Object* thisObject = se::Object::_createJSObject(cls, _thiz.toObjectOrNull()); \
thisObject->_setFinalizeCallback(finalizeCb##Registry); \
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(funcName) \
bool funcName##Registry(JSContext *_cx, unsigned argc, JS::Value* _vp) \
{ \
++__jsbInvocationCount; \
bool ret = false; \
JS::CallArgs _argv = JS::CallArgsFromVp(argc, _vp); \
JS::Value _thiz = _argv.computeThis(_cx); \
JS::RootedObject _thizObj(_cx, _thiz.toObjectOrNull()); \
void* nativeThisObject = se::internal::getPrivate(_cx, _thizObj); \
se::State state(nativeThisObject); \
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_SET(funcName) \
bool funcName##Registry(JSContext *_cx, unsigned _argc, JS::Value *_vp) \
{ \
++__jsbInvocationCount; \
bool ret = false; \
JS::CallArgs _argv = JS::CallArgsFromVp(_argc, _vp); \
JS::Value _thiz = _argv.computeThis(_cx); \
JS::RootedObject _thizObj(_cx, _thiz.toObjectOrNull()); \
void* nativeThisObject = se::internal::getPrivate(_cx, _thizObj); \
se::Value data; \
se::internal::jsToSeValue(_cx, _argv[0], &data); \
se::ValueArray args; \
args.push_back(std::move(data)); \
se::State state(nativeThisObject, args); \
ret = funcName(state); \
if (!ret) { \
SE_LOGE("[ERROR] Failed to invoke %s, location: %s:%d\n", #funcName, __FILE__, __LINE__); \
} \
return ret; \
}
#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 COCOS2D_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 COCOS2D_DEBUG > 0
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM

View File

@@ -0,0 +1,722 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.hpp"
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
#include "Utils.hpp"
#include "Class.hpp"
#include "ScriptEngine.hpp"
#include "../MappingUtils.hpp"
namespace se {
std::unordered_map<Object*, void*> __objectMap; // Currently, the value `void*` is always nullptr
namespace {
JSContext *__cx = nullptr;
void get_or_create_js_obj(JSContext* cx, JS::HandleObject obj, const std::string &name, JS::MutableHandleObject jsObj)
{
JS::RootedValue nsval(cx);
JS_GetProperty(cx, obj, name.c_str(), &nsval);
if (nsval.isNullOrUndefined()) {
jsObj.set(JS_NewPlainObject(cx));
nsval = JS::ObjectValue(*jsObj);
JS_SetProperty(cx, obj, name.c_str(), nsval);
} else {
jsObj.set(nsval.toObjectOrNull());
}
}
}
Object::Object()
: _root(nullptr)
, _privateData(nullptr)
, _cls(nullptr)
, _finalizeCb(nullptr)
, _rootCount(0)
{
_currentVMId = ScriptEngine::getInstance()->getVMId();
}
Object::~Object()
{
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);
return true;
}
Object* Object::_createJSObject(Class* cls, JSObject* obj)
{
Object* ret = new Object();
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)
{
JSObject* jsobj = Class::_createJSObjectWithClass(cls);
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(void* data, size_t byteLength)
{
JS::RootedObject jsobj(__cx, JS_NewArrayBuffer(__cx, (uint32_t)byteLength));
bool isShared = false;
JS::AutoCheckCannotGC nogc;
uint8_t* tmpData = JS_GetArrayBufferData(jsobj, &isShared, nogc);
if (data)
{
memcpy((void*)tmpData, (const void*)data, byteLength);
}
else
{
memset((void*)tmpData, 0, byteLength);
}
Object* obj = Object::_createJSObject(nullptr, jsobj);
return obj;
}
Object* Object::createTypedArray(TypedArrayType type, 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;
}
JSObject* arr = nullptr;
void* tmpData = nullptr;
bool isShared = false;
JS::AutoCheckCannotGC nogc;
switch (type) {
case TypedArrayType::INT8:
arr = JS_NewInt8Array(__cx, (uint32_t)byteLength);
tmpData = JS_GetInt8ArrayData(arr, &isShared, nogc);
break;
case TypedArrayType::INT16:
arr = JS_NewInt16Array(__cx, (uint32_t)byteLength/2);
tmpData = JS_GetInt16ArrayData(arr, &isShared, nogc);
break;
case TypedArrayType::INT32:
arr = JS_NewInt32Array(__cx, (uint32_t)byteLength/4);
tmpData = JS_GetInt32ArrayData(arr, &isShared, nogc);
break;
case TypedArrayType::UINT8:
arr = JS_NewUint8Array(__cx, (uint32_t)byteLength);
tmpData = JS_GetUint8ArrayData(arr, &isShared, nogc);
break;
case TypedArrayType::UINT16:
arr = JS_NewUint16Array(__cx, (uint32_t)byteLength/2);
tmpData = JS_GetUint16ArrayData(arr, &isShared, nogc);
break;
case TypedArrayType::UINT32:
arr = JS_NewUint32Array(__cx, (uint32_t)byteLength/4);
tmpData = JS_GetUint32ArrayData(arr, &isShared, nogc);
break;
case TypedArrayType::FLOAT32:
arr = JS_NewFloat32Array(__cx, (uint32_t)byteLength/4);
tmpData = JS_GetFloat32ArrayData(arr, &isShared, nogc);
break;
case TypedArrayType::FLOAT64:
arr = JS_NewFloat64Array(__cx, (uint32_t)byteLength/8);
tmpData = JS_GetFloat64ArrayData(arr, &isShared, nogc);
break;
default:
assert(false); // Should never go here.
break;
}
//If data has content,then will copy data into buffer,or will only clear buffer.
if (data) {
memcpy(tmpData, (const void*)data, byteLength);
}else{
memset(tmpData, 0, byteLength);
}
Object* obj = Object::_createJSObject(nullptr, arr);
return obj;
}
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)
{
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, JS::UndefinedHandleValue, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_SHARED, getter, setter);
}
bool Object::call(const ValueArray& args, Object* thisObject, Value* rval/* = nullptr*/)
{
assert(isFunction());
JS::AutoValueVector 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);
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());
bool ok = JS_DefineFunction(__cx, object, funcName, func, 0, JSPROP_ENUMERATE | JSPROP_PERMANENT);
return ok;
}
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(__cx, _getJSObject());
}
bool Object::_isNativeFunction(JSNative func) const
{
JSObject* obj = _getJSObject();
return JS_ObjectIsFunction(__cx, 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;
*ptr = (uint8_t*)JS_GetArrayBufferViewData(_getJSObject(), &isShared, nogc);
*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;
*ptr = (uint8_t*)JS_GetArrayBufferData(_getJSObject(), &isShared, nogc);
*length = JS_GetArrayBufferByteLength(_getJSObject());
return (*ptr != nullptr);
}
bool Object::getAllKeys(std::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;
std::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::getPrivateData() const
{
if (_privateData == nullptr)
{
JS::RootedObject obj(__cx, _getJSObject());
const_cast<Object*>(this)->_privateData = internal::getPrivate(__cx, obj);
}
return _privateData;
}
void Object::setPrivateData(void* data)
{
assert(_privateData == nullptr);
assert(NativePtrToObjectMap::find(data) == NativePtrToObjectMap::end());
assert(_cls != nullptr);
JS::RootedObject obj(__cx, _getJSObject());
internal::setPrivate(__cx, obj, data, _finalizeCb);
NativePtrToObjectMap::emplace(data, this);
_privateData = data;
}
void Object::clearPrivateData(bool clearMapping)
{
if (_privateData != nullptr)
{
if (clearMapping)
NativePtrToObjectMap::erase(_privateData);
JS::RootedObject obj(__cx, _getJSObject());
internal::clearPrivate(__cx, obj);
_privateData = 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();
NonRefNativePtrCreatedByCtorMap::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::GCPolicy<JSObject*>::initial());
_root = new JS::PersistentRootedObject(__cx, _heap);
_heap = JS::GCPolicy<JSObject*>::initial();
}
void Object::unprotect()
{
if (_root == nullptr)
return;
assert(_currentVMId == ScriptEngine::getInstance()->getVMId());
assert(_heap == JS::GCPolicy<JSObject*>::initial());
_heap = *_root;
delete _root;
_root = nullptr;
}
void Object::reset()
{
if (_root != nullptr)
{
delete _root;
_root = nullptr;
}
_heap = JS::GCPolicy<JSObject*>::initial();
}
/* Tracing makes no sense in the rooted case, because JS::PersistentRooted
* already takes care of that. */
void Object::trace(JSTracer* tracer, void* data)
{
assert(!isRooted());
JS::TraceEdge(tracer, &_heap, "ccobj 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(void* data)
{
assert(!isRooted());
bool isGarbageCollected = false;
internal::PrivateData* internalData = nullptr;
JSObject* oldPtr = _heap.unbarrieredGet();
if (_heap.unbarrieredGet() != nullptr)
JS_UpdateWeakPointerAfterGC(&_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

View File

@@ -0,0 +1,399 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.hpp"
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
#include "Base.h"
#include "../Value.hpp"
#include "../RefCounter.hpp"
namespace se {
class Class;
/**
* 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, void* data, 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(void* data, size_t byteLength);
/**
* @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.
*/
bool getProperty(const char* name, Value* 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);
/**
* @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);
/**
* @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(std::vector<std::string>* allKeys) const;
/**
* @brief Sets a pointer to private data on an object.
* @param[in] data A void* to set as the object's private data.
* @note This method will associate private data with se::Object by std::unordered_map::emplace.
* It's used for search a se::Object via a void* private data.
*/
void setPrivateData(void* data);
/**
* @brief Gets an object's private data.
* @return A void* that is the object's private data, if the object has private data, otherwise nullptr.
*/
void* getPrivateData() const;
/**
* @brief Clears private data of an object.
* @param clearMapping Whether to clear the mapping of native object & se::Object.
*/
void clearPrivateData(bool clearMapping = true);
/**
* @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);
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();
void trace(JSTracer* tracer, void* data);
bool updateAfterGC(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 */
void* _privateData;
Class* _cls;
JSFinalizeOp _finalizeCb;
uint32_t _rootCount;
uint32_t _currentVMId;
friend class ScriptEngine;
};
extern std::unordered_map<Object*, void*> __objectMap; // Currently, the value `void*` is always nullptr
} // namespace se {
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,310 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.hpp"
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
#include "Base.h"
namespace se {
class Object;
class Class;
class Value;
extern Class* __jsb_CCPrivateData_class;
/**
* 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 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);
/**
* 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 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 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; }
// 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(JSContext* cx, JSCompartment* comp, void* data);
static void onWeakPointerZoneGroupCallback(JSContext* cx, void* data);
bool getScript(const std::string& path, JS::MutableHandleScript script);
bool compileScript(const std::string& path, JS::MutableHandleScript script);
JSContext* _cx;
JSCompartment* _oldCompartment;
Object* _globalObj;
Object* _debugGlobalObj;
FileOperationDelegate _fileOperationDelegate;
std::vector<RegisterCallback> _registerCallbackArray;
std::chrono::steady_clock::time_point _startTime;
std::vector<std::function<void()>> _beforeInitHookArray;
std::vector<std::function<void()>> _afterInitHookArray;
std::vector<std::function<void()>> _beforeCleanupHookArray;
std::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

View File

@@ -0,0 +1,33 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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 "ScriptEngine.hpp"
#include "Class.hpp"
#include "Object.hpp"
#include "../Value.hpp"
#include "../State.hpp"
#include "HelperMacros.h"
#include "Utils.hpp"

View File

@@ -0,0 +1,280 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.hpp"
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
#include "Class.hpp"
#include "Object.hpp"
#include "ScriptEngine.hpp"
namespace se {
namespace internal {
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)
{
char* str = JS_EncodeStringToUTF8(cx, jsStr);
std::string ret(str);
JS_free(cx, str);
return ret;
}
void jsToSeArgs(JSContext* cx, int argc, const JS::CallArgs& argv, ValueArray* outArr)
{
outArr->reserve(argc);
for (int i = 0; i < argc; ++i)
{
Value v;
jsToSeValue(cx, argv[i], &v);
outArr->push_back(v);
}
}
void seToJsArgs(JSContext* cx, const ValueArray& args, JS::AutoValueVector* 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;
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());
void* nativeObj = getPrivate(cx, jsobj);
if (nativeObj != nullptr)
{
object = Object::getObjectWithPtr(nativeObj);
}
if (object == nullptr)
{
object = Object::_createJSObject(nullptr, jsval.toObjectOrNull());
}
v->setObject(object, true);
object->decRef();
}
else if (jsval.isNull())
{
v->setNull();
}
else if (jsval.isUndefined())
{
v->setUndefined();
}
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);
}
const char* KEY_PRIVATE_DATA = "__cc_private_data";
bool hasPrivate(JSContext* cx, JS::HandleObject obj)
{
bool found = false;
const JSClass* cls = JS_GetClass(obj);
found = !!(cls->flags & JSCLASS_HAS_PRIVATE);
if (!found)
{
JS::RootedObject jsobj(cx, obj);
if (JS_HasProperty(cx, jsobj, KEY_PRIVATE_DATA, &found) && found)
{
return true;
}
}
return found;
}
void* getPrivate(JSContext* cx, JS::HandleObject obj)
{
bool found = false;
const JSClass* cls = JS_GetClass(obj);
found = !!(cls->flags & JSCLASS_HAS_PRIVATE);
if (found)
{
return JS_GetPrivate(obj);
}
if (JS_HasProperty(cx, obj, KEY_PRIVATE_DATA, &found) && found)
{
JS::RootedValue jsData(cx);
if (JS_GetProperty(cx, obj, KEY_PRIVATE_DATA, &jsData))
{
PrivateData* privateData = (PrivateData*)JS_GetPrivate(jsData.toObjectOrNull());
return privateData->data;
}
}
return nullptr;
}
void setPrivate(JSContext* cx, JS::HandleObject obj, void* data, JSFinalizeOp finalizeCb)
{
bool found = false;
const JSClass* jsCls = JS_GetClass(obj);
found = !!(jsCls->flags & JSCLASS_HAS_PRIVATE);
if (found)
{
JS_SetPrivate(obj, data);
}
else
{
assert(finalizeCb);
Object* privateObj = Object::createObjectWithClass(__jsb_CCPrivateData_class);
PrivateData* privateData = (PrivateData*)malloc(sizeof(PrivateData));
privateData->data = data;
privateData->finalizeCb = finalizeCb;
JS_SetPrivate(privateObj->_getJSObject(), privateData);
JS::RootedValue privateVal(cx, JS::ObjectValue(*privateObj->_getJSObject()));
JS_SetProperty(cx, obj, KEY_PRIVATE_DATA, privateVal);
privateObj->decRef();
}
}
void clearPrivate(JSContext* cx, JS::HandleObject obj)
{
bool found = false;
const JSClass* cls = JS_GetClass(obj);
found = !!(cls->flags & JSCLASS_HAS_PRIVATE);
if (found)
{
JS_SetPrivate(obj, nullptr);
}
else if (JS_HasProperty(cx, obj, KEY_PRIVATE_DATA, &found) && found)
{
JS::RootedValue jsData(cx);
assert(JS_GetProperty(cx, obj, KEY_PRIVATE_DATA, &jsData));
PrivateData* privateData = (PrivateData*)JS_GetPrivate(jsData.toObjectOrNull());
free(privateData);
JS_SetPrivate(jsData.toObjectOrNull(), nullptr);
bool ok = JS_DeleteProperty(cx, obj, KEY_PRIVATE_DATA);
assert(ok);
}
}
}} // namespace se { namespace internal {
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM

View File

@@ -0,0 +1,66 @@
/****************************************************************************
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos2d-x.org
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.hpp"
#if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
#include "Base.h"
#include "../Value.hpp"
namespace se {
class Class;
namespace internal {
struct PrivateData
{
void* data;
JSFinalizeOp finalizeCb;
};
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::AutoValueVector* 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);
void setPrivate(JSContext* cx, JS::HandleObject obj, void* data, JSFinalizeOp finalizeCb);
void clearPrivate(JSContext* cx, JS::HandleObject obj);
} // namespace internal {
} // namespace se {
#endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM