| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836 |
- /****************************************************************************
- 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 "ScriptEngine.hpp"
- #include "platform/CCPlatformConfig.h"
- #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8
- #include "Object.hpp"
- #include "Class.hpp"
- #include "Utils.hpp"
- #include "../State.hpp"
- #include "../MappingUtils.hpp"
- #if SE_ENABLE_INSPECTOR
- #include "debugger/inspector_agent.h"
- #include "debugger/env.h"
- #include "debugger/node.h"
- #endif
- #include <sstream>
- #define EXPOSE_GC "__jsb_gc__"
- uint32_t __jsbInvocationCount = 0;
- uint32_t __jsbStackFrameLimit = 20;
- #define RETRUN_VAL_IF_FAIL(cond, val) \
- if (!(cond)) return val
- namespace se {
- Class* __jsb_CCPrivateData_class = nullptr;
- namespace {
- ScriptEngine* __instance = nullptr;
- void __log(const v8::FunctionCallbackInfo<v8::Value>& info)
- {
- if (info[0]->IsString())
- {
- v8::String::Utf8Value utf8(v8::Isolate::GetCurrent(), info[0]);
- SE_LOGD("JS: %s\n", *utf8);
- }
- }
- void __forceGC(const v8::FunctionCallbackInfo<v8::Value>& info)
- {
- ScriptEngine::getInstance()->garbageCollect();
- }
- std::string stackTraceToString(v8::Local<v8::StackTrace> stack)
- {
- std::string stackStr;
- if (stack.IsEmpty())
- return stackStr;
- char tmp[100] = {0};
- for (int i = 0, e = stack->GetFrameCount(); i < e; ++i)
- {
- v8::Local<v8::StackFrame> frame = stack->GetFrame(v8::Isolate::GetCurrent(), i);
- v8::Local<v8::String> script = frame->GetScriptName();
- std::string scriptName;
- if (!script.IsEmpty())
- {
- scriptName = *v8::String::Utf8Value(v8::Isolate::GetCurrent(), script);
- }
- v8::Local<v8::String> func = frame->GetFunctionName();
- std::string funcName;
- if (!func.IsEmpty())
- {
- funcName = *v8::String::Utf8Value(v8::Isolate::GetCurrent(), func);
- }
- stackStr += "[";
- snprintf(tmp, sizeof(tmp), "%d", i);
- stackStr += tmp;
- stackStr += "]";
- stackStr += (funcName.empty() ? "anonymous" : funcName.c_str());
- stackStr += "@";
- stackStr += (scriptName.empty() ? "(no filename)" : scriptName.c_str());
- stackStr += ":";
- snprintf(tmp, sizeof(tmp), "%d", frame->GetLineNumber());
- stackStr += tmp;
- if (i < (e-1))
- {
- stackStr += "\n";
- }
- }
- return stackStr;
- }
- se::Value __oldConsoleLog;
- se::Value __oldConsoleDebug;
- se::Value __oldConsoleInfo;
- se::Value __oldConsoleWarn;
- se::Value __oldConsoleError;
- se::Value __oldConsoleAssert;
- bool JSB_console_format_log(State& s, const char* prefix, int msgIndex = 0)
- {
- if (msgIndex < 0)
- return false;
- const auto& args = s.args();
- int argc = (int)args.size();
- if ((argc - msgIndex) == 1)
- {
- std::string msg = args[msgIndex].toStringForce();
- SE_LOGD("JS: %s%s\n", prefix, msg.c_str());
- }
- else if (argc > 1)
- {
- std::string msg = args[msgIndex].toStringForce();
- size_t pos;
- for (int i = (msgIndex+1); i < argc; ++i)
- {
- pos = msg.find("%");
- if (pos != std::string::npos && pos != (msg.length()-1) && (msg[pos+1] == 'd' || msg[pos+1] == 's' || msg[pos+1] == 'f'))
- {
- msg.replace(pos, 2, args[i].toStringForce());
- }
- else
- {
- msg += " " + args[i].toStringForce();
- }
- }
- SE_LOGD("JS: %s%s\n", prefix, msg.c_str());
- }
- return true;
- }
- bool JSB_console_log(State& s)
- {
- JSB_console_format_log(s, "");
- __oldConsoleLog.toObject()->call(s.args(), s.thisObject());
- return true;
- }
- SE_BIND_FUNC(JSB_console_log)
- bool JSB_console_debug(State& s)
- {
- JSB_console_format_log(s, "[DEBUG]: ");
- __oldConsoleDebug.toObject()->call(s.args(), s.thisObject());
- return true;
- }
- SE_BIND_FUNC(JSB_console_debug)
- bool JSB_console_info(State& s)
- {
- JSB_console_format_log(s, "[INFO]: ");
- __oldConsoleInfo.toObject()->call(s.args(), s.thisObject());
- return true;
- }
- SE_BIND_FUNC(JSB_console_info)
- bool JSB_console_warn(State& s)
- {
- JSB_console_format_log(s, "[WARN]: ");
- __oldConsoleWarn.toObject()->call(s.args(), s.thisObject());
- return true;
- }
- SE_BIND_FUNC(JSB_console_warn)
- bool JSB_console_error(State& s)
- {
- JSB_console_format_log(s, "[ERROR]: ");
- __oldConsoleError.toObject()->call(s.args(), s.thisObject());
- return true;
- }
- SE_BIND_FUNC(JSB_console_error)
- bool JSB_console_assert(State& s)
- {
- const auto& args = s.args();
- if (!args.empty())
- {
- if (args[0].isBoolean() && !args[0].toBoolean())
- {
- JSB_console_format_log(s, "[ASSERT]: ", 1);
- __oldConsoleAssert.toObject()->call(s.args(), s.thisObject());
- }
- }
- return true;
- }
- SE_BIND_FUNC(JSB_console_assert)
- } // namespace {
- void ScriptEngine::callExceptionCallback(const char* location, const char* message, const char *stack) {
- if (_nativeExceptionCallback) {
- _nativeExceptionCallback(location, message, stack);
- }
- if (_jsExceptionCallback) {
- _jsExceptionCallback(location, message, stack);
- }
- }
- void ScriptEngine::onFatalErrorCallback(const char* location, const char* message)
- {
- std::string errorStr = "[FATAL ERROR] location: ";
- errorStr += location;
- errorStr += ", message: ";
- errorStr += message;
- SE_LOGE("%s\n", errorStr.c_str());
- getInstance()->callExceptionCallback(location, message, "(no stack information)");
- }
- void ScriptEngine::onOOMErrorCallback(const char* location, bool is_heap_oom)
- {
- std::string errorStr = "[OOM ERROR] location: ";
- errorStr += location;
- std::string message;
- message = "is heap out of memory: ";
- if (is_heap_oom)
- message += "true";
- else
- message += "false";
- errorStr += ", " + message;
- SE_LOGE("%s\n", errorStr.c_str());
- getInstance()->callExceptionCallback(location, message.c_str(), "(no stack information)");
-
- }
- void ScriptEngine::onMessageCallback(v8::Local<v8::Message> message, v8::Local<v8::Value> data)
- {
- ScriptEngine* thiz = getInstance();
- v8::Local<v8::String> msg = message->Get();
- Value msgVal;
- internal::jsToSeValue(v8::Isolate::GetCurrent(), msg, &msgVal);
- assert(msgVal.isString());
- v8::ScriptOrigin origin = message->GetScriptOrigin();
- Value resouceNameVal;
- internal::jsToSeValue(v8::Isolate::GetCurrent(), origin.ResourceName(), &resouceNameVal);
- Value line;
- internal::jsToSeValue(v8::Isolate::GetCurrent(), origin.ResourceLineOffset(), &line);
- Value column;
- internal::jsToSeValue(v8::Isolate::GetCurrent(), origin.ResourceColumnOffset(), &column);
- std::string location = resouceNameVal.toStringForce() + ":" + line.toStringForce() + ":" + column.toStringForce();
- std::string errorStr = msgVal.toString() + ", location: " + location;
- std::string stackStr = stackTraceToString(message->GetStackTrace());
- if (!stackStr.empty())
- {
- if (line.toInt32() == 0)
- {
- location = "(see stack)";
- }
- errorStr += "\nSTACK:\n" + stackStr;
- }
- SE_LOGE("ERROR: %s\n", errorStr.c_str());
- thiz->callExceptionCallback(location.c_str(), msgVal.toString().c_str(), stackStr.c_str());
- if (!thiz->_isErrorHandleWorking)
- {
- thiz->_isErrorHandleWorking = true;
- Value errorHandler;
- if (thiz->_globalObj && thiz->_globalObj->getProperty("__errorHandler", &errorHandler) && errorHandler.isObject() && errorHandler.toObject()->isFunction())
- {
- ValueArray args;
- args.push_back(resouceNameVal);
- args.push_back(line);
- args.push_back(msgVal);
- args.push_back(Value(stackStr));
- errorHandler.toObject()->call(args, thiz->_globalObj);
- }
- thiz->_isErrorHandleWorking = false;
- }
- else
- {
- SE_LOGE("ERROR: __errorHandler has exception\n");
- }
- }
- void ScriptEngine::onPromiseRejectCallback(v8::PromiseRejectMessage msg)
- {
- v8::Isolate *isolate = getInstance()->_isolate;
- v8::HandleScope scope(isolate);
- std::stringstream ss;
- auto event = msg.GetEvent();
- auto value = msg.GetValue();
- const char *eventName = "[invalidatePromiseEvent]";
-
- if(event == v8::kPromiseRejectWithNoHandler) {
- eventName = "unhandledRejectedPromise";
- }else if(event == v8::kPromiseHandlerAddedAfterReject) {
- eventName = "handlerAddedAfterPromiseRejected";
- }else if(event == v8::kPromiseRejectAfterResolved) {
- eventName = "rejectAfterPromiseResolved";
- }else if( event == v8::kPromiseResolveAfterResolved) {
- eventName = "resolveAfterPromiseResolved";
- }
-
- if(!value.IsEmpty()) {
- // prepend error object to stack message
- v8::Local<v8::String> str = value->ToString(isolate->GetCurrentContext()).ToLocalChecked();
- v8::String::Utf8Value valueUtf8(isolate, str);
- ss << *valueUtf8 << std::endl;
- }
-
- auto stackStr = getInstance()->getCurrentStackTrace();
- ss << "stacktrace: " << std::endl;
- ss << stackStr << std::endl;
- getInstance()->callExceptionCallback("", eventName, ss.str().c_str());
-
- }
- void ScriptEngine::privateDataFinalize(void* nativeObj)
- {
- internal::PrivateData* p = (internal::PrivateData*)nativeObj;
- Object::nativeObjectFinalizeHook(p->data);
- assert(p->seObj->getRefCount() == 1);
- p->seObj->decRef();
- free(p);
- }
- ScriptEngine *ScriptEngine::getInstance()
- {
- if (__instance == nullptr)
- {
- __instance = new ScriptEngine();
- }
- return __instance;
- }
- void ScriptEngine::destroyInstance()
- {
- delete __instance;
- __instance = nullptr;
- }
- ScriptEngine::ScriptEngine()
- : _platform(nullptr)
- , _isolate(nullptr)
- , _handleScope(nullptr)
- , _globalObj(nullptr)
- #if SE_ENABLE_INSPECTOR
- , _env(nullptr)
- , _isolateData(nullptr)
- #endif
- , _debuggerServerPort(0)
- , _vmId(0)
- , _isValid(false)
- , _isGarbageCollecting(false)
- , _isInCleanup(false)
- , _isErrorHandleWorking(false)
- {
- _platform = v8::platform::NewDefaultPlatform().release();
- v8::V8::InitializePlatform(_platform);
- std::string flags;
- //NOTICE: spaces are required between flags
- flags.append(" --expose-gc-as=" EXPOSE_GC);
- // flags.append(" --trace-gc"); // v8 trace gc
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
- flags.append(" --jitless");
- #endif
- if(!flags.empty())
- {
- v8::V8::SetFlagsFromString(flags.c_str(), (int)flags.length());
- }
-
- bool ok = v8::V8::Initialize();
- assert(ok);
- }
- ScriptEngine::~ScriptEngine()
- {
- cleanup();
- v8::V8::Dispose();
- v8::V8::ShutdownPlatform();
- delete _platform;
- }
- bool ScriptEngine::init()
- {
- cleanup();
- SE_LOGD("Initializing V8, version: %s\n", v8::V8::GetVersion());
- ++_vmId;
- _engineThreadId = std::this_thread::get_id();
- for (const auto& hook : _beforeInitHookArray)
- {
- hook();
- }
- _beforeInitHookArray.clear();
- v8::Isolate::CreateParams create_params;
- create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
- _isolate = v8::Isolate::New(create_params);
- v8::HandleScope hs(_isolate);
- _isolate->Enter();
- _isolate->SetCaptureStackTraceForUncaughtExceptions(true, __jsbStackFrameLimit, v8::StackTrace::kOverview);
- _isolate->SetFatalErrorHandler(onFatalErrorCallback);
- _isolate->SetOOMErrorHandler(onOOMErrorCallback);
- _isolate->AddMessageListener(onMessageCallback);
- _isolate->SetPromiseRejectCallback(onPromiseRejectCallback);
- _context.Reset(_isolate, v8::Context::New(_isolate));
- _context.Get(_isolate)->Enter();
- NativePtrToObjectMap::init();
- NonRefNativePtrCreatedByCtorMap::init();
-
- Object::setup();
- Class::setIsolate(_isolate);
- Object::setIsolate(_isolate);
- _globalObj = Object::_createJSObject(nullptr, _context.Get(_isolate)->Global());
- _globalObj->root();
- _globalObj->setProperty("window", Value(_globalObj));
- se::Value consoleVal;
- if (_globalObj->getProperty("console", &consoleVal) && consoleVal.isObject())
- {
- consoleVal.toObject()->getProperty("log", &__oldConsoleLog);
- consoleVal.toObject()->defineFunction("log", _SE(JSB_console_log));
- consoleVal.toObject()->getProperty("debug", &__oldConsoleDebug);
- consoleVal.toObject()->defineFunction("debug", _SE(JSB_console_debug));
- consoleVal.toObject()->getProperty("info", &__oldConsoleInfo);
- consoleVal.toObject()->defineFunction("info", _SE(JSB_console_info));
- consoleVal.toObject()->getProperty("warn", &__oldConsoleWarn);
- consoleVal.toObject()->defineFunction("warn", _SE(JSB_console_warn));
- consoleVal.toObject()->getProperty("error", &__oldConsoleError);
- consoleVal.toObject()->defineFunction("error", _SE(JSB_console_error));
- consoleVal.toObject()->getProperty("assert", &__oldConsoleAssert);
- consoleVal.toObject()->defineFunction("assert", _SE(JSB_console_assert));
- }
- _globalObj->setProperty("scriptEngineType", se::Value("V8"));
- _globalObj->defineFunction("log", __log);
- _globalObj->defineFunction("forceGC", __forceGC);
-
-
- _globalObj->getProperty(EXPOSE_GC, &_gcFuncValue);
- if(_gcFuncValue.isObject() && _gcFuncValue.toObject()->isFunction()) {
- _gcFunc = _gcFuncValue.toObject();
- } else {
- _gcFunc = nullptr;
- }
-
- __jsb_CCPrivateData_class = Class::create("__PrivateData", _globalObj, nullptr, nullptr);
- __jsb_CCPrivateData_class->defineFinalizeFunction(privateDataFinalize);
- __jsb_CCPrivateData_class->setCreateProto(false);
- __jsb_CCPrivateData_class->install();
- _isValid = true;
- for (const auto& hook : _afterInitHookArray)
- {
- hook();
- }
- _afterInitHookArray.clear();
- return _isValid;
- }
- void ScriptEngine::cleanup()
- {
- if (!_isValid)
- return;
- SE_LOGD("ScriptEngine::cleanup begin ...\n");
- _isInCleanup = true;
- {
- AutoHandleScope hs;
- for (const auto& hook : _beforeCleanupHookArray)
- {
- hook();
- }
- _beforeCleanupHookArray.clear();
- SAFE_DEC_REF(_globalObj);
- Object::cleanup();
- Class::cleanup();
- garbageCollect();
- __oldConsoleLog.setUndefined();
- __oldConsoleDebug.setUndefined();
- __oldConsoleInfo.setUndefined();
- __oldConsoleWarn.setUndefined();
- __oldConsoleError.setUndefined();
- __oldConsoleAssert.setUndefined();
- #if SE_ENABLE_INSPECTOR
- if (_isolateData != nullptr)
- {
- node::FreeIsolateData(_isolateData);
- _isolateData = nullptr;
- }
- if (_env != nullptr)
- {
- _env->inspector_agent()->Stop();
- _env->CleanupHandles();
- node::FreeEnvironment(_env);
- _env = nullptr;
- }
- #endif
- _context.Get(_isolate)->Exit();
- _context.Reset();
- _isolate->Exit();
- }
- _isolate->Dispose();
- _isolate = nullptr;
- _globalObj = nullptr;
- _isValid = false;
- _registerCallbackArray.clear();
- for (const auto& hook : _afterCleanupHookArray)
- {
- hook();
- }
- _afterCleanupHookArray.clear();
- _isInCleanup = false;
- NativePtrToObjectMap::destroy();
- NonRefNativePtrCreatedByCtorMap::destroy();
- _gcFunc = nullptr;
- SE_LOGD("ScriptEngine::cleanup end ...\n");
- }
- Object* ScriptEngine::getGlobalObject() const
- {
- return _globalObj;
- }
- void ScriptEngine::addBeforeInitHook(const std::function<void()>& hook)
- {
- _beforeInitHookArray.push_back(hook);
- }
- void ScriptEngine::addAfterInitHook(const std::function<void()>& hook)
- {
- _afterInitHookArray.push_back(hook);
- }
- void ScriptEngine::addBeforeCleanupHook(const std::function<void()>& hook)
- {
- _beforeCleanupHookArray.push_back(hook);
- }
- void ScriptEngine::addAfterCleanupHook(const std::function<void()>& hook)
- {
- _afterCleanupHookArray.push_back(hook);
- }
- void ScriptEngine::addRegisterCallback(RegisterCallback cb)
- {
- assert(std::find(_registerCallbackArray.begin(), _registerCallbackArray.end(), cb) == _registerCallbackArray.end());
- _registerCallbackArray.push_back(cb);
- }
- bool ScriptEngine::start()
- {
- if (!init())
- return false;
- se::AutoHandleScope hs;
- // debugger
- if (isDebuggerEnabled())
- {
- #if SE_ENABLE_INSPECTOR
- // V8 inspector stuff, most code are taken from NodeJS.
- _isolateData = node::CreateIsolateData(_isolate, uv_default_loop());
- _env = node::CreateEnvironment(_isolateData, _context.Get(_isolate), 0, nullptr, 0, nullptr);
- node::DebugOptions options;
- options.set_wait_for_connect(_isWaitForConnect);// the program will be hung up until debug attach if _isWaitForConnect = true
- options.set_inspector_enabled(true);
- options.set_port((int)_debuggerServerPort);
- options.set_host_name(_debuggerServerAddr.c_str());
- bool ok = _env->inspector_agent()->Start(_platform, "", options);
- assert(ok);
- #endif
- }
- //
- bool ok = false;
- _startTime = std::chrono::steady_clock::now();
- for (auto cb : _registerCallbackArray)
- {
- ok = cb(_globalObj);
- assert(ok);
- if (!ok)
- break;
- }
- // After ScriptEngine is started, _registerCallbackArray isn't needed. Therefore, clear it here.
- _registerCallbackArray.clear();
- return ok;
- }
- void ScriptEngine::garbageCollect()
- {
- int objSize = __objectMap ? (int)__objectMap->size() : -1;
- SE_LOGD("GC begin ..., (js->native map) size: %d, all objects: %d\n", (int)NativePtrToObjectMap::size(), objSize);
-
- if(_gcFunc == nullptr)
- {
- const double kLongIdlePauseInSeconds = 1.0;
- _isolate->ContextDisposedNotification();
- _isolate->IdleNotificationDeadline(_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
- // By sending a low memory notifications, we will try hard to collect all
- // garbage and will therefore also invoke all weak callbacks of actually
- // unreachable persistent handles.
- _isolate->LowMemoryNotification();
- }
- else
- {
- _gcFunc->call({}, nullptr);
- }
- objSize = __objectMap ? (int)__objectMap->size() : -1;
-
- SE_LOGD("GC end ..., (js->native map) size: %d, all objects: %d\n", (int)NativePtrToObjectMap::size(), objSize);
- }
- bool ScriptEngine::isGarbageCollecting()
- {
- return _isGarbageCollecting;
- }
- void ScriptEngine::_setGarbageCollecting(bool isGarbageCollecting)
- {
- _isGarbageCollecting = isGarbageCollecting;
- }
- bool ScriptEngine::isValid() const
- {
- return _isValid;
- }
- bool ScriptEngine::evalString(const char* script, ssize_t length/* = -1 */, Value* ret/* = nullptr */, const char* fileName/* = nullptr */)
- {
- if(_engineThreadId != std::this_thread::get_id())
- {
- // `evalString` should run in main thread
- assert(false);
- return false;
- }
- assert(script != nullptr);
- if (length < 0)
- length = strlen(script);
- if (fileName == nullptr)
- fileName = "(no filename)";
- // Fix the source url is too long displayed in Chrome debugger.
- std::string sourceUrl = fileName;
- static const std::string prefixKey = "/temp/quick-scripts/";
- size_t prefixPos = sourceUrl.find(prefixKey);
- if (prefixPos != std::string::npos)
- {
- sourceUrl = sourceUrl.substr(prefixPos + prefixKey.length());
- }
- // It is needed, or will crash if invoked from non C++ context, such as invoked from objective-c context(for example, handler of UIKit).
- v8::HandleScope handle_scope(_isolate);
- std::string scriptStr(script, length);
- v8::MaybeLocal<v8::String> source = v8::String::NewFromUtf8(_isolate, scriptStr.c_str(), v8::NewStringType::kNormal);
- if (source.IsEmpty())
- return false;
- v8::MaybeLocal<v8::String> originStr = v8::String::NewFromUtf8(_isolate, sourceUrl.c_str(), v8::NewStringType::kNormal);
- if (originStr.IsEmpty())
- return false;
- v8::ScriptOrigin origin(originStr.ToLocalChecked());
- v8::MaybeLocal<v8::Script> maybeScript = v8::Script::Compile(_context.Get(_isolate), source.ToLocalChecked(), &origin);
- bool success = false;
- if (!maybeScript.IsEmpty())
- {
- v8::TryCatch block(_isolate);
- v8::Local<v8::Script> v8Script = maybeScript.ToLocalChecked();
- v8::MaybeLocal<v8::Value> maybeResult = v8Script->Run(_context.Get(_isolate));
- if (!maybeResult.IsEmpty())
- {
- v8::Local<v8::Value> result = maybeResult.ToLocalChecked();
- if (!result->IsUndefined() && ret != nullptr)
- {
- internal::jsToSeValue(_isolate, result, ret);
- }
- success = true;
- }
- if (block.HasCaught()) {
- v8::Local<v8::Message> message = block.Message();
- SE_LOGE("ScriptEngine::evalString catch exception:\n");
- onMessageCallback(message, v8::Undefined(_isolate));
- }
- }
- if (!success)
- {
- SE_LOGE("ScriptEngine::evalString script %s, failed!\n", fileName);
- }
- return success;
- }
- std::string ScriptEngine::getCurrentStackTrace()
- {
- if (!_isValid)
- return std::string();
- v8::HandleScope hs(_isolate);
- v8::Local<v8::StackTrace> stack = v8::StackTrace::CurrentStackTrace(_isolate, __jsbStackFrameLimit, v8::StackTrace::kOverview);
- return stackTraceToString(stack);
- }
- void ScriptEngine::setFileOperationDelegate(const FileOperationDelegate& delegate)
- {
- _fileOperationDelegate = delegate;
- }
- const ScriptEngine::FileOperationDelegate& ScriptEngine::getFileOperationDelegate() const
- {
- return _fileOperationDelegate;
- }
- bool ScriptEngine::runScript(const std::string& path, Value* ret/* = nullptr */)
- {
- assert(!path.empty());
- assert(_fileOperationDelegate.isValid());
- std::string scriptBuffer = _fileOperationDelegate.onGetStringFromFile(path);
- if (!scriptBuffer.empty())
- {
- return evalString(scriptBuffer.c_str(), scriptBuffer.length(), ret, path.c_str());
- }
- SE_LOGE("ScriptEngine::runScript script %s, buffer is empty!\n", path.c_str());
- return false;
- }
- void ScriptEngine::clearException()
- {
- //IDEA:
- }
- void ScriptEngine::setExceptionCallback(const ExceptionCallback& cb)
- {
- _nativeExceptionCallback = cb;
- }
- void ScriptEngine::setJSExceptionCallback(const ExceptionCallback& cb)
- {
- _jsExceptionCallback = cb;
- }
- v8::Local<v8::Context> ScriptEngine::_getContext() const
- {
- return _context.Get(_isolate);
- }
- void ScriptEngine::enableDebugger(const std::string& serverAddr, uint32_t port, bool isWait)
- {
- _debuggerServerAddr = serverAddr;
- _debuggerServerPort = port;
- _isWaitForConnect = isWait;
- }
- bool ScriptEngine::isDebuggerEnabled() const
- {
- return !_debuggerServerAddr.empty() && _debuggerServerPort > 0;
- }
- void ScriptEngine::mainLoopUpdate()
- {
- // empty implementation
- }
- } // namespace se {
- #endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8
|