Changeset View
Changeset View
Standalone View
Standalone View
source/scriptinterface/ScriptInterface.cpp
Show First 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | struct ScriptInterface_impl | ||||
ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime); | ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime); | ||||
~ScriptInterface_impl(); | ~ScriptInterface_impl(); | ||||
void Register(const char* name, JSNative fptr, uint nargs) const; | void Register(const char* name, JSNative fptr, uint nargs) const; | ||||
// Take care to keep this declaration before heap rooted members. Destructors of heap rooted | // Take care to keep this declaration before heap rooted members. Destructors of heap rooted | ||||
// members have to be called before the runtime destructor. | // members have to be called before the runtime destructor. | ||||
shared_ptr<ScriptRuntime> m_runtime; | shared_ptr<ScriptRuntime> m_runtime; | ||||
JS::PersistentRootedObject m_glob; // global scope object | |||||
boost::rand48* m_rng; | |||||
JS::PersistentRootedObject m_nativeScope; // native function scope object | |||||
friend ScriptInterface::Request; | friend ScriptInterface::Request; | ||||
private: | private: | ||||
JSContext* m_cx; | JSContext* m_cx; | ||||
JSCompartment* m_formerCompartment; | JS::PersistentRootedObject m_glob; // global scope object | ||||
public: | |||||
boost::rand48* m_rng; | |||||
Stan: Any reason we use boost for this? smart pointer? | |||||
wraitiiAuthorUnsubmitted Done Inline ActionsFor the randomness I think. wraitii: For the randomness I think. | |||||
JS::PersistentRootedObject m_nativeScope; // native function scope object | |||||
}; | }; | ||||
ScriptInterface::Request::Request(const ScriptInterface& scriptInterface) : | ScriptInterface::Request::Request(const ScriptInterface& scriptInterface) : | ||||
cx(scriptInterface.m->m_cx) | cx(scriptInterface.m->m_cx) | ||||
{ | { | ||||
JS_BeginRequest(cx); | JS_BeginRequest(cx); | ||||
m_formerCompartment = JS_EnterCompartment(cx, scriptInterface.m->m_glob); | |||||
glob = JS::CurrentGlobalOrNull(cx); | |||||
} | |||||
JS::Value ScriptInterface::Request::globalValue() const | |||||
{ | |||||
return JS::ObjectValue(*glob); | |||||
} | } | ||||
ScriptInterface::Request::~Request() | ScriptInterface::Request::~Request() | ||||
{ | { | ||||
JS_LeaveCompartment(cx, m_formerCompartment); | |||||
JS_EndRequest(cx); | JS_EndRequest(cx); | ||||
} | } | ||||
namespace | namespace | ||||
{ | { | ||||
JSClass global_class = { | JSClass global_class = { | ||||
"global", JSCLASS_GLOBAL_FLAGS, | "global", JSCLASS_GLOBAL_FLAGS, | ||||
nullptr, nullptr, | nullptr, nullptr, | ||||
nullptr, nullptr, | nullptr, nullptr, | ||||
nullptr, nullptr, nullptr, | nullptr, nullptr, nullptr, | ||||
nullptr, nullptr, nullptr, nullptr, | nullptr, nullptr, nullptr, nullptr, | ||||
JS_GlobalObjectTraceHook | JS_GlobalObjectTraceHook | ||||
}; | }; | ||||
void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report) | |||||
{ | |||||
JSAutoRequest rq(cx); | |||||
std::stringstream msg; | |||||
bool isWarning = JSREPORT_IS_WARNING(report->flags); | |||||
msg << (isWarning ? "JavaScript warning: " : "JavaScript error: "); | |||||
if (report->filename) | |||||
{ | |||||
msg << report->filename; | |||||
msg << " line " << report->lineno << "\n"; | |||||
} | |||||
msg << message; | |||||
// If there is an exception, then print its stack trace | |||||
JS::RootedValue excn(cx); | |||||
if (JS_GetPendingException(cx, &excn) && excn.isObject()) | |||||
{ | |||||
JS::RootedValue stackVal(cx); | |||||
JS::RootedObject excnObj(cx, &excn.toObject()); | |||||
JS_GetProperty(cx, excnObj, "stack", &stackVal); | |||||
std::string stackText; | |||||
ScriptInterface::FromJSVal(cx, stackVal, stackText); | |||||
std::istringstream stream(stackText); | |||||
for (std::string line; std::getline(stream, line);) | |||||
msg << "\n " << line; | |||||
} | |||||
if (isWarning) | |||||
LOGWARNING("%s", msg.str().c_str()); | |||||
else | |||||
LOGERROR("%s", msg.str().c_str()); | |||||
// When running under Valgrind, print more information in the error message | |||||
// VALGRIND_PRINTF_BACKTRACE("->"); | |||||
} | |||||
// Functions in the global namespace: | // Functions in the global namespace: | ||||
bool print(JSContext* cx, uint argc, JS::Value* vp) | bool print(JSContext* cx, uint argc, JS::Value* vp) | ||||
{ | { | ||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); | ||||
for (uint i = 0; i < args.length(); ++i) | for (uint i = 0; i < args.length(); ++i) | ||||
{ | { | ||||
std::wstring str; | std::wstring str; | ||||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
if (m->m_rng == NULL) | if (m->m_rng == NULL) | ||||
return false; | return false; | ||||
nbr = generate_uniform_real(*(m->m_rng), 0.0, 1.0); | nbr = generate_uniform_real(*(m->m_rng), 0.0, 1.0); | ||||
return true; | return true; | ||||
} | } | ||||
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) : | ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) : | ||||
m_runtime(runtime), m_glob(runtime->m_rt), m_nativeScope(runtime->m_rt) | m_runtime(runtime), m_cx(runtime->GetGeneralJSContext()), m_glob(runtime->GetJSRuntime()), m_nativeScope(runtime->GetJSRuntime()) | ||||
{ | { | ||||
m_cx = JS_NewContext(m_runtime->m_rt, STACK_CHUNK_SIZE); | |||||
ENSURE(m_cx); | |||||
JS_SetOffthreadIonCompilationEnabled(m_runtime->m_rt, true); | |||||
// For GC debugging: | |||||
// JS_SetGCZeal(m_cx, 2, JS_DEFAULT_ZEAL_FREQ); | |||||
JS_SetContextPrivate(m_cx, NULL); | |||||
JS_SetErrorReporter(m_runtime->m_rt, ErrorReporter); | |||||
JS_SetGlobalJitCompilerOption(m_runtime->m_rt, JSJITCOMPILER_ION_ENABLE, 1); | |||||
JS_SetGlobalJitCompilerOption(m_runtime->m_rt, JSJITCOMPILER_BASELINE_ENABLE, 1); | |||||
JS::RuntimeOptionsRef(m_cx) | |||||
.setExtraWarnings(true) | |||||
.setWerror(false) | |||||
.setStrictMode(true); | |||||
JS::CompartmentOptions opt; | JS::CompartmentOptions opt; | ||||
opt.setVersion(JSVERSION_LATEST); | opt.setVersion(JSVERSION_LATEST); | ||||
// Keep JIT code during non-shrinking GCs. This brings a quite big performance improvement. | // Keep JIT code during non-shrinking GCs. This brings a quite big performance improvement. | ||||
opt.setPreserveJitCode(true); | opt.setPreserveJitCode(true); | ||||
JSAutoRequest rq(m_cx); | JSAutoRequest rq(m_cx); | ||||
JS::RootedObject globalRootedVal(m_cx, JS_NewGlobalObject(m_cx, &global_class, NULL, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt)); | m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt); | ||||
m_formerCompartment = JS_EnterCompartment(m_cx, globalRootedVal); | |||||
ENSURE(JS_InitStandardClasses(m_cx, globalRootedVal)); | JSAutoCompartment autoCmpt(m_cx, m_glob); | ||||
m_glob = globalRootedVal.get(); | |||||
ENSURE(JS_InitStandardClasses(m_cx, m_glob)); | |||||
JS_DefineProperty(m_cx, m_glob, "global", globalRootedVal, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | JS_DefineProperty(m_cx, m_glob, "global", m_glob, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | ||||
m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | ||||
JS_DefineFunction(m_cx, globalRootedVal, "print", ::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | JS_DefineFunction(m_cx, m_glob, "print", ::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | ||||
JS_DefineFunction(m_cx, globalRootedVal, "log", ::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | JS_DefineFunction(m_cx, m_glob, "log", ::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | ||||
JS_DefineFunction(m_cx, globalRootedVal, "warn", ::warn, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | JS_DefineFunction(m_cx, m_glob, "warn", ::warn, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | ||||
JS_DefineFunction(m_cx, globalRootedVal, "error", ::error, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | JS_DefineFunction(m_cx, m_glob, "error", ::error, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | ||||
JS_DefineFunction(m_cx, globalRootedVal, "clone", ::deepcopy, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | JS_DefineFunction(m_cx, m_glob, "clone", ::deepcopy, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | ||||
JS_DefineFunction(m_cx, globalRootedVal, "deepfreeze", ::deepfreeze, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | JS_DefineFunction(m_cx, m_glob, "deepfreeze", ::deepfreeze, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); | ||||
Register("ProfileStart", ::ProfileStart, 1); | Register("ProfileStart", ::ProfileStart, 1); | ||||
Register("ProfileStop", ::ProfileStop, 0); | Register("ProfileStop", ::ProfileStop, 0); | ||||
Register("ProfileAttribute", ::ProfileAttribute, 1); | Register("ProfileAttribute", ::ProfileAttribute, 1); | ||||
runtime->RegisterContext(m_cx); | m_runtime->RegisterCompartment(js::GetObjectCompartment(m_glob)); | ||||
} | } | ||||
ScriptInterface_impl::~ScriptInterface_impl() | ScriptInterface_impl::~ScriptInterface_impl() | ||||
{ | { | ||||
m_runtime->UnRegisterContext(m_cx); | m_runtime->UnRegisterCompartment(js::GetObjectCompartment(m_glob)); | ||||
{ | |||||
JSAutoRequest rq(m_cx); | |||||
JS_LeaveCompartment(m_cx, m_formerCompartment); | |||||
} | |||||
JS_DestroyContext(m_cx); | |||||
} | } | ||||
void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint nargs) const | void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint nargs) const | ||||
{ | { | ||||
JSAutoRequest rq(m_cx); | JSAutoRequest rq(m_cx); | ||||
JSAutoCompartment autoCmpt(m_cx, m_glob); | |||||
JS::RootedObject nativeScope(m_cx, m_nativeScope); | JS::RootedObject nativeScope(m_cx, m_nativeScope); | ||||
JS::RootedFunction func(m_cx, JS_DefineFunction(m_cx, nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)); | JS::RootedFunction func(m_cx, JS_DefineFunction(m_cx, nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)); | ||||
} | } | ||||
ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName, const shared_ptr<ScriptRuntime>& runtime) : | ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName, const shared_ptr<ScriptRuntime>& runtime) : | ||||
m(new ScriptInterface_impl(nativeScopeName, runtime)) | m(new ScriptInterface_impl(nativeScopeName, runtime)) | ||||
{ | { | ||||
// Profiler stats table isn't thread-safe, so only enable this on the main thread | // Profiler stats table isn't thread-safe, so only enable this on the main thread | ||||
if (ThreadUtil::IsMainThread()) | if (ThreadUtil::IsMainThread()) | ||||
{ | { | ||||
if (g_ScriptStatsTable) | if (g_ScriptStatsTable) | ||||
g_ScriptStatsTable->Add(this, debugName); | g_ScriptStatsTable->Add(this, debugName); | ||||
} | } | ||||
Request rq(this); | Request rq(this); | ||||
m_CmptPrivate.pScriptInterface = this; | m_CmptPrivate.pScriptInterface = this; | ||||
JS_SetContextPrivate(rq.cx, (void*)&m_CmptPrivate); | JS_SetCompartmentPrivate(js::GetObjectCompartment(rq.glob), (void*)&m_CmptPrivate); | ||||
} | } | ||||
ScriptInterface::~ScriptInterface() | ScriptInterface::~ScriptInterface() | ||||
{ | { | ||||
if (ThreadUtil::IsMainThread()) | if (ThreadUtil::IsMainThread()) | ||||
{ | { | ||||
if (g_ScriptStatsTable) | if (g_ScriptStatsTable) | ||||
g_ScriptStatsTable->Remove(this); | g_ScriptStatsTable->Remove(this); | ||||
} | } | ||||
} | } | ||||
void ScriptInterface::SetCallbackData(void* pCBData) | void ScriptInterface::SetCallbackData(void* pCBData) | ||||
{ | { | ||||
m_CmptPrivate.pCBData = pCBData; | m_CmptPrivate.pCBData = pCBData; | ||||
} | } | ||||
ScriptInterface::CmptPrivate* ScriptInterface::GetScriptInterfaceAndCBData(JSContext* cx) | ScriptInterface::CmptPrivate* ScriptInterface::GetScriptInterfaceAndCBData(JSContext* cx) | ||||
{ | { | ||||
CmptPrivate* pCmptPrivate = (CmptPrivate*)JS_GetContextPrivate(cx); | CmptPrivate* pCmptPrivate = (CmptPrivate*)JS_GetCompartmentPrivate(js::GetContextCompartment(cx)); | ||||
return pCmptPrivate; | return pCmptPrivate; | ||||
} | } | ||||
bool ScriptInterface::LoadGlobalScripts() | bool ScriptInterface::LoadGlobalScripts() | ||||
{ | { | ||||
// Ignore this failure in tests | // Ignore this failure in tests | ||||
if (!g_VFS) | if (!g_VFS) | ||||
Show All 11 Lines | bool ScriptInterface::LoadGlobalScripts() | ||||
return true; | return true; | ||||
} | } | ||||
bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng) | bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng) | ||||
{ | { | ||||
Request rq(this); | Request rq(this); | ||||
JS::RootedValue math(rq.cx); | JS::RootedValue math(rq.cx); | ||||
JS::RootedObject global(rq.cx, m->m_glob); | JS::RootedObject global(rq.cx, rq.glob); | ||||
if (JS_GetProperty(rq.cx, global, "Math", &math) && math.isObject()) | if (JS_GetProperty(rq.cx, global, "Math", &math) && math.isObject()) | ||||
{ | { | ||||
JS::RootedObject mathObj(rq.cx, &math.toObject()); | JS::RootedObject mathObj(rq.cx, &math.toObject()); | ||||
JS::RootedFunction random(rq.cx, JS_DefineFunction(rq.cx, mathObj, "random", Math_random, 0, | JS::RootedFunction random(rq.cx, JS_DefineFunction(rq.cx, mathObj, "random", Math_random, 0, | ||||
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)); | JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)); | ||||
if (random) | if (random) | ||||
{ | { | ||||
m->m_rng = &rng; | m->m_rng = &rng; | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
LOGERROR("ReplaceNondeterministicRNG: failed to replace Math.random"); | LOGERROR("ReplaceNondeterministicRNG: failed to replace Math.random"); | ||||
return false; | return false; | ||||
} | } | ||||
void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) const | void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) const | ||||
{ | { | ||||
m->Register(name, fptr, (uint)nargs); | m->Register(name, fptr, (uint)nargs); | ||||
} | } | ||||
JSRuntime* ScriptInterface::GetJSRuntime() const | JSRuntime* ScriptInterface::GetJSRuntime() const | ||||
{ | { | ||||
return m->m_runtime->m_rt; | return m->m_runtime->GetJSRuntime(); | ||||
} | } | ||||
shared_ptr<ScriptRuntime> ScriptInterface::GetRuntime() const | shared_ptr<ScriptRuntime> ScriptInterface::GetRuntime() const | ||||
{ | { | ||||
return m->m_runtime; | return m->m_runtime; | ||||
} | } | ||||
void ScriptInterface::CallConstructor(JS::HandleValue ctor, JS::HandleValueArray argv, JS::MutableHandleValue out) const | void ScriptInterface::CallConstructor(JS::HandleValue ctor, JS::HandleValueArray argv, JS::MutableHandleValue out) const | ||||
Show All 16 Lines | void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) | ||||
std::string typeName = clasp->name; | std::string typeName = clasp->name; | ||||
if (m_CustomObjectTypes.find(typeName) != m_CustomObjectTypes.end()) | if (m_CustomObjectTypes.find(typeName) != m_CustomObjectTypes.end()) | ||||
{ | { | ||||
// This type already exists | // This type already exists | ||||
throw PSERROR_Scripting_DefineType_AlreadyExists(); | throw PSERROR_Scripting_DefineType_AlreadyExists(); | ||||
} | } | ||||
JS::RootedObject global(rq.cx, m->m_glob); | JS::RootedObject global(rq.cx, rq.glob); | ||||
JS::RootedObject obj(rq.cx, JS_InitClass(rq.cx, global, nullptr, | JS::RootedObject obj(rq.cx, JS_InitClass(rq.cx, global, nullptr, | ||||
clasp, | clasp, | ||||
constructor, minArgs, // Constructor, min args | constructor, minArgs, // Constructor, min args | ||||
ps, fs, // Properties, methods | ps, fs, // Properties, methods | ||||
static_ps, static_fs)); // Constructor properties, methods | static_ps, static_fs)); // Constructor properties, methods | ||||
if (obj == NULL) | if (obj == NULL) | ||||
throw PSERROR_Scripting_DefineType_CreationFailed(); | throw PSERROR_Scripting_DefineType_CreationFailed(); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
objectValue.setObjectOrNull(JS_NewArrayObject(cx, length)); | objectValue.setObjectOrNull(JS_NewArrayObject(cx, length)); | ||||
if (!objectValue.isObject()) | if (!objectValue.isObject()) | ||||
throw PSERROR_Scripting_CreateObjectFailed(); | throw PSERROR_Scripting_CreateObjectFailed(); | ||||
} | } | ||||
JS::Value ScriptInterface::GetGlobalObject() const | |||||
{ | |||||
Request rq(this); | |||||
return JS::ObjectValue(*JS::CurrentGlobalOrNull(rq.cx)); | |||||
} | |||||
bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool replace, bool constant, bool enumerate) | bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool replace, bool constant, bool enumerate) | ||||
{ | { | ||||
Request rq(this); | Request rq(this); | ||||
JS::RootedObject global(rq.cx, m->m_glob); | JS::RootedObject global(rq.cx, rq.glob); | ||||
bool found; | bool found; | ||||
if (!JS_HasProperty(rq.cx, global, name, &found)) | if (!JS_HasProperty(rq.cx, global, name, &found)) | ||||
return false; | return false; | ||||
if (found) | if (found) | ||||
{ | { | ||||
JS::Rooted<JSPropertyDescriptor> desc(rq.cx); | JS::Rooted<JSPropertyDescriptor> desc(rq.cx); | ||||
if (!JS_GetOwnPropertyDescriptor(rq.cx, global, name, &desc)) | if (!JS_GetOwnPropertyDescriptor(rq.cx, global, name, &desc)) | ||||
▲ Show 20 Lines • Show All 211 Lines • ▼ Show 20 Lines | if (deep) | ||||
return JS_DeepFreezeObject(rq.cx, obj); | return JS_DeepFreezeObject(rq.cx, obj); | ||||
else | else | ||||
return JS_FreezeObject(rq.cx, obj); | return JS_FreezeObject(rq.cx, obj); | ||||
} | } | ||||
bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& code) const | bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& code) const | ||||
{ | { | ||||
Request rq(this); | Request rq(this); | ||||
JS::RootedObject global(rq.cx, m->m_glob); | JS::RootedObject global(rq.cx, rq.glob); | ||||
utf16string codeUtf16(code.begin(), code.end()); | utf16string codeUtf16(code.begin(), code.end()); | ||||
uint lineNo = 1; | uint lineNo = 1; | ||||
// CompileOptions does not copy the contents of the filename string pointer. | // CompileOptions does not copy the contents of the filename string pointer. | ||||
// Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary. | // Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary. | ||||
std::string filenameStr = filename.string8(); | std::string filenameStr = filename.string8(); | ||||
JS::CompileOptions options(rq.cx); | JS::CompileOptions options(rq.cx); | ||||
options.setFileAndLine(filenameStr.c_str(), lineNo); | options.setFileAndLine(filenameStr.c_str(), lineNo); | ||||
▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) const | ||||
// Try to stringify as JSON if possible | // Try to stringify as JSON if possible | ||||
// (TODO: this is maybe a bad idea since it'll drop 'undefined' values silently) | // (TODO: this is maybe a bad idea since it'll drop 'undefined' values silently) | ||||
if (pretty) | if (pretty) | ||||
{ | { | ||||
Stringifier str; | Stringifier str; | ||||
JS::RootedValue indentVal(rq.cx, JS::Int32Value(2)); | JS::RootedValue indentVal(rq.cx, JS::Int32Value(2)); | ||||
// Temporary disable the error reporter, so we don't print complaints about cyclic values | // Temporary disable the error reporter, so we don't print complaints about cyclic values | ||||
JSErrorReporter er = JS_SetErrorReporter(m->m_runtime->m_rt, NULL); | JSErrorReporter er = JS_SetErrorReporter(GetJSRuntime(), nullptr); | ||||
bool ok = JS_Stringify(rq.cx, obj, nullptr, indentVal, &Stringifier::callback, &str); | bool ok = JS_Stringify(rq.cx, obj, nullptr, indentVal, &Stringifier::callback, &str); | ||||
// Restore error reporter | // Restore error reporter | ||||
JS_SetErrorReporter(m->m_runtime->m_rt, er); | JS_SetErrorReporter(GetJSRuntime(), er); | ||||
if (ok) | if (ok) | ||||
return str.stream.str(); | return str.stream.str(); | ||||
// Clear the exception set when Stringify failed | // Clear the exception set when Stringify failed | ||||
JS_ClearPendingException(rq.cx); | JS_ClearPendingException(rq.cx); | ||||
} | } | ||||
Show All 20 Lines | |||||
} | } | ||||
bool ScriptInterface::IsExceptionPending(JSContext* cx) | bool ScriptInterface::IsExceptionPending(JSContext* cx) | ||||
{ | { | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
return JS_IsExceptionPending(cx) ? true : false; | return JS_IsExceptionPending(cx) ? true : false; | ||||
} | } | ||||
JS::Value ScriptInterface::CloneValueFromOtherContext(const ScriptInterface& otherContext, JS::HandleValue val) const | JS::Value ScriptInterface::CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val) const | ||||
{ | { | ||||
PROFILE("CloneValueFromOtherContext"); | PROFILE("CloneValueFromOtherCompartment"); | ||||
Request rq(this); | Request rq(this); | ||||
JS::RootedValue out(rq.cx); | JS::RootedValue out(rq.cx); | ||||
shared_ptr<StructuredClone> structuredClone = otherContext.WriteStructuredClone(val); | shared_ptr<StructuredClone> structuredClone = otherCompartment.WriteStructuredClone(val); | ||||
ReadStructuredClone(structuredClone, &out); | ReadStructuredClone(structuredClone, &out); | ||||
return out.get(); | return out.get(); | ||||
} | } | ||||
ScriptInterface::StructuredClone::StructuredClone() : | ScriptInterface::StructuredClone::StructuredClone() : | ||||
m_Data(NULL), m_Size(0) | m_Data(NULL), m_Size(0) | ||||
{ | { | ||||
} | } | ||||
Show All 29 Lines |
Wildfire Games · Phabricator
Any reason we use boost for this? smart pointer?