forked from 0ad/0ad
Explicitly make ScriptInterface a Compartment wrapper.
ScriptInterface is now a wrapper around a JSCompartment, and thus always has a well-defined global. The error reporter is moved to ScriptRuntime in anticipation of that handling JSContext in a later diff. Part of the SM52 migration, stage: SM45 compatible. Patch by: Itms Tested By: Freagarach Refs #4893 Differential Revision: https://code.wildfiregames.com/D3090 This was SVN commit r24180.
This commit is contained in:
parent
0046783e73
commit
aae417bd29
@ -92,7 +92,7 @@ void* CMapGeneratorWorker::RunThread(CMapGeneratorWorker* self)
|
||||
shared_ptr<ScriptRuntime> mapgenRuntime = ScriptRuntime::CreateRuntime(RMS_RUNTIME_SIZE);
|
||||
|
||||
// Enable the script to be aborted
|
||||
JS_SetInterruptCallback(mapgenRuntime->m_rt, MapGeneratorInterruptCallback);
|
||||
JS_SetInterruptCallback(mapgenRuntime->GetJSRuntime(), MapGeneratorInterruptCallback);
|
||||
|
||||
self->m_ScriptInterface = new ScriptInterface("Engine", "MapGenerator", mapgenRuntime);
|
||||
|
||||
@ -143,7 +143,7 @@ bool CMapGeneratorWorker::Run()
|
||||
RegisterScriptFunctions_MapGenerator();
|
||||
|
||||
// Copy settings to global variable
|
||||
JS::RootedValue global(rq.cx, m_ScriptInterface->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
if (!m_ScriptInterface->SetProperty(global, "g_MapSettings", settingsVal, true, true))
|
||||
{
|
||||
LOGERROR("CMapGeneratorWorker::Run: Failed to define g_MapSettings");
|
||||
|
@ -97,8 +97,8 @@ InReaction CGUI::HandleEvent(const SDL_Event_* ev)
|
||||
{
|
||||
ret = IN_HANDLED;
|
||||
|
||||
ScriptInterface::Request rq(*m_ScriptInterface);
|
||||
JS::RootedObject globalObj(rq.cx, &GetGlobalObject().toObject());
|
||||
ScriptInterface::Request rq(m_ScriptInterface);
|
||||
JS::RootedObject globalObj(rq.cx, rq.glob);
|
||||
JS::RootedValue result(rq.cx);
|
||||
JS_CallFunctionValue(rq.cx, globalObj, m_GlobalHotkeys[hotkey][eventName], JS::HandleValueArray::empty(), &result);
|
||||
}
|
||||
|
@ -237,7 +237,6 @@ public:
|
||||
const CGUIColor& GetPreDefinedColor(const CStr& name) const { return m_PreDefinedColors.at(name); }
|
||||
|
||||
shared_ptr<ScriptInterface> GetScriptInterface() { return m_ScriptInterface; };
|
||||
JS::Value GetGlobalObject() { return m_ScriptInterface->GetGlobalObject(); };
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -133,9 +133,9 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptRuntime> scriptRuntime)
|
||||
if (gui)
|
||||
{
|
||||
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface();
|
||||
ScriptInterface::Request rq(*scriptInterface);
|
||||
ScriptInterface::Request rq(scriptInterface);
|
||||
|
||||
JS::RootedValue global(rq.cx, scriptInterface->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
JS::RootedValue hotloadDataVal(rq.cx);
|
||||
scriptInterface->CallFunction(global, "getHotloadData", &hotloadDataVal);
|
||||
hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal);
|
||||
@ -199,11 +199,11 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptRuntime> scriptRuntime)
|
||||
gui->LoadedXmlFiles();
|
||||
|
||||
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface();
|
||||
ScriptInterface::Request rq(*scriptInterface);
|
||||
ScriptInterface::Request rq(scriptInterface);
|
||||
|
||||
JS::RootedValue initDataVal(rq.cx);
|
||||
JS::RootedValue hotloadDataVal(rq.cx);
|
||||
JS::RootedValue global(rq.cx, scriptInterface->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
|
||||
if (initData)
|
||||
scriptInterface->ReadStructuredClone(initData, &initDataVal);
|
||||
@ -241,9 +241,9 @@ void CGUIManager::SGUIPage::PerformCallbackFunction(shared_ptr<ScriptInterface::
|
||||
return;
|
||||
|
||||
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface();
|
||||
ScriptInterface::Request rq(*scriptInterface);
|
||||
ScriptInterface::Request rq(scriptInterface);
|
||||
|
||||
JS::RootedObject globalObj(rq.cx, &scriptInterface->GetGlobalObject().toObject());
|
||||
JS::RootedObject globalObj(rq.cx, rq.glob);
|
||||
|
||||
JS::RootedValue funcVal(rq.cx, *callbackFunction);
|
||||
|
||||
@ -299,7 +299,7 @@ InReaction CGUIManager::HandleEvent(const SDL_Event_* ev)
|
||||
PROFILE("handleInputBeforeGui");
|
||||
ScriptInterface::Request rq(*top()->GetScriptInterface());
|
||||
|
||||
JS::RootedValue global(rq.cx, top()->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
if (top()->GetScriptInterface()->CallFunction(global, "handleInputBeforeGui", handled, *ev, top()->FindObjectUnderMouse()))
|
||||
if (handled)
|
||||
return IN_HANDLED;
|
||||
@ -315,7 +315,7 @@ InReaction CGUIManager::HandleEvent(const SDL_Event_* ev)
|
||||
{
|
||||
// We can't take the following lines out of this scope because top() may be another gui page than it was when calling handleInputBeforeGui!
|
||||
ScriptInterface::Request rq(*top()->GetScriptInterface());
|
||||
JS::RootedValue global(rq.cx, top()->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
|
||||
PROFILE("handleInputAfterGui");
|
||||
if (top()->GetScriptInterface()->CallFunction(global, "handleInputAfterGui", handled, *ev))
|
||||
|
@ -300,8 +300,6 @@ float IGUIObject::GetBufferedZ() const
|
||||
void IGUIObject::RegisterScriptHandler(const CStr& eventName, const CStr& Code, CGUI& pGUI)
|
||||
{
|
||||
ScriptInterface::Request rq(pGUI.GetScriptInterface());
|
||||
JS::RootedValue globalVal(rq.cx, pGUI.GetGlobalObject());
|
||||
JS::RootedObject globalObj(rq.cx, &globalVal.toObject());
|
||||
|
||||
const int paramCount = 1;
|
||||
const char* paramNames[paramCount] = { "mouse" };
|
||||
|
@ -84,7 +84,7 @@ public:
|
||||
|
||||
const ScriptInterface& pageScriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface());
|
||||
ScriptInterface::Request prq(pageScriptInterface);
|
||||
JS::RootedValue global(prq.cx, pageScriptInterface.GetGlobalObject());
|
||||
JS::RootedValue global(prq.cx, prq.globalValue());
|
||||
|
||||
// Ensure that our hotkey state was synchronised with the event itself.
|
||||
bool hotkey_pressed_value = false;
|
||||
|
@ -736,7 +736,7 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface)
|
||||
m_GuiMessageQueue.clear();
|
||||
|
||||
// Copy the messages over to the caller script interface.
|
||||
return scriptInterface.CloneValueFromOtherContext(*m_ScriptInterface, messages);
|
||||
return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages);
|
||||
}
|
||||
|
||||
JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInterface)
|
||||
@ -754,7 +754,7 @@ JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInter
|
||||
m_ScriptInterface->SetPropertyInt(messages, j++, message);
|
||||
|
||||
// Copy the messages over to the caller script interface.
|
||||
return scriptInterface.CloneValueFromOtherContext(*m_ScriptInterface, messages);
|
||||
return scriptInterface.CloneValueFromOtherCompartment(*m_ScriptInterface, messages);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -158,7 +158,7 @@ JS::Value JSI_Network::PollNetworkClient(ScriptInterface::CmptPrivate* pCmptPriv
|
||||
ScriptInterface::Request rqNet(g_NetClient->GetScriptInterface());
|
||||
JS::RootedValue pollNet(rqNet.cx);
|
||||
g_NetClient->GuiPoll(&pollNet);
|
||||
return pCmptPrivate->pScriptInterface->CloneValueFromOtherContext(g_NetClient->GetScriptInterface(), pollNet);
|
||||
return pCmptPrivate->pScriptInterface->CloneValueFromOtherCompartment(g_NetClient->GetScriptInterface(), pollNet);
|
||||
}
|
||||
|
||||
void JSI_Network::SetNetworkGameAttributes(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleValue attribs1)
|
||||
|
@ -325,7 +325,7 @@ PSRETURN CGame::ReallyStartGame()
|
||||
shared_ptr<ScriptInterface> scriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface();
|
||||
ScriptInterface::Request rq(scriptInterface);
|
||||
|
||||
JS::RootedValue global(rq.cx, scriptInterface->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
if (scriptInterface->HasProperty(global, "reallyStartGame"))
|
||||
scriptInterface->CallFunctionVoid(global, "reallyStartGame");
|
||||
}
|
||||
|
@ -1615,7 +1615,7 @@ void CancelLoad(const CStrW& message)
|
||||
shared_ptr<ScriptInterface> pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface();
|
||||
ScriptInterface::Request rq(pScriptInterface);
|
||||
|
||||
JS::RootedValue global(rq.cx, pScriptInterface->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
|
||||
LDR_Cancel();
|
||||
|
||||
|
@ -283,7 +283,7 @@ void RunHardwareDetection()
|
||||
scriptInterface.StringifyJSON(&settings, true));
|
||||
|
||||
// Run the detection script:
|
||||
JS::RootedValue global(rq.cx, scriptInterface.GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
scriptInterface.CallFunctionVoid(global, "RunHardwareDetection", settings);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ void JSI_Game::StartGame(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleV
|
||||
ScriptInterface::Request rqSim(sim->GetScriptInterface());
|
||||
|
||||
JS::RootedValue gameAttribs(rqSim.cx,
|
||||
sim->GetScriptInterface().CloneValueFromOtherContext(*(pCmptPrivate->pScriptInterface), attribs));
|
||||
sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), attribs));
|
||||
|
||||
g_Game->SetPlayerID(playerID);
|
||||
g_Game->StartGame(&gameAttribs, "");
|
||||
|
@ -99,7 +99,7 @@ JS::Value JSI_SavedGame::StartSavedGame(ScriptInterface::CmptPrivate* pCmptPriva
|
||||
ScriptInterface::Request rqGame(sim->GetScriptInterface());
|
||||
|
||||
JS::RootedValue gameContextMetadata(rqGame.cx,
|
||||
sim->GetScriptInterface().CloneValueFromOtherContext(*(pCmptPrivate->pScriptInterface), guiContextMetadata));
|
||||
sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), guiContextMetadata));
|
||||
JS::RootedValue gameInitAttributes(rqGame.cx);
|
||||
sim->GetScriptInterface().GetProperty(gameContextMetadata, "initAttributes", &gameInitAttributes);
|
||||
|
||||
|
@ -62,24 +62,32 @@ struct ScriptInterface_impl
|
||||
// members have to be called before the runtime destructor.
|
||||
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;
|
||||
private:
|
||||
JSContext* m_cx;
|
||||
JSCompartment* m_formerCompartment;
|
||||
JS::PersistentRootedObject m_glob; // global scope object
|
||||
|
||||
public:
|
||||
boost::rand48* m_rng;
|
||||
JS::PersistentRootedObject m_nativeScope; // native function scope object
|
||||
};
|
||||
|
||||
ScriptInterface::Request::Request(const ScriptInterface& scriptInterface) :
|
||||
cx(scriptInterface.m->m_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()
|
||||
{
|
||||
JS_LeaveCompartment(cx, m_formerCompartment);
|
||||
JS_EndRequest(cx);
|
||||
}
|
||||
|
||||
@ -95,46 +103,6 @@ JSClass global_class = {
|
||||
JS_GlobalObjectTraceHook
|
||||
};
|
||||
|
||||
void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
|
||||
{
|
||||
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
|
||||
|
||||
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(rq, 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:
|
||||
|
||||
bool print(JSContext* cx, uint argc, JS::Value* vp)
|
||||
@ -351,70 +319,47 @@ bool ScriptInterface::MathRandom(double& nbr)
|
||||
}
|
||||
|
||||
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;
|
||||
opt.setVersion(JSVERSION_LATEST);
|
||||
// Keep JIT code during non-shrinking GCs. This brings a quite big performance improvement.
|
||||
opt.setPreserveJitCode(true);
|
||||
|
||||
JSAutoRequest rq(m_cx);
|
||||
JS::RootedObject globalRootedVal(m_cx, JS_NewGlobalObject(m_cx, &global_class, NULL, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt));
|
||||
m_formerCompartment = JS_EnterCompartment(m_cx, globalRootedVal);
|
||||
ENSURE(JS_InitStandardClasses(m_cx, globalRootedVal));
|
||||
m_glob = globalRootedVal.get();
|
||||
m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt);
|
||||
|
||||
JS_DefineProperty(m_cx, m_glob, "global", globalRootedVal, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
JSAutoCompartment autoCmpt(m_cx, m_glob);
|
||||
|
||||
ENSURE(JS_InitStandardClasses(m_cx, m_glob));
|
||||
|
||||
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);
|
||||
|
||||
JS_DefineFunction(m_cx, globalRootedVal, "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, globalRootedVal, "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, globalRootedVal, "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, "print", ::print, 0, 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, m_glob, "warn", ::warn, 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, m_glob, "clone", ::deepcopy, 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("ProfileStop", ::ProfileStop, 0);
|
||||
Register("ProfileAttribute", ::ProfileAttribute, 1);
|
||||
|
||||
runtime->RegisterContext(m_cx);
|
||||
m_runtime->RegisterCompartment(js::GetObjectCompartment(m_glob));
|
||||
}
|
||||
|
||||
ScriptInterface_impl::~ScriptInterface_impl()
|
||||
{
|
||||
m_runtime->UnRegisterContext(m_cx);
|
||||
{
|
||||
JSAutoRequest rq(m_cx);
|
||||
JS_LeaveCompartment(m_cx, m_formerCompartment);
|
||||
}
|
||||
JS_DestroyContext(m_cx);
|
||||
m_runtime->UnRegisterCompartment(js::GetObjectCompartment(m_glob));
|
||||
}
|
||||
|
||||
void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint nargs) const
|
||||
{
|
||||
JSAutoRequest rq(m_cx);
|
||||
JSAutoCompartment autoCmpt(m_cx, m_glob);
|
||||
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));
|
||||
}
|
||||
@ -431,7 +376,7 @@ ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugN
|
||||
|
||||
Request rq(this);
|
||||
m_CmptPrivate.pScriptInterface = this;
|
||||
JS_SetContextPrivate(rq.cx, (void*)&m_CmptPrivate);
|
||||
JS_SetCompartmentPrivate(js::GetObjectCompartment(rq.glob), (void*)&m_CmptPrivate);
|
||||
}
|
||||
|
||||
ScriptInterface::~ScriptInterface()
|
||||
@ -450,7 +395,7 @@ void ScriptInterface::SetCallbackData(void* pCBData)
|
||||
|
||||
ScriptInterface::CmptPrivate* ScriptInterface::GetScriptInterfaceAndCBData(JSContext* cx)
|
||||
{
|
||||
CmptPrivate* pCmptPrivate = (CmptPrivate*)JS_GetContextPrivate(cx);
|
||||
CmptPrivate* pCmptPrivate = (CmptPrivate*)JS_GetCompartmentPrivate(js::GetContextCompartment(cx));
|
||||
return pCmptPrivate;
|
||||
}
|
||||
|
||||
@ -478,7 +423,7 @@ bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng)
|
||||
{
|
||||
Request rq(this);
|
||||
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())
|
||||
{
|
||||
JS::RootedObject mathObj(rq.cx, &math.toObject());
|
||||
@ -502,7 +447,7 @@ void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) co
|
||||
|
||||
JSRuntime* ScriptInterface::GetJSRuntime() const
|
||||
{
|
||||
return m->m_runtime->m_rt;
|
||||
return m->m_runtime->GetJSRuntime();
|
||||
}
|
||||
|
||||
shared_ptr<ScriptRuntime> ScriptInterface::GetRuntime() const
|
||||
@ -535,7 +480,7 @@ void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructo
|
||||
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,
|
||||
clasp,
|
||||
constructor, minArgs, // Constructor, min args
|
||||
@ -597,16 +542,10 @@ void ScriptInterface::CreateArray(const Request& rq, JS::MutableHandleValue obje
|
||||
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)
|
||||
{
|
||||
Request rq(this);
|
||||
JS::RootedObject global(rq.cx, m->m_glob);
|
||||
JS::RootedObject global(rq.cx, rq.glob);
|
||||
|
||||
bool found;
|
||||
if (!JS_HasProperty(rq.cx, global, name, &found))
|
||||
@ -834,7 +773,7 @@ bool ScriptInterface::FreezeObject(JS::HandleValue objVal, bool deep) const
|
||||
bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& code) const
|
||||
{
|
||||
Request rq(this);
|
||||
JS::RootedObject global(rq.cx, m->m_glob);
|
||||
JS::RootedObject global(rq.cx, rq.glob);
|
||||
utf16string codeUtf16(code.begin(), code.end());
|
||||
uint lineNo = 1;
|
||||
// CompileOptions does not copy the contents of the filename string pointer.
|
||||
@ -1036,12 +975,12 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) c
|
||||
JS::RootedValue indentVal(rq.cx, JS::Int32Value(2));
|
||||
|
||||
// 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);
|
||||
|
||||
// Restore error reporter
|
||||
JS_SetErrorReporter(m->m_runtime->m_rt, er);
|
||||
JS_SetErrorReporter(GetJSRuntime(), er);
|
||||
|
||||
if (ok)
|
||||
return str.stream.str();
|
||||
@ -1077,12 +1016,12 @@ bool ScriptInterface::IsExceptionPending(const Request& rq)
|
||||
return JS_IsExceptionPending(rq.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);
|
||||
JS::RootedValue out(rq.cx);
|
||||
shared_ptr<StructuredClone> structuredClone = otherContext.WriteStructuredClone(val);
|
||||
shared_ptr<StructuredClone> structuredClone = otherCompartment.WriteStructuredClone(val);
|
||||
ReadStructuredClone(structuredClone, &out);
|
||||
return out.get();
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ extern thread_local shared_ptr<ScriptRuntime> g_ScriptRuntime;
|
||||
|
||||
|
||||
/**
|
||||
* Abstraction around a SpiderMonkey JSContext.
|
||||
* Abstraction around a SpiderMonkey JSCompartment.
|
||||
*
|
||||
* Thread-safety:
|
||||
* - May be used in non-main threads.
|
||||
@ -84,7 +84,7 @@ public:
|
||||
|
||||
struct CmptPrivate
|
||||
{
|
||||
ScriptInterface* pScriptInterface; // the ScriptInterface object the current context belongs to
|
||||
ScriptInterface* pScriptInterface; // the ScriptInterface object the compartment belongs to
|
||||
void* pCBData; // meant to be used as the "this" object for callback functions
|
||||
} m_CmptPrivate;
|
||||
|
||||
@ -95,9 +95,13 @@ public:
|
||||
shared_ptr<ScriptRuntime> GetRuntime() const;
|
||||
|
||||
/**
|
||||
* RAII structure which encapsulates an access to the context of a ScriptInterface.
|
||||
* This struct provides a pointer to the context, and it acts like JSAutoRequest. This
|
||||
* way, getting the context is safe with respect to the GC.
|
||||
* RAII structure which encapsulates an access to the context and compartment of a ScriptInterface.
|
||||
* This struct provides:
|
||||
* - a pointer to the context, while acting like JSAutoRequest
|
||||
* - a pointer to the global object of the compartment, while acting like JSAutoCompartment
|
||||
*
|
||||
* This way, getting and using those pointers is safe with respect to the GC
|
||||
* and to the separation of compartments.
|
||||
*/
|
||||
struct Request
|
||||
{
|
||||
@ -107,15 +111,19 @@ public:
|
||||
Request(const ScriptInterface& scriptInterface);
|
||||
Request(const ScriptInterface* scriptInterface) : Request(*scriptInterface) {}
|
||||
Request(shared_ptr<ScriptInterface> scriptInterface) : Request(*scriptInterface) {}
|
||||
Request(const CmptPrivate* CmptPrivate) : Request(CmptPrivate->pScriptInterface) {}
|
||||
Request(const CmptPrivate* cmptPrivate) : Request(cmptPrivate->pScriptInterface) {}
|
||||
~Request();
|
||||
|
||||
JS::Value globalValue() const;
|
||||
JSContext* cx;
|
||||
JSObject* glob;
|
||||
private:
|
||||
JSCompartment* m_formerCompartment;
|
||||
};
|
||||
friend struct Request;
|
||||
|
||||
/**
|
||||
* Load global scripts that most script contexts need,
|
||||
* Load global scripts that most script interfaces need,
|
||||
* located in the /globalscripts directory. VFS must be initialized.
|
||||
*/
|
||||
bool LoadGlobalScripts();
|
||||
@ -158,8 +166,6 @@ public:
|
||||
*/
|
||||
static void CreateArray(const Request& rq, JS::MutableHandleValue objectValue, size_t length = 0);
|
||||
|
||||
JS::Value GetGlobalObject() const;
|
||||
|
||||
/**
|
||||
* Set the named property on the global object.
|
||||
* Optionally makes it {ReadOnly, DontEnum}. We do not allow to make it DontDelete, so that it can be hotloaded
|
||||
@ -291,12 +297,12 @@ public:
|
||||
bool LoadGlobalScriptFile(const VfsPath& path) const;
|
||||
|
||||
/**
|
||||
* Construct a new value (usable in this ScriptInterface's context) by cloning
|
||||
* a value from a different context.
|
||||
* Construct a new value (usable in this ScriptInterface's compartment) by cloning
|
||||
* a value from a different compartment.
|
||||
* Complex values (functions, XML, etc) won't be cloned correctly, but basic
|
||||
* types and cyclic references should be fine.
|
||||
*/
|
||||
JS::Value CloneValueFromOtherContext(const ScriptInterface& otherContext, JS::HandleValue val) const;
|
||||
JS::Value CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val) const;
|
||||
|
||||
/**
|
||||
* Convert a JS::Value to a C++ type. (This might trigger GC.)
|
||||
@ -327,7 +333,7 @@ public:
|
||||
|
||||
/**
|
||||
* Structured clones are a way to serialize 'simple' JS::Values into a buffer
|
||||
* that can safely be passed between contexts and runtimes and threads.
|
||||
* that can safely be passed between compartments and between threads.
|
||||
* A StructuredClone can be stored and read multiple times if desired.
|
||||
* We wrap them in shared_ptr so memory management is automatic and
|
||||
* thread-safe.
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "scriptinterface/ScriptEngine.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
|
||||
|
||||
void GCSliceCallbackHook(JSRuntime* UNUSED(rt), JS::GCProgress progress, const JS::GCDescription& UNUSED(desc))
|
||||
@ -89,6 +90,52 @@ void GCSliceCallbackHook(JSRuntime* UNUSED(rt), JS::GCProgress progress, const J
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
|
||||
{
|
||||
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
|
||||
|
||||
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(rq.cx);
|
||||
if (JS_GetPendingException(rq.cx, &excn) && excn.isObject())
|
||||
{
|
||||
JS::RootedValue stackVal(rq.cx);
|
||||
JS::RootedObject excnObj(rq.cx, &excn.toObject());
|
||||
JS_GetProperty(rq.cx, excnObj, "stack", &stackVal);
|
||||
|
||||
std::string stackText;
|
||||
ScriptInterface::FromJSVal(rq, 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("->");
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
shared_ptr<ScriptRuntime> ScriptRuntime::CreateRuntime(int runtimeSize, int heapGrowthBytesGCTrigger)
|
||||
{
|
||||
return shared_ptr<ScriptRuntime>(new ScriptRuntime(runtimeSize, heapGrowthBytesGCTrigger));
|
||||
@ -116,24 +163,47 @@ ScriptRuntime::ScriptRuntime(int runtimeSize, int heapGrowthBytesGCTrigger):
|
||||
JS_SetGCParameter(m_rt, JSGC_DYNAMIC_HEAP_GROWTH, false);
|
||||
|
||||
ScriptEngine::GetSingleton().RegisterRuntime(m_rt);
|
||||
|
||||
|
||||
m_cx = JS_NewContext(m_rt, STACK_CHUNK_SIZE);
|
||||
ENSURE(m_cx); // TODO: error handling
|
||||
|
||||
JS_SetOffthreadIonCompilationEnabled(m_rt, true);
|
||||
|
||||
// For GC debugging:
|
||||
// JS_SetGCZeal(m_cx, 2, JS_DEFAULT_ZEAL_FREQ);
|
||||
|
||||
JS_SetContextPrivate(m_cx, nullptr);
|
||||
|
||||
JS_SetErrorReporter(m_rt, ErrorReporter);
|
||||
|
||||
JS_SetGlobalJitCompilerOption(m_rt, JSJITCOMPILER_ION_ENABLE, 1);
|
||||
JS_SetGlobalJitCompilerOption(m_rt, JSJITCOMPILER_BASELINE_ENABLE, 1);
|
||||
|
||||
JS::RuntimeOptionsRef(m_cx)
|
||||
.setExtraWarnings(true)
|
||||
.setWerror(false)
|
||||
.setStrictMode(true);
|
||||
}
|
||||
|
||||
ScriptRuntime::~ScriptRuntime()
|
||||
{
|
||||
JS_DestroyContext(m_cx);
|
||||
JS_DestroyRuntime(m_rt);
|
||||
|
||||
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be active (initialized and not yet shut down) when destroying a ScriptRuntime!");
|
||||
ScriptEngine::GetSingleton().UnRegisterRuntime(m_rt);
|
||||
}
|
||||
|
||||
void ScriptRuntime::RegisterContext(JSContext* cx)
|
||||
void ScriptRuntime::RegisterCompartment(JSCompartment* cmpt)
|
||||
{
|
||||
m_Contexts.push_back(cx);
|
||||
ENSURE(cmpt);
|
||||
m_Compartments.push_back(cmpt);
|
||||
}
|
||||
|
||||
void ScriptRuntime::UnRegisterContext(JSContext* cx)
|
||||
void ScriptRuntime::UnRegisterCompartment(JSCompartment* cmpt)
|
||||
{
|
||||
m_Contexts.remove(cx);
|
||||
m_Compartments.remove(cmpt);
|
||||
}
|
||||
|
||||
#define GC_DEBUG_PRINT 0
|
||||
@ -199,7 +269,7 @@ void ScriptRuntime::MaybeIncrementalGC(double delay)
|
||||
#if GC_DEBUG_PRINT
|
||||
printf("Finishing incremental GC because gcBytes > m_RuntimeSize / 2. \n");
|
||||
#endif
|
||||
PrepareContextsForIncrementalGC();
|
||||
PrepareCompartmentsForIncrementalGC();
|
||||
JS::FinishIncrementalGC(m_rt, JS::gcreason::REFRESH_FRAME);
|
||||
}
|
||||
else
|
||||
@ -228,7 +298,7 @@ void ScriptRuntime::MaybeIncrementalGC(double delay)
|
||||
else
|
||||
printf("Running incremental GC slice \n");
|
||||
#endif
|
||||
PrepareContextsForIncrementalGC();
|
||||
PrepareCompartmentsForIncrementalGC();
|
||||
if (!JS::IsIncrementalGCInProgress(m_rt))
|
||||
JS::StartIncrementalGC(m_rt, GC_NORMAL, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget);
|
||||
else
|
||||
@ -247,8 +317,8 @@ void ScriptRuntime::ShrinkingGC()
|
||||
JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
|
||||
}
|
||||
|
||||
void ScriptRuntime::PrepareContextsForIncrementalGC()
|
||||
void ScriptRuntime::PrepareCompartmentsForIncrementalGC() const
|
||||
{
|
||||
for (JSContext* const& ctx : m_Contexts)
|
||||
JS::PrepareZoneForGC(js::GetCompartmentZone(js::GetContextCompartment(ctx)));
|
||||
for (JSCompartment* const& cmpt : m_Compartments)
|
||||
JS::PrepareZoneForGC(js::GetCompartmentZone(cmpt));
|
||||
}
|
||||
|
@ -30,10 +30,10 @@ constexpr int DEFAULT_RUNTIME_SIZE = 16 * 1024 * 1024;
|
||||
constexpr int DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER = 2 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* Abstraction around a SpiderMonkey JSRuntime.
|
||||
* Each ScriptRuntime can be used to initialize several ScriptInterface
|
||||
* contexts which can then share data, but a single ScriptRuntime should
|
||||
* only be used on a single thread.
|
||||
* Abstraction around a SpiderMonkey JSRuntime/JSContext.
|
||||
*
|
||||
* A single ScriptRuntime, with the associated runtime and context,
|
||||
* should only be used on a single thread.
|
||||
*
|
||||
* (One means to share data between threads and runtimes is to create
|
||||
* a ScriptInterface::StructuredClone.)
|
||||
@ -46,9 +46,7 @@ public:
|
||||
~ScriptRuntime();
|
||||
|
||||
/**
|
||||
* Returns a runtime, which can used to initialise any number of
|
||||
* ScriptInterfaces contexts. Values created in one context may be used
|
||||
* in any other context from the same runtime (but not any other runtime).
|
||||
* Returns a runtime/context, in which any number of ScriptInterfaces compartments can live.
|
||||
* Each runtime should only ever be used on a single thread.
|
||||
* @param runtimeSize Maximum size in bytes of the new runtime
|
||||
* @param heapGrowthBytesGCTrigger Size in bytes of cumulated allocations after which a GC will be triggered
|
||||
@ -70,16 +68,30 @@ public:
|
||||
void MaybeIncrementalGC(double delay);
|
||||
void ShrinkingGC();
|
||||
|
||||
void RegisterContext(JSContext* cx);
|
||||
void UnRegisterContext(JSContext* cx);
|
||||
/**
|
||||
* This is used to keep track of compartments which should be prepared for a GC.
|
||||
*/
|
||||
void RegisterCompartment(JSCompartment* cmpt);
|
||||
void UnRegisterCompartment(JSCompartment* cmpt);
|
||||
|
||||
JSRuntime* m_rt;
|
||||
JSRuntime* GetJSRuntime() const { return m_rt; }
|
||||
|
||||
/**
|
||||
* GetGeneralJSContext returns the context without starting a GC request and without
|
||||
* entering any compartment. It should only be used in specific situations, such as
|
||||
* creating a new compartment, or as an unsafe alternative to GetJSRuntime.
|
||||
* If you need the compartmented context of a ScriptInterface, you should create a
|
||||
* ScriptInterface::Request and use the context from that.
|
||||
*/
|
||||
JSContext* GetGeneralJSContext() const { return m_cx; }
|
||||
|
||||
private:
|
||||
|
||||
void PrepareContextsForIncrementalGC();
|
||||
JSRuntime* m_rt;
|
||||
JSContext* m_cx;
|
||||
|
||||
std::list<JSContext*> m_Contexts;
|
||||
void PrepareCompartmentsForIncrementalGC() const;
|
||||
std::list<JSCompartment*> m_Compartments;
|
||||
|
||||
int m_RuntimeSize;
|
||||
int m_HeapGrowthBytesGCTrigger;
|
||||
|
@ -43,7 +43,7 @@ class TestScriptConversions : public CxxTest::TestSuite
|
||||
// We want to convert values to strings, but can't just call toSource() on them
|
||||
// since they might not be objects. So just use uneval.
|
||||
std::string source;
|
||||
JS::RootedValue global(rq.cx, script.GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
TS_ASSERT(script.CallFunction(global, "uneval", source, v1));
|
||||
|
||||
TS_ASSERT_STR_EQUALS(source, expected);
|
||||
@ -60,7 +60,7 @@ class TestScriptConversions : public CxxTest::TestSuite
|
||||
ScriptInterface::ToJSVal(rq, &v1, value);
|
||||
|
||||
std::string source;
|
||||
JS::RootedValue global(rq.cx, script.GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
TS_ASSERT(script.CallFunction(global, "uneval", source, v1));
|
||||
|
||||
if (expected)
|
||||
@ -90,7 +90,7 @@ class TestScriptConversions : public CxxTest::TestSuite
|
||||
ScriptInterface::ToJSVal(rq, &r1, r);
|
||||
|
||||
std::string source;
|
||||
JS::RootedValue global(rq.cx, script.GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
TS_ASSERT(script.CallFunction(global, "uneval", source, r1));
|
||||
|
||||
TS_ASSERT_STR_EQUALS(source, expected);
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
{
|
||||
ScriptInterface::Request rq2(script2);
|
||||
|
||||
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherContext(script1, obj1));
|
||||
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1));
|
||||
|
||||
std::string source;
|
||||
TS_ASSERT(script2.CallFunction(obj2, "toSource", source));
|
||||
@ -94,7 +94,7 @@ public:
|
||||
{
|
||||
ScriptInterface::Request rq2(script2);
|
||||
|
||||
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherContext(script1, obj1));
|
||||
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1));
|
||||
|
||||
std::string source;
|
||||
TS_ASSERT(script2.CallFunction(obj2, "toSource", source));
|
||||
@ -114,7 +114,7 @@ public:
|
||||
|
||||
{
|
||||
ScriptInterface::Request rq2(script2);
|
||||
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherContext(script1, obj1));
|
||||
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1));
|
||||
|
||||
// Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0]
|
||||
JS::RootedValue prop_a(rq2.cx);
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
m_SimContext(), m_ComponentManager(m_SimContext, rt),
|
||||
m_EnableOOSLog(false), m_EnableSerializationTest(false), m_RejoinTestTurn(-1), m_TestingRejoin(false),
|
||||
m_SecondaryTerrain(nullptr), m_SecondaryContext(nullptr), m_SecondaryComponentManager(nullptr), m_SecondaryLoadedScripts(nullptr),
|
||||
m_MapSettings(rt->m_rt), m_InitAttributes(rt->m_rt)
|
||||
m_MapSettings(rt->GetJSRuntime()), m_InitAttributes(rt->GetJSRuntime())
|
||||
{
|
||||
m_SimContext.m_UnitManager = unitManager;
|
||||
m_SimContext.m_Terrain = terrain;
|
||||
@ -173,7 +173,7 @@ public:
|
||||
ScriptInterface::Request rqNew(newScript);
|
||||
for (const SimulationCommand& command : commands)
|
||||
{
|
||||
JS::RootedValue tmpCommand(rqNew.cx, newScript.CloneValueFromOtherContext(oldScript, command.data));
|
||||
JS::RootedValue tmpCommand(rqNew.cx, newScript.CloneValueFromOtherCompartment(oldScript, command.data));
|
||||
newScript.FreezeObject(tmpCommand, true);
|
||||
SimulationCommand cmd(command.player, rqNew.cx, tmpCommand);
|
||||
newCommands.emplace_back(std::move(cmd));
|
||||
@ -423,7 +423,7 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
|
||||
{
|
||||
ScriptInterface::Request rq2(m_SecondaryComponentManager->GetScriptInterface());
|
||||
JS::RootedValue mapSettingsCloned(rq2.cx,
|
||||
m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherContext(
|
||||
m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherCompartment(
|
||||
scriptInterface, m_MapSettings));
|
||||
ENSURE(LoadTriggerScripts(*m_SecondaryComponentManager, mapSettingsCloned, m_SecondaryLoadedScripts));
|
||||
}
|
||||
@ -734,14 +734,14 @@ ScriptInterface& CSimulation2::GetScriptInterface() const
|
||||
void CSimulation2::PreInitGame()
|
||||
{
|
||||
ScriptInterface::Request rq(GetScriptInterface());
|
||||
JS::RootedValue global(rq.cx, GetScriptInterface().GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
GetScriptInterface().CallFunctionVoid(global, "PreInitGame");
|
||||
}
|
||||
|
||||
void CSimulation2::InitGame()
|
||||
{
|
||||
ScriptInterface::Request rq(GetScriptInterface());
|
||||
JS::RootedValue global(rq.cx, GetScriptInterface().GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
|
||||
JS::RootedValue settings(rq.cx);
|
||||
JS::RootedValue tmpInitAttributes(rq.cx, GetInitAttributes());
|
||||
@ -840,7 +840,7 @@ void CSimulation2::GetMapSettings(JS::MutableHandleValue ret)
|
||||
void CSimulation2::LoadPlayerSettings(bool newPlayers)
|
||||
{
|
||||
ScriptInterface::Request rq(GetScriptInterface());
|
||||
JS::RootedValue global(rq.cx, GetScriptInterface().GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
GetScriptInterface().CallFunctionVoid(global, "LoadPlayerSettings", m->m_MapSettings, newPlayers);
|
||||
}
|
||||
|
||||
@ -848,7 +848,7 @@ void CSimulation2::LoadMapSettings()
|
||||
{
|
||||
ScriptInterface::Request rq(GetScriptInterface());
|
||||
|
||||
JS::RootedValue global(rq.cx, GetScriptInterface().GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
|
||||
// Initialize here instead of in Update()
|
||||
GetScriptInterface().CallFunctionVoid(global, "LoadMapSettings", m->m_MapSettings);
|
||||
|
@ -111,7 +111,7 @@ private:
|
||||
std::string moduleName;
|
||||
std::string constructor;
|
||||
JS::RootedValue objectWithConstructor(rq.cx); // object that should contain the constructor function
|
||||
JS::RootedValue global(rq.cx, m_ScriptInterface->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
JS::RootedValue ctor(rq.cx);
|
||||
if (!m_ScriptInterface->HasProperty(metadata, "moduleName"))
|
||||
{
|
||||
@ -216,10 +216,10 @@ public:
|
||||
m_CommandsComputed(true),
|
||||
m_HasLoadedEntityTemplates(false),
|
||||
m_HasSharedComponent(false),
|
||||
m_EntityTemplates(g_ScriptRuntime->m_rt),
|
||||
m_SharedAIObj(g_ScriptRuntime->m_rt),
|
||||
m_PassabilityMapVal(g_ScriptRuntime->m_rt),
|
||||
m_TerritoryMapVal(g_ScriptRuntime->m_rt)
|
||||
m_EntityTemplates(g_ScriptRuntime->GetJSRuntime()),
|
||||
m_SharedAIObj(g_ScriptRuntime->GetJSRuntime()),
|
||||
m_PassabilityMapVal(g_ScriptRuntime->GetJSRuntime()),
|
||||
m_TerritoryMapVal(g_ScriptRuntime->GetJSRuntime())
|
||||
{
|
||||
|
||||
m_ScriptInterface->ReplaceNondeterministicRNG(m_RNG);
|
||||
@ -422,7 +422,7 @@ public:
|
||||
// Constructor name is SharedScript, it's in the module API3
|
||||
// TODO: Hardcoding this is bad, we need a smarter way.
|
||||
JS::RootedValue AIModule(rq.cx);
|
||||
JS::RootedValue global(rq.cx, m_ScriptInterface->GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
JS::RootedValue ctor(rq.cx);
|
||||
if (!m_ScriptInterface->GetProperty(global, "API3", &AIModule) || AIModule.isUndefined())
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
|
||||
ScriptInterface::Request rq(scriptInterface);
|
||||
|
||||
JS::RootedValue global(rq.cx, scriptInterface.GetGlobalObject());
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
std::vector<SimulationCommand> localCommands;
|
||||
m_LocalQueue.swap(localCommands);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -158,8 +158,7 @@ template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(const Request& rq, J
|
||||
|
||||
template<> void ScriptInterface::ToJSVal<CFixedVector3D>(const Request& rq, JS::MutableHandleValue ret, const CFixedVector3D& val)
|
||||
{
|
||||
ScriptInterface::CmptPrivate* pCmptPrivate = ScriptInterface::GetScriptInterfaceAndCBData(rq.cx);
|
||||
JS::RootedObject global(rq.cx, &pCmptPrivate->pScriptInterface->GetGlobalObject().toObject());
|
||||
JS::RootedObject global(rq.cx, rq.glob);
|
||||
JS::RootedValue valueVector3D(rq.cx);
|
||||
if (!JS_GetProperty(rq.cx, global, "Vector3D", &valueVector3D))
|
||||
FAIL_VOID("Failed to get Vector3D constructor");
|
||||
@ -192,8 +191,7 @@ template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(const Request& rq, J
|
||||
|
||||
template<> void ScriptInterface::ToJSVal<CFixedVector2D>(const Request& rq, JS::MutableHandleValue ret, const CFixedVector2D& val)
|
||||
{
|
||||
ScriptInterface::CmptPrivate* pCmptPrivate = ScriptInterface::GetScriptInterfaceAndCBData(rq.cx);
|
||||
JS::RootedObject global(rq.cx, &pCmptPrivate->pScriptInterface->GetGlobalObject().toObject());
|
||||
JS::RootedObject global(rq.cx, rq.glob);
|
||||
JS::RootedValue valueVector2D(rq.cx);
|
||||
if (!JS_GetProperty(rq.cx, global, "Vector2D", &valueVector2D))
|
||||
FAIL_VOID("Failed to get Vector2D constructor");
|
||||
|
@ -51,11 +51,11 @@ JS::Value JSI_Simulation::GuiInterfaceCall(ScriptInterface::CmptPrivate* pCmptPr
|
||||
return JS::UndefinedValue();
|
||||
|
||||
ScriptInterface::Request rqSim(sim->GetScriptInterface());
|
||||
JS::RootedValue arg(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherContext(*(pCmptPrivate->pScriptInterface), data));
|
||||
JS::RootedValue arg(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), data));
|
||||
JS::RootedValue ret(rqSim.cx);
|
||||
cmpGuiInterface->ScriptCall(g_Game->GetViewedPlayerID(), name, arg, &ret);
|
||||
|
||||
return pCmptPrivate->pScriptInterface->CloneValueFromOtherContext(sim->GetScriptInterface(), ret);
|
||||
return pCmptPrivate->pScriptInterface->CloneValueFromOtherCompartment(sim->GetScriptInterface(), ret);
|
||||
}
|
||||
|
||||
void JSI_Simulation::PostNetworkCommand(ScriptInterface::CmptPrivate* pCmptPrivate, JS::HandleValue cmd)
|
||||
@ -71,7 +71,7 @@ void JSI_Simulation::PostNetworkCommand(ScriptInterface::CmptPrivate* pCmptPriva
|
||||
return;
|
||||
|
||||
ScriptInterface::Request rqSim(sim->GetScriptInterface());
|
||||
JS::RootedValue cmd2(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherContext(*(pCmptPrivate->pScriptInterface), cmd));
|
||||
JS::RootedValue cmd2(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), cmd));
|
||||
|
||||
cmpCommandQueue->PostNetworkCommand(cmd2);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user