JSScript* may be garbage collected before the next time execute the same JS file.

It will crash in JS_ExecuteScript.
This commit is contained in:
James Chen 2016-06-22 16:18:20 +08:00
parent 9fd190d283
commit 67dd4b0684
2 changed files with 51 additions and 27 deletions

View File

@ -101,7 +101,7 @@ static char *_js_log_buf = NULL;
static std::vector<sc_register_sth> registrationList; static std::vector<sc_register_sth> registrationList;
// name ~> JSScript map // name ~> JSScript map
static std::unordered_map<std::string, JSScript*> filename_script; static std::unordered_map<std::string, JS::PersistentRootedScript*> filename_script;
// port ~> socket map // port ~> socket map
static std::unordered_map<int,int> ports_sockets; static std::unordered_map<int,int> ports_sockets;
@ -651,7 +651,7 @@ static std::string RemoveFileExt(const std::string& filePath) {
} }
} }
JSScript* ScriptingCore::getScript(const char *path) JS::PersistentRootedScript* ScriptingCore::getScript(const char *path)
{ {
// a) check jsc file first // a) check jsc file first
std::string byteCodePath = RemoveFileExt(std::string(path)) + BYTE_CODE_FILE_EXT; std::string byteCodePath = RemoveFileExt(std::string(path)) + BYTE_CODE_FILE_EXT;
@ -666,26 +666,31 @@ JSScript* ScriptingCore::getScript(const char *path)
return NULL; return NULL;
} }
void ScriptingCore::compileScript(const char *path, JS::HandleObject global, JSContext* cx) JS::PersistentRootedScript* ScriptingCore::compileScript(const char *path, JS::HandleObject global, JSContext* cx)
{ {
if (!path) { if (!path) {
return; return nullptr;
} }
if (getScript(path)) { JS::PersistentRootedScript* script = getScript(path);
return; if (script != nullptr) {
return script;
}
if (cx == nullptr) {
cx = _cx;
} }
cocos2d::FileUtils *futil = cocos2d::FileUtils::getInstance(); cocos2d::FileUtils *futil = cocos2d::FileUtils::getInstance();
if (cx == NULL) { JSAutoCompartment ac(cx, global);
cx = _cx; script = new (std::nothrow) JS::PersistentRootedScript(cx);
if (script == nullptr) {
return nullptr;
} }
JSAutoCompartment ac(cx, global);
JS::RootedScript script(cx);
JS::RootedObject obj(cx, global); JS::RootedObject obj(cx, global);
bool compileSucceed = false;
// a) check jsc file first // a) check jsc file first
std::string byteCodePath = RemoveFileExt(std::string(path)) + BYTE_CODE_FILE_EXT; std::string byteCodePath = RemoveFileExt(std::string(path)) + BYTE_CODE_FILE_EXT;
@ -696,12 +701,17 @@ void ScriptingCore::compileScript(const char *path, JS::HandleObject global, JSC
Data data = futil->getDataFromFile(byteCodePath); Data data = futil->getDataFromFile(byteCodePath);
if (!data.isNull()) if (!data.isNull())
{ {
script = JS_DecodeScript(cx, data.getBytes(), static_cast<uint32_t>(data.getSize()), nullptr); *script = JS_DecodeScript(cx, data.getBytes(), static_cast<uint32_t>(data.getSize()), nullptr);
}
if (*script) {
compileSucceed = true;
filename_script[byteCodePath] = script;
} }
} }
// b) no jsc file, check js file // b) no jsc file, check js file
if (!script) if (!(*script))
{ {
/* Clear any pending exception from previous failed decoding. */ /* Clear any pending exception from previous failed decoding. */
ReportException(cx); ReportException(cx);
@ -717,18 +727,27 @@ void ScriptingCore::compileScript(const char *path, JS::HandleObject global, JSC
std::string jsFileContent = futil->getStringFromFile(fullPath); std::string jsFileContent = futil->getStringFromFile(fullPath);
if (!jsFileContent.empty()) if (!jsFileContent.empty())
{ {
ok = JS::Compile(cx, obj, op, jsFileContent.c_str(), jsFileContent.size(), &script); ok = JS::Compile(cx, obj, op, jsFileContent.c_str(), jsFileContent.size(), &(*script));
} }
#else #else
ok = JS::Compile(cx, obj, op, fullPath.c_str(), &script); ok = JS::Compile(cx, obj, op, fullPath.c_str(), &(*script));
#endif #endif
if (ok) { if (ok) {
compileSucceed = true;
filename_script[fullPath] = script; filename_script[fullPath] = script;
} }
} }
else { else {
filename_script[byteCodePath] = script; filename_script[byteCodePath] = script;
} }
if (compileSucceed) {
return script;
} else {
LOGD("ScriptingCore:: compileScript fail:%s", path);
CC_SAFE_DELETE(script);
return nullptr;
}
} }
void ScriptingCore::cleanScript(const char *path) void ScriptingCore::cleanScript(const char *path)
@ -737,6 +756,7 @@ void ScriptingCore::cleanScript(const char *path)
auto it = filename_script.find(byteCodePath); auto it = filename_script.find(byteCodePath);
if (it != filename_script.end()) if (it != filename_script.end())
{ {
delete it->second;
filename_script.erase(it); filename_script.erase(it);
} }
@ -744,11 +764,12 @@ void ScriptingCore::cleanScript(const char *path)
it = filename_script.find(fullPath); it = filename_script.find(fullPath);
if (it != filename_script.end()) if (it != filename_script.end())
{ {
delete it->second;
filename_script.erase(it); filename_script.erase(it);
} }
} }
std::unordered_map<std::string, JSScript*> &ScriptingCore::getFileScript() std::unordered_map<std::string, JS::PersistentRootedScript*>& ScriptingCore::getFileScript()
{ {
return filename_script; return filename_script;
} }
@ -769,13 +790,16 @@ bool ScriptingCore::runScript(const char *path, JS::HandleObject global, JSConte
cx = _cx; cx = _cx;
} }
compileScript(path,global,cx); auto script = compileScript(path, global, cx);
JS::RootedScript script(cx, getScript(path)); if (script == nullptr) {
return false;
}
bool evaluatedOK = false; bool evaluatedOK = false;
if (script) { if (script) {
JS::RootedValue rval(cx); JS::RootedValue rval(cx);
JSAutoCompartment ac(cx, global); JSAutoCompartment ac(cx, global);
evaluatedOK = JS_ExecuteScript(cx, global, script, &rval); evaluatedOK = JS_ExecuteScript(cx, global, *script, &rval);
if (false == evaluatedOK) { if (false == evaluatedOK) {
cocos2d::log("Evaluating %s failed (evaluatedOK == JS_FALSE)", path); cocos2d::log("Evaluating %s failed (evaluatedOK == JS_FALSE)", path);
JS_ReportPendingException(cx); JS_ReportPendingException(cx);
@ -797,13 +821,13 @@ bool ScriptingCore::requireScript(const char *path, JS::HandleObject global, JSC
cx = _cx; cx = _cx;
} }
compileScript(path,global,cx); auto script = compileScript(path, global, cx);
JS::RootedScript script(cx, getScript(path));
bool evaluatedOK = false; bool evaluatedOK = false;
if (script) if (script)
{ {
JSAutoCompartment ac(cx, global); JSAutoCompartment ac(cx, global);
evaluatedOK = JS_ExecuteScript(cx, global, script, jsvalRet); evaluatedOK = JS_ExecuteScript(cx, global, (*script), jsvalRet);
if (false == evaluatedOK) if (false == evaluatedOK)
{ {
cocos2d::log("(evaluatedOK == JS_FALSE)"); cocos2d::log("(evaluatedOK == JS_FALSE)");

View File

@ -289,7 +289,7 @@ public:
@param path @~english The script file path @param path @~english The script file path
@return @~english Script object @return @~english Script object
*/ */
JSScript* getScript(const char *path); JS::PersistentRootedScript* getScript(const char *path);
/**@~english /**@~english
* Compile the specified js file * Compile the specified js file
@ -297,7 +297,7 @@ public:
* @param global @~english The js global object * @param global @~english The js global object
* @param cx @~english The js context * @param cx @~english The js context
*/ */
void compileScript(const char *path, JS::HandleObject global, JSContext* cx = NULL); JS::PersistentRootedScript* compileScript(const char *path, JS::HandleObject global, JSContext* cx = NULL);
/**@~english /**@~english
* Run the specified js file * Run the specified js file
@ -345,7 +345,7 @@ public:
* Gets the cached script objects for all executed js file * Gets the cached script objects for all executed js file
* @return @~english The cached script object map * @return @~english The cached script object map
*/ */
std::unordered_map<std::string, JSScript*> &getFileScript(); std::unordered_map<std::string, JS::PersistentRootedScript*>& getFileScript();
/**@~english /**@~english
* Clean all script objects * Clean all script objects
*/ */