Skip to content

Commit

Permalink
Fix restart crash on HarmonyOS NEXT platform when using JSVM.
Browse files Browse the repository at this point in the history
  • Loading branch information
qiuguohua committed Feb 8, 2025
1 parent 4a88af7 commit 8df655d
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 57 deletions.
42 changes: 18 additions & 24 deletions native/cocos/bindings/jswrapper/jsvm/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,17 @@

namespace se {
std::unique_ptr<std::unordered_map<Object*, void*>> __objectMap; // Currently, the value `void*` is always nullptr
std::set<Object*> Object::objBaseSet = {};

bool Object::restarting = false;


Object::Object() {}
Object::~Object() {
if(restarting) {
objBaseSet.insert(this);
}
if (__objectMap) {
__objectMap->erase(this);
}

delete _privateObject;
_privateObject = nullptr;
}

Object* Object::createObjectWithClass(Class* cls) {
Expand Down Expand Up @@ -652,7 +651,6 @@ std::string Object::toString() const {
}

void Object::root() {
JSVM_Status status;
if (_rootCount == 0) {
uint32_t result = 0;
_objRef.incRef(_env);
Expand All @@ -661,7 +659,6 @@ void Object::root() {
}

void Object::unroot() {
JSVM_Status status;
if (_rootCount > 0) {
--_rootCount;
if (_rootCount == 0) {
Expand Down Expand Up @@ -704,37 +701,34 @@ void Object::weakCallback(JSVM_Env env, void* nativeObject, void* finalizeHint /
}
void* rawPtr = reinterpret_cast<Object*>(finalizeHint)->_privateData;
Object* seObj = reinterpret_cast<Object*>(finalizeHint);

auto it = objBaseSet.find(seObj);
if(it != objBaseSet.end()) {
if (seObj->_onCleaingPrivateData) { //called by cleanPrivateData, not release seObj;
return;
}

if (seObj->_onCleaingPrivateData) { //called by cleanPrivateData, not release seObj;
if(!NativePtrToObjectMap::isValid()) {
return;
}
if (seObj->_clearMappingInFinalizer && rawPtr != nullptr) {
auto iter = NativePtrToObjectMap::find(rawPtr);
if (iter != NativePtrToObjectMap::end()) {
if (seObj->_finalizeCb != nullptr) {
seObj->_finalizeCb(env, finalizeHint, finalizeHint);
} else {
assert(seObj->_getClass() != nullptr);
if (seObj->_getClass()->_getFinalizeFunction() != nullptr) {
seObj->_getClass()->_getFinalizeFunction()(env, finalizeHint, finalizeHint);
}
}
seObj->decRef();
NativePtrToObjectMap::erase(iter);
} else {
SE_LOGE("not find ptr in NativePtrToObjectMap");
}
}

if (seObj->_finalizeCb != nullptr) {
seObj->_finalizeCb(env, finalizeHint, finalizeHint);
} else {
assert(seObj->_getClass() != nullptr);
if (seObj->_getClass()->_getFinalizeFunction() != nullptr) {
seObj->_getClass()->_getFinalizeFunction()(env, finalizeHint, finalizeHint);
}
}
seObj->decRef();
}
}

void Object::setup() {
restarting = false;
__objectMap = std::make_unique<std::unordered_map<Object*, void*>>();
}

Expand All @@ -749,11 +743,11 @@ void Object::cleanup() {
obj = e.second;

if (obj->_finalizeCb != nullptr) {
obj->_finalizeCb(ScriptEngine::getEnv(), nativeObj, nullptr);
obj->_finalizeCb(ScriptEngine::getEnv(), obj, nullptr);
} else {
if (obj->_getClass() != nullptr) {
if (obj->_getClass()->_getFinalizeFunction() != nullptr) {
obj->_getClass()->_getFinalizeFunction()(ScriptEngine::getEnv(), nativeObj, nullptr);
obj->_getClass()->_getFinalizeFunction()(ScriptEngine::getEnv(), obj, nullptr);
}
}
}
Expand Down
6 changes: 0 additions & 6 deletions native/cocos/bindings/jswrapper/jsvm/Object.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,6 @@ class Object : public RefCounter {
BIGINT64,
BIGUINT64
};

static std::set<Object*> objBaseSet;
static bool restarting;
static void resetBaseSet() {
objBaseSet.erase(objBaseSet.begin(), objBaseSet.end());
}

using BufferContentsFreeFunc = void (*)(void *contents, size_t byteLength, void *userData);

Expand Down
57 changes: 30 additions & 27 deletions native/cocos/bindings/jswrapper/jsvm/ScriptEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,14 @@ SE_BIND_FUNC(JSB_console_assert)
ScriptEngine *gSriptEngineInstance = nullptr;

ScriptEngine::ScriptEngine() {
static bool initialized = false;
if (initialized) {
return;
}
JSVM_InitOptions initOptions;
memset(&initOptions, 0, sizeof(initOptions));
OH_JSVM_Init(&initOptions);
initialized = true;
OH_JSVM_Init(nullptr);
gSriptEngineInstance = this;
};

ScriptEngine::~ScriptEngine() = default;
ScriptEngine::~ScriptEngine() {
cleanup();
gSriptEngineInstance = nullptr;
};

void ScriptEngine::setFileOperationDelegate(const FileOperationDelegate &delegate) {
_fileOperationDelegate = delegate;
Expand Down Expand Up @@ -303,6 +300,21 @@ bool ScriptEngine::init() {

Object *ScriptEngine::getGlobalObject() const { return _globalObj; }

void ScriptEngine::closeEngine() {
JSVM_Env env = _env;
_env = nullptr;

JSVM_Status status;
NODE_API_CALL(status, env, OH_JSVM_CloseEnvScope(env, _envScope));
NODE_API_CALL(status, env, OH_JSVM_DestroyEnv(env));
NODE_API_CALL(status, env, OH_JSVM_CloseVMScope(_vm, _vmScope));
NODE_API_CALL(status, env, OH_JSVM_DestroyVM(_vm));
_envScope = nullptr;
env = nullptr;
_vmScope = nullptr;
_vm = nullptr;
}

bool ScriptEngine::start() {
bool ok = true;
if (!init()) {
Expand Down Expand Up @@ -337,43 +349,34 @@ void ScriptEngine::cleanup() {
if (!_isValid) {
return;
}
Object::restarting = true;
Object::resetBaseSet();

SE_LOGD("ScriptEngine::cleanup begin ...\n");
_isInCleanup = true;
se::AutoHandleScope hs;

//cc::events::ScriptEngine::broadcast(cc::ScriptEngineEvent::BEFORE_CLEANUP);

do{
se::AutoHandleScope hs;
for (const auto &hook : _beforeCleanupHookArray) {
hook();
}
_beforeCleanupHookArray.clear();
}while (0);
_beforeCleanupHookArray.clear();


SAFE_DEC_REF(_globalObj);
Object::cleanup();
Class::cleanup();
garbageCollect();


__oldConsoleLog.setUndefined();
__oldConsoleDebug.setUndefined();
__oldConsoleInfo.setUndefined();
__oldConsoleWarn.setUndefined();
__oldConsoleError.setUndefined();
__oldConsoleAssert.setUndefined();
garbageCollect();

JSVM_Env env = _env;
_env = nullptr;

JSVM_Status status;
NODE_API_CALL(status, env, OH_JSVM_CloseEnvScope(env, _envScope));

NODE_API_CALL(status, env, OH_JSVM_DestroyEnv(env));
NODE_API_CALL(status, env, OH_JSVM_CloseVMScope(_vm, _vmScope));
NODE_API_CALL(status, env, OH_JSVM_DestroyVM(_vm));
_envScope = nullptr;
env = nullptr;
_vmScope = nullptr;
_vm = nullptr;

_globalObj = nullptr;
_isValid = false;
Expand Down
5 changes: 5 additions & 0 deletions native/cocos/bindings/jswrapper/jsvm/ScriptEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ class ScriptEngine {
};
ScriptEngine();
~ScriptEngine();
/**
* @brief Shut down the JSVM engine, because cleanup doesn't destroy all objects immediately.
*/
void closeEngine();

/**
* @brief Sets the delegate for file operation.
* @param delegate[in] The delegate instance for file operation.
Expand Down
4 changes: 4 additions & 0 deletions native/cocos/engine/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ void Engine::destroy() {
if (cc::render::getRenderingModule()) {
cc::render::Factory::destroy(cc::render::getRenderingModule());
}
#if(CC_PLATFORM == CC_PLATFORM_OPENHARMONY && SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_JSVM)
// When using JSVM, not all objects are destroyed during cleanup, so we need to close JSVM at the end.
_scriptEngine->closeEngine();
#endif

CC_SAFE_DESTROY_AND_DELETE(_gfxDevice);
delete _fs;
Expand Down

0 comments on commit 8df655d

Please sign in to comment.