Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/scriptinterface/ScriptInterface.cpp
Show First 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
JS_LeaveCompartment(cx, m_formerCompartment); | JS_LeaveCompartment(cx, m_formerCompartment); | ||||
JS_EndRequest(cx); | JS_EndRequest(cx); | ||||
} | } | ||||
namespace | namespace | ||||
{ | { | ||||
JSClass global_class = { | JSClassOps global_classops = { | ||||
"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 | ||||
}; | }; | ||||
JSClass global_class = { | |||||
"global", JSCLASS_GLOBAL_FLAGS, &global_classops | |||||
}; | |||||
// 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); | ||||
ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ | ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ | ||||
for (uint i = 0; i < args.length(); ++i) | for (uint i = 0; i < args.length(); ++i) | ||||
▲ Show 20 Lines • Show All 200 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<ScriptContext>& context) : | ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptContext>& context) : | ||||
m_context(context), m_cx(context->GetGeneralJSContext()), m_glob(context->GetJSRuntime()), m_nativeScope(context->GetJSRuntime()) | m_context(context), m_cx(context->GetGeneralJSContext()), m_glob(context->GetGeneralJSContext()), m_nativeScope(context->GetGeneralJSContext()) | ||||
{ | { | ||||
JS::CompartmentOptions opt; | JS::CompartmentCreationOptions creationOpt; | ||||
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); | creationOpt.setPreserveJitCode(true); | ||||
JS::CompartmentBehaviors behaviors; | |||||
behaviors.setVersion(JSVERSION_LATEST); | |||||
JS::CompartmentOptions opt(creationOpt, behaviors); | |||||
JSAutoRequest rq(m_cx); | JSAutoRequest rq(m_cx); | ||||
m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt); | m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt); | ||||
JSAutoCompartment autoCmpt(m_cx, m_glob); | JSAutoCompartment autoCmpt(m_cx, m_glob); | ||||
ENSURE(JS_InitStandardClasses(m_cx, m_glob)); | ENSURE(JS_InitStandardClasses(m_cx, m_glob)); | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng) | ||||
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 | JSContext* ScriptInterface::GetGeneralJSContext() const | ||||
{ | { | ||||
return m->m_context->GetJSRuntime(); | return m->m_context->GetGeneralJSContext(); | ||||
} | } | ||||
shared_ptr<ScriptContext> ScriptInterface::GetContext() const | shared_ptr<ScriptContext> ScriptInterface::GetContext() const | ||||
{ | { | ||||
return m->m_context; | return m->m_context; | ||||
} | } | ||||
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 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool replace, bool constant, bool enumerate) | ||||
ScriptRequest rq(this); | ScriptRequest rq(this); | ||||
JS::RootedObject global(rq.cx, rq.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<JS::PropertyDescriptor> desc(rq.cx); | ||||
if (!JS_GetOwnPropertyDescriptor(rq.cx, global, name, &desc)) | if (!JS_GetOwnPropertyDescriptor(rq.cx, global, name, &desc)) | ||||
return false; | return false; | ||||
if (!desc.writable()) | if (!desc.writable()) | ||||
{ | { | ||||
if (!replace) | if (!replace) | ||||
{ | { | ||||
ScriptException::Raise(rq, "SetGlobal \"%s\" called multiple times", name); | ScriptException::Raise(rq, "SetGlobal \"%s\" called multiple times", name); | ||||
▲ Show 20 Lines • Show All 394 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 | if (JS_Stringify(rq.cx, obj, nullptr, indentVal, &Stringifier::callback, &str)) | ||||
JSErrorReporter er = JS_SetErrorReporter(GetJSRuntime(), nullptr); | |||||
bool ok = JS_Stringify(rq.cx, obj, nullptr, indentVal, &Stringifier::callback, &str); | |||||
// Restore error reporter | |||||
JS_SetErrorReporter(GetJSRuntime(), er); | |||||
if (ok) | |||||
return str.stream.str(); | return str.stream.str(); | ||||
// Drop exceptions raised by cyclic values before trying something else | // Drop exceptions raised by cyclic values before trying something else | ||||
JS_ClearPendingException(rq.cx); | JS_ClearPendingException(rq.cx); | ||||
} | } | ||||
// Caller didn't want pretty output, or JSON conversion failed (e.g. due to cycles), | // Caller didn't want pretty output, or JSON conversion failed (e.g. due to cycles), | ||||
// so fall back to obj.toSource() | // so fall back to obj.toSource() | ||||
std::wstring source = L"(error)"; | std::wstring source = L"(error)"; | ||||
CallFunction(obj, "toSource", source); | CallFunction(obj, "toSource", source); | ||||
return utf8_from_wstring(source); | return utf8_from_wstring(source); | ||||
} | } | ||||
JS::Value ScriptInterface::CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val) const | JS::Value ScriptInterface::CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val, bool sameThread) const | ||||
{ | { | ||||
PROFILE("CloneValueFromOtherCompartment"); | PROFILE("CloneValueFromOtherCompartment"); | ||||
ScriptRequest rq(this); | ScriptRequest rq(this); | ||||
JS::RootedValue out(rq.cx); | JS::RootedValue out(rq.cx); | ||||
shared_ptr<StructuredClone> structuredClone = otherCompartment.WriteStructuredClone(val); | ScriptInterface::StructuredClone structuredClone = otherCompartment.WriteStructuredClone(val, sameThread); | ||||
ReadStructuredClone(structuredClone, &out); | ReadStructuredClone(structuredClone, &out); | ||||
return out.get(); | return out.get(); | ||||
} | } | ||||
ScriptInterface::StructuredClone::StructuredClone() : | ScriptInterface::StructuredClone ScriptInterface::WriteStructuredClone(JS::HandleValue v, bool sameThread) const | ||||
m_Data(NULL), m_Size(0) | |||||
{ | { | ||||
} | ScriptRequest rq(this); | ||||
ScriptInterface::StructuredClone::~StructuredClone() | JS::StructuredCloneScope scope = sameThread ? JS::StructuredCloneScope::SameProcessSameThread : JS::StructuredCloneScope::SameProcessDifferentThread; | ||||
{ | ScriptInterface::StructuredClone ret(new JSStructuredCloneData(scope)); | ||||
if (m_Data) | JS::CloneDataPolicy policy; | ||||
JS_ClearStructuredClone(m_Data, m_Size, NULL, NULL); | |||||
} | |||||
shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClone(JS::HandleValue v) const | if (!JS_WriteStructuredClone(rq.cx, v, ret.get(), scope, policy, nullptr, nullptr, JS::UndefinedHandleValue)) | ||||
{ | |||||
ScriptRequest rq(this); | |||||
u64* data = NULL; | |||||
size_t nbytes = 0; | |||||
if (!JS_WriteStructuredClone(rq.cx, v, &data, &nbytes, NULL, NULL, JS::UndefinedHandleValue)) | |||||
{ | { | ||||
debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!"); | debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!"); | ||||
ScriptException::CatchPending(rq); | ScriptException::CatchPending(rq); | ||||
return shared_ptr<StructuredClone>(); | return ScriptInterface::StructuredClone(); | ||||
} | } | ||||
shared_ptr<StructuredClone> ret(new StructuredClone); | |||||
ret->m_Data = data; | |||||
ret->m_Size = nbytes; | |||||
return ret; | return ret; | ||||
} | } | ||||
void ScriptInterface::ReadStructuredClone(const shared_ptr<ScriptInterface::StructuredClone>& ptr, JS::MutableHandleValue ret) const | void ScriptInterface::ReadStructuredClone(const ScriptInterface::StructuredClone& ptr, JS::MutableHandleValue ret) const | ||||
{ | { | ||||
ScriptRequest rq(this); | ScriptRequest rq(this); | ||||
if (!JS_ReadStructuredClone(rq.cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, ret, NULL, NULL)) | if (!JS_ReadStructuredClone(rq.cx, *ptr, JS_STRUCTURED_CLONE_VERSION, ptr->scope(), ret, nullptr, nullptr)) | ||||
ScriptException::CatchPending(rq); | ScriptException::CatchPending(rq); | ||||
} | } |
Wildfire Games · Phabricator