1
0
forked from 0ad/0ad

Wrap JSAutoRequest and replace usage of JSContext* with the wrapper.

JSAutoRequest is required before calling into most JSAPI methods, for GC
reasons.
Calling it is required and fragile as one must not forget.
Further, SM52 and later make manipulating JSContext* dangerous as that
can cross Compartment(Realm in SM68) barriers (and ScriptInterface now
matches a Compartment).

The solution to both problems is to avoid using JSContext* in 0 A.D.
itself. To achieve this, a Request class is introduced, and must be used
to access a JSContext* from a scriptInterface. Further, Request is
passed to other ScriptInterface functions isntead of JSContext*, making
it obvious that the caller has already called it, reducing errors and
redundant JSAutoRequest calls.
Only JSNative functions now get a naked JSContext* without protection,
but the likelihood of forgetting a request is lower since many
ScriptInterface functions now expect it.

JSContext* is directly passed to JSAPI functions only.

Part of the SM52 migration, stage: SM45 compatible

Based on a patch by: Itms
Tested By: Freagarach
Refs #4893

Differential Revision: https://code.wildfiregames.com/D3088
This was SVN commit r24176.
This commit is contained in:
wraitii 2020-11-13 13:18:22 +00:00
parent 6a029d2a84
commit ee0d204bf6
74 changed files with 1591 additions and 1812 deletions

View File

@ -115,11 +115,10 @@ void* CMapGeneratorWorker::RunThread(CMapGeneratorWorker* self)
bool CMapGeneratorWorker::Run()
{
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
// Parse settings
JS::RootedValue settingsVal(cx);
JS::RootedValue settingsVal(rq.cx);
if (!m_ScriptInterface->ParseJSON(m_Settings, &settingsVal) && settingsVal.isUndefined())
{
LOGERROR("CMapGeneratorWorker::Run: Failed to parse settings");
@ -144,7 +143,7 @@ bool CMapGeneratorWorker::Run()
RegisterScriptFunctions_MapGenerator();
// Copy settings to global variable
JS::RootedValue global(cx, m_ScriptInterface->GetGlobalObject());
JS::RootedValue global(rq.cx, m_ScriptInterface->GetGlobalObject());
if (!m_ScriptInterface->SetProperty(global, "g_MapSettings", settingsVal, true, true))
{
LOGERROR("CMapGeneratorWorker::Run: Failed to define g_MapSettings");
@ -326,10 +325,9 @@ JS::Value CMapGeneratorWorker::LoadHeightmap(ScriptInterface::CxPrivate* pCxPriv
}
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData);
JSContext* cx = self->m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue returnValue(cx);
ToJSVal_vector(cx, &returnValue, heightmap);
ScriptInterface::Request rq(self->m_ScriptInterface);
JS::RootedValue returnValue(rq.cx);
ToJSVal_vector(rq, &returnValue, heightmap);
return returnValue;
}
@ -337,8 +335,7 @@ JS::Value CMapGeneratorWorker::LoadHeightmap(ScriptInterface::CxPrivate* pCxPriv
JS::Value CMapGeneratorWorker::LoadMapTerrain(ScriptInterface::CxPrivate* pCxPrivate, const VfsPath& filename)
{
CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData);
JSContext* cx = self->m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(self->m_ScriptInterface);
if (!VfsFileExists(filename))
{
@ -400,10 +397,10 @@ JS::Value CMapGeneratorWorker::LoadMapTerrain(ScriptInterface::CxPrivate* pCxPri
}
}
JS::RootedValue returnValue(cx);
JS::RootedValue returnValue(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&returnValue,
"height", heightmap,
"textureNames", textureNames,

View File

@ -371,15 +371,14 @@ PSRETURN CMapSummaryReader::LoadMap(const VfsPath& pathname)
void CMapSummaryReader::GetMapSettings(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
ScriptInterface::CreateObject(cx, ret);
ScriptInterface::CreateObject(rq, ret);
if (m_ScriptSettings.empty())
return;
JS::RootedValue scriptSettingsVal(cx);
JS::RootedValue scriptSettingsVal(rq.cx);
scriptInterface.ParseJSON(m_ScriptSettings, &scriptSettingsVal);
scriptInterface.SetProperty(ret, "settings", scriptSettingsVal, false);
}
@ -1267,8 +1266,7 @@ int CMapReader::LoadRMSettings()
int CMapReader::GenerateMap()
{
JSContext* cx = pSimulation2->GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pSimulation2->GetScriptInterface());
if (!m_MapGen)
{
@ -1300,7 +1298,7 @@ int CMapReader::GenerateMap()
shared_ptr<ScriptInterface::StructuredClone> results = m_MapGen->GetResults();
// Parse data into simulation context
JS::RootedValue data(cx);
JS::RootedValue data(rq.cx);
pSimulation2->GetScriptInterface().ReadStructuredClone(results, &data);
if (data.isUndefined())
@ -1310,7 +1308,7 @@ int CMapReader::GenerateMap()
}
else
{
m_MapData.init(cx, data);
m_MapData.init(rq.cx, data);
}
}
else
@ -1330,8 +1328,7 @@ int CMapReader::GenerateMap()
int CMapReader::ParseTerrain()
{
TIMER(L"ParseTerrain");
JSContext* cx = pSimulation2->GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pSimulation2->GetScriptInterface());
// parse terrain from map data
// an error here should stop the loading process
@ -1365,7 +1362,7 @@ int CMapReader::ParseTerrain()
// build tile data
m_Tiles.resize(SQR(size));
JS::RootedValue tileData(cx);
JS::RootedValue tileData(rq.cx);
GET_TERRAIN_PROPERTY(m_MapData, tileData, &tileData)
// parse tile data object into flat arrays
@ -1406,8 +1403,7 @@ int CMapReader::ParseTerrain()
int CMapReader::ParseEntities()
{
TIMER(L"ParseEntities");
JSContext* cx = pSimulation2->GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pSimulation2->GetScriptInterface());
// parse entities from map data
std::vector<Entity> entities;
@ -1471,14 +1467,13 @@ int CMapReader::ParseEntities()
int CMapReader::ParseEnvironment()
{
// parse environment settings from map data
JSContext* cx = pSimulation2->GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pSimulation2->GetScriptInterface());
#define GET_ENVIRONMENT_PROPERTY(val, prop, out)\
if (!pSimulation2->GetScriptInterface().GetProperty(val, #prop, out))\
LOGWARNING("CMapReader::ParseEnvironment() failed to get '%s' property", #prop);
JS::RootedValue envObj(cx);
JS::RootedValue envObj(rq.cx);
GET_ENVIRONMENT_PROPERTY(m_MapData, Environment, &envObj)
if (envObj.isUndefined())
@ -1511,10 +1506,10 @@ int CMapReader::ParseEnvironment()
m_LightEnv.m_UnitsAmbientColor = RGBColor(unitsAmbientColor.r, unitsAmbientColor.g, unitsAmbientColor.b);
// Water properties
JS::RootedValue waterObj(cx);
JS::RootedValue waterObj(rq.cx);
GET_ENVIRONMENT_PROPERTY(envObj, Water, &waterObj)
JS::RootedValue waterBodyObj(cx);
JS::RootedValue waterBodyObj(rq.cx);
GET_ENVIRONMENT_PROPERTY(waterObj, WaterBody, &waterBodyObj)
// Water level - necessary
@ -1538,7 +1533,7 @@ int CMapReader::ParseEnvironment()
GET_ENVIRONMENT_PROPERTY(waterBodyObj, WindAngle, pWaterMan->m_WindAngle)
}
JS::RootedValue fogObject(cx);
JS::RootedValue fogObject(rq.cx);
GET_ENVIRONMENT_PROPERTY(envObj, Fog, &fogObject);
GET_ENVIRONMENT_PROPERTY(fogObject, FogFactor, m_LightEnv.m_FogFactor);
@ -1548,7 +1543,7 @@ int CMapReader::ParseEnvironment()
GET_ENVIRONMENT_PROPERTY(fogObject, FogColor, fogColor);
m_LightEnv.m_FogColor = RGBColor(fogColor.r, fogColor.g, fogColor.b);
JS::RootedValue postprocObject(cx);
JS::RootedValue postprocObject(rq.cx);
GET_ENVIRONMENT_PROPERTY(envObj, Postproc, &postprocObject);
std::wstring postProcEffect;
@ -1571,8 +1566,8 @@ int CMapReader::ParseEnvironment()
int CMapReader::ParseCamera()
{
JSContext* cx = pSimulation2->GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pSimulation2->GetScriptInterface());
// parse camera settings from map data
// defaults if we don't find player starting camera
float declination = DEGTORAD(30.f), rotation = DEGTORAD(-45.f);
@ -1582,7 +1577,7 @@ int CMapReader::ParseCamera()
if (!pSimulation2->GetScriptInterface().GetProperty(val, #prop, out))\
LOGWARNING("CMapReader::ParseCamera() failed to get '%s' property", #prop);
JS::RootedValue cameraObj(cx);
JS::RootedValue cameraObj(rq.cx);
GET_CAMERA_PROPERTY(m_MapData, Camera, &cameraObj)
if (!cameraObj.isUndefined())

View File

@ -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
@ -70,14 +70,13 @@ void JSI_GameView::RegisterScriptFunctions_Settings(const ScriptInterface& scrip
JS::Value JSI_GameView::GetCameraPivot(ScriptInterface::CxPrivate* pCxPrivate)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pCxPrivate);
CVector3D pivot(-1, -1, -1);
if (g_Game && g_Game->GetView())
pivot = g_Game->GetView()->GetCameraPivot();
JS::RootedValue pivotValue(cx);
ScriptInterface::CreateObject(cx, &pivotValue, "x", pivot.X, "z", pivot.Z);
JS::RootedValue pivotValue(rq.cx);
ScriptInterface::CreateObject(rq, &pivotValue, "x", pivot.X, "z", pivot.Z);
return pivotValue;
}

View File

@ -97,11 +97,10 @@ InReaction CGUI::HandleEvent(const SDL_Event_* ev)
{
ret = IN_HANDLED;
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedObject globalObj(cx, &GetGlobalObject().toObject());
JS::RootedValue result(cx);
JS_CallFunctionValue(cx, globalObj, m_GlobalHotkeys[hotkey][eventName], JS::HandleValueArray::empty(), &result);
ScriptInterface::Request rq(*m_ScriptInterface);
JS::RootedObject globalObj(rq.cx, &GetGlobalObject().toObject());
JS::RootedValue result(rq.cx);
JS_CallFunctionValue(rq.cx, globalObj, m_GlobalHotkeys[hotkey][eventName], JS::HandleValueArray::empty(), &result);
}
std::map<CStr, std::vector<IGUIObject*> >::iterator it = m_HotkeyObjects.find(hotkey);
@ -407,30 +406,29 @@ void CGUI::UnsetObjectHotkey(IGUIObject* pObject, const CStr& hotkeyTag)
void CGUI::SetGlobalHotkey(const CStr& hotkeyTag, const CStr& eventName, JS::HandleValue function)
{
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(*m_ScriptInterface);
if (hotkeyTag.empty())
{
JS_ReportError(cx, "Cannot assign a function to an empty hotkey identifier!");
JS_ReportError(rq.cx, "Cannot assign a function to an empty hotkey identifier!");
return;
}
// Only support "Press", "Keydown" and "Release" events.
if (eventName != EventNamePress && eventName != EventNameKeyDown && eventName != EventNameRelease)
{
JS_ReportError(cx, "Cannot assign a function to an unsupported event!");
JS_ReportError(rq.cx, "Cannot assign a function to an unsupported event!");
return;
}
if (!function.isObject() || !JS_ObjectIsFunction(cx, &function.toObject()))
if (!function.isObject() || !JS_ObjectIsFunction(rq.cx, &function.toObject()))
{
JS_ReportError(cx, "Cannot assign non-function value to global hotkey '%s'", hotkeyTag.c_str());
JS_ReportError(rq.cx, "Cannot assign non-function value to global hotkey '%s'", hotkeyTag.c_str());
return;
}
UnsetGlobalHotkey(hotkeyTag, eventName);
m_GlobalHotkeys[hotkeyTag][eventName].init(cx, function);
m_GlobalHotkeys[hotkeyTag][eventName].init(rq.cx, function);
}
void CGUI::UnsetGlobalHotkey(const CStr& hotkeyTag, const CStr& eventName)

View File

@ -41,23 +41,22 @@ bool CGUISetting<T>::FromString(const CStrW& Value, const bool SendMessage)
};
template<>
bool CGUISetting<CGUIColor>::FromJSVal(JSContext* cx, JS::HandleValue Value, const bool SendMessage)
bool CGUISetting<CGUIColor>::FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue Value, const bool SendMessage)
{
CGUIColor settingValue;
if (Value.isString())
{
CStr name;
if (!ScriptInterface::FromJSVal(cx, Value, name))
if (!ScriptInterface::FromJSVal(rq, Value, name))
return false;
if (!settingValue.ParseString(m_pObject.GetGUI(), name))
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "Invalid color '%s'", name.c_str());
JS_ReportError(rq.cx, "Invalid color '%s'", name.c_str());
return false;
}
}
else if (!ScriptInterface::FromJSVal<CColor>(cx, Value, settingValue))
else if (!ScriptInterface::FromJSVal<CColor>(rq, Value, settingValue))
return false;
m_pObject.SetSetting<CGUIColor>(m_Name, settingValue, SendMessage);
@ -65,10 +64,10 @@ bool CGUISetting<CGUIColor>::FromJSVal(JSContext* cx, JS::HandleValue Value, con
};
template<typename T>
bool CGUISetting<T>::FromJSVal(JSContext* cx, JS::HandleValue Value, const bool SendMessage)
bool CGUISetting<T>::FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue Value, const bool SendMessage)
{
T settingValue;
if (!ScriptInterface::FromJSVal<T>(cx, Value, settingValue))
if (!ScriptInterface::FromJSVal<T>(rq, Value, settingValue))
return false;
m_pObject.SetSetting<T>(m_Name, settingValue, SendMessage);
@ -76,9 +75,9 @@ bool CGUISetting<T>::FromJSVal(JSContext* cx, JS::HandleValue Value, const bool
};
template<typename T>
void CGUISetting<T>::ToJSVal(JSContext* cx, JS::MutableHandleValue Value)
void CGUISetting<T>::ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue Value)
{
ScriptInterface::ToJSVal<T>(cx, Value, m_pSetting);
ScriptInterface::ToJSVal<T>(rq, Value, m_pSetting);
};
#define TYPE(T) \

View File

@ -41,12 +41,12 @@ public:
/**
* Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data.
*/
virtual bool FromJSVal(JSContext* cx, JS::HandleValue Value, const bool SendMessage) = 0;
virtual bool FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue Value, const bool SendMessage) = 0;
/**
* Converts the setting data to a JS::Value using ScriptInterface::ToJSVal.
*/
virtual void ToJSVal(JSContext* cx, JS::MutableHandleValue Value) = 0;
virtual void ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue Value) = 0;
};
template<typename T>
@ -65,12 +65,12 @@ public:
/**
* Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data.
*/
bool FromJSVal(JSContext* cx, JS::HandleValue Value, const bool SendMessage) override;
bool FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue Value, const bool SendMessage) override;
/**
* Converts the setting data to a JS::Value using ScriptInterface::ToJSVal.
*/
void ToJSVal(JSContext* cx, JS::MutableHandleValue Value) override;
void ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue Value) override;
/**
* These members are public because they are either unmodifiable or free to be modified.

View File

@ -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
@ -133,11 +133,10 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptRuntime> scriptRuntime)
if (gui)
{
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface();
JSContext* cx = scriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(*scriptInterface);
JS::RootedValue global(cx, scriptInterface->GetGlobalObject());
JS::RootedValue hotloadDataVal(cx);
JS::RootedValue global(rq.cx, scriptInterface->GetGlobalObject());
JS::RootedValue hotloadDataVal(rq.cx);
scriptInterface->CallFunction(global, "getHotloadData", &hotloadDataVal);
hotloadData = scriptInterface->WriteStructuredClone(hotloadDataVal);
}
@ -200,12 +199,11 @@ void CGUIManager::SGUIPage::LoadPage(shared_ptr<ScriptRuntime> scriptRuntime)
gui->LoadedXmlFiles();
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface();
JSContext* cx = scriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(*scriptInterface);
JS::RootedValue initDataVal(cx);
JS::RootedValue hotloadDataVal(cx);
JS::RootedValue global(cx, scriptInterface->GetGlobalObject());
JS::RootedValue initDataVal(rq.cx);
JS::RootedValue hotloadDataVal(rq.cx);
JS::RootedValue global(rq.cx, scriptInterface->GetGlobalObject());
if (initData)
scriptInterface->ReadStructuredClone(initData, &initDataVal);
@ -226,8 +224,9 @@ void CGUIManager::SGUIPage::SetCallbackFunction(ScriptInterface& scriptInterface
return;
}
// Does not require JSAutoRequest
if (!JS_ObjectIsFunction(scriptInterface.GetContext(), &callbackFunc.toObject()))
ScriptInterface::Request rq(scriptInterface);
if (!JS_ObjectIsFunction(rq.cx, &callbackFunc.toObject()))
{
LOGERROR("Given callback handler is not a function!");
return;
@ -242,26 +241,25 @@ void CGUIManager::SGUIPage::PerformCallbackFunction(shared_ptr<ScriptInterface::
return;
shared_ptr<ScriptInterface> scriptInterface = gui->GetScriptInterface();
JSContext* cx = scriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(*scriptInterface);
JS::RootedObject globalObj(cx, &scriptInterface->GetGlobalObject().toObject());
JS::RootedObject globalObj(rq.cx, &scriptInterface->GetGlobalObject().toObject());
JS::RootedValue funcVal(cx, *callbackFunction);
JS::RootedValue funcVal(rq.cx, *callbackFunction);
// Delete the callback function, so that it is not called again
callbackFunction.reset();
JS::RootedValue argVal(cx);
JS::RootedValue argVal(rq.cx);
if (args)
scriptInterface->ReadStructuredClone(args, &argVal);
JS::AutoValueVector paramData(cx);
JS::AutoValueVector paramData(rq.cx);
paramData.append(argVal);
JS::RootedValue result(cx);
JS::RootedValue result(rq.cx);
JS_CallFunctionValue(cx, globalObj, funcVal, paramData, &result);
JS_CallFunctionValue(rq.cx, globalObj, funcVal, paramData, &result);
}
Status CGUIManager::ReloadChangedFile(const VfsPath& path)
@ -299,9 +297,9 @@ InReaction CGUIManager::HandleEvent(const SDL_Event_* ev)
{
PROFILE("handleInputBeforeGui");
JSContext* cx = top()->GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue global(cx, top()->GetGlobalObject());
ScriptInterface::Request rq(*top()->GetScriptInterface());
JS::RootedValue global(rq.cx, top()->GetGlobalObject());
if (top()->GetScriptInterface()->CallFunction(global, "handleInputBeforeGui", handled, *ev, top()->FindObjectUnderMouse()))
if (handled)
return IN_HANDLED;
@ -316,9 +314,8 @@ 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!
JSContext* cx = top()->GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue global(cx, top()->GetGlobalObject());
ScriptInterface::Request rq(*top()->GetScriptInterface());
JS::RootedValue global(rq.cx, top()->GetGlobalObject());
PROFILE("handleInputAfterGui");
if (top()->GetScriptInterface()->CallFunction(global, "handleInputAfterGui", handled, *ev))

View File

@ -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
@ -299,10 +299,9 @@ float IGUIObject::GetBufferedZ() const
void IGUIObject::RegisterScriptHandler(const CStr& eventName, const CStr& Code, CGUI& pGUI)
{
JSContext* cx = pGUI.GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue globalVal(cx, pGUI.GetGlobalObject());
JS::RootedObject globalObj(cx, &globalVal.toObject());
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" };
@ -315,19 +314,19 @@ void IGUIObject::RegisterScriptHandler(const CStr& eventName, const CStr& Code,
char buf[64];
sprintf_s(buf, ARRAY_SIZE(buf), "__eventhandler%d (%s)", x++, eventName.c_str());
JS::CompileOptions options(cx);
JS::CompileOptions options(rq.cx);
options.setFileAndLine(CodeName.c_str(), 0);
options.setIsRunOnce(false);
JS::RootedFunction func(cx);
JS::AutoObjectVector emptyScopeChain(cx);
if (!JS::CompileFunction(cx, emptyScopeChain, options, buf, paramCount, paramNames, Code.c_str(), Code.length(), &func))
JS::RootedFunction func(rq.cx);
JS::AutoObjectVector emptyScopeChain(rq.cx);
if (!JS::CompileFunction(rq.cx, emptyScopeChain, options, buf, paramCount, paramNames, Code.c_str(), Code.length(), &func))
{
LOGERROR("RegisterScriptHandler: Failed to compile the script for %s", eventName.c_str());
return;
}
JS::RootedObject funcObj(cx, JS_GetFunctionObject(func));
JS::RootedObject funcObj(rq.cx, JS_GetFunctionObject(func));
SetScriptHandler(eventName, funcObj);
}
@ -375,21 +374,20 @@ InReaction IGUIObject::SendMouseEvent(EGUIMessageType type, const CStr& eventNam
SGUIMessage msg(type);
HandleMessage(msg);
JSContext* cx = m_pGUI.GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_pGUI.GetScriptInterface());
// Set up the 'mouse' parameter
JS::RootedValue mouse(cx);
JS::RootedValue mouse(rq.cx);
const CPos& mousePos = m_pGUI.GetMousePos();
ScriptInterface::CreateObject(
cx,
rq,
&mouse,
"x", mousePos.x,
"y", mousePos.y,
"buttons", m_pGUI.GetMouseButtons());
JS::AutoValueVector paramData(cx);
JS::AutoValueVector paramData(rq.cx);
paramData.append(mouse);
ScriptEvent(eventName, paramData);
@ -406,9 +404,8 @@ bool IGUIObject::ScriptEventWithReturn(const CStr& eventName)
if (m_ScriptHandlers.find(eventName) == m_ScriptHandlers.end())
return false;
JSContext* cx = m_pGUI.GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
JS::AutoValueVector paramData(cx);
ScriptInterface::Request rq(m_pGUI.GetScriptInterface());
JS::AutoValueVector paramData(rq.cx);
return ScriptEventWithReturn(eventName, paramData);
}
@ -423,13 +420,12 @@ bool IGUIObject::ScriptEventWithReturn(const CStr& eventName, const JS::HandleVa
if (it == m_ScriptHandlers.end())
return false;
JSContext* cx = m_pGUI.GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
JS::RootedObject obj(cx, GetJSObject());
JS::RootedValue handlerVal(cx, JS::ObjectValue(*it->second));
JS::RootedValue result(cx);
ScriptInterface::Request rq(m_pGUI.GetScriptInterface());
JS::RootedObject obj(rq.cx, GetJSObject());
JS::RootedValue handlerVal(rq.cx, JS::ObjectValue(*it->second));
JS::RootedValue result(rq.cx);
if (!JS_CallFunctionValue(cx, obj, handlerVal, paramData, &result))
if (!JS_CallFunctionValue(rq.cx, obj, handlerVal, paramData, &result))
{
LOGERROR("Errors executing script event \"%s\"", eventName.c_str());
return false;
@ -439,10 +435,9 @@ bool IGUIObject::ScriptEventWithReturn(const CStr& eventName, const JS::HandleVa
void IGUIObject::CreateJSObject()
{
JSContext* cx = m_pGUI.GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_pGUI.GetScriptInterface());
m_JSObject.init(cx, m_pGUI.GetScriptInterface()->CreateCustomObject("GUIObject"));
m_JSObject.init(rq.cx, m_pGUI.GetScriptInterface()->CreateCustomObject("GUIObject"));
JS_SetPrivate(m_JSObject.get(), this);
RegisterScriptFunctions();

View File

@ -238,19 +238,18 @@ float CMiniMap::GetAngle() const
bool CMiniMap::FireWorldClickEvent(int button, int UNUSED(clicks))
{
JSContext* cx = g_GUI->GetActiveGUI()->GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(g_GUI->GetActiveGUI()->GetScriptInterface());
float x, z;
GetMouseWorldCoordinates(x, z);
JS::RootedValue coords(cx);
ScriptInterface::CreateObject(cx, &coords, "x", x, "z", z);
JS::RootedValue coords(rq.cx);
ScriptInterface::CreateObject(rq, &coords, "x", x, "z", z);
JS::RootedValue buttonJs(cx);
ScriptInterface::ToJSVal(cx, &buttonJs, button);
JS::RootedValue buttonJs(rq.cx);
ScriptInterface::ToJSVal(rq, &buttonJs, button);
JS::AutoValueVector paramData(cx);
JS::AutoValueVector paramData(rq.cx);
paramData.append(coords);
paramData.append(buttonJs);

View File

@ -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
@ -254,9 +254,8 @@ bool CText::MouseOverIcon()
void CText::RegisterScriptFunctions()
{
JSContext* cx = m_pGUI.GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
JS_DefineFunctions(cx, m_JSObject, CText::JSI_methods);
ScriptInterface::Request rq(m_pGUI.GetScriptInterface());
JS_DefineFunctions(rq.cx, m_JSObject, CText::JSI_methods);
}
JSFunctionSpec CText::JSI_methods[] =
@ -267,18 +266,18 @@ JSFunctionSpec CText::JSI_methods[] =
bool CText::GetTextSize(JSContext* cx, uint argc, JS::Value* vp)
{
// No JSAutoRequest needed for these calls
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
CText* thisObj = ScriptInterface::GetPrivate<CText>(cx, args, &JSI_IGUIObject::JSI_class);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
CText* thisObj = ScriptInterface::GetPrivate<CText>(rq, args, &JSI_IGUIObject::JSI_class);
if (!thisObj)
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "This is not a CText object!");
return false;
}
thisObj->UpdateText();
ScriptInterface::ToJSVal(cx, args.rval(), thisObj->m_GeneratedTexts[0].GetSize());
ScriptInterface::ToJSVal(rq, args.rval(), thisObj->m_GeneratedTexts[0].GetSize());
return true;
}

View File

@ -29,13 +29,12 @@
#include <string>
#define SET(obj, name, value) STMT(JS::RootedValue v_(cx); AssignOrToJSVal(cx, &v_, (value)); JS_SetProperty(cx, obj, (name), v_))
#define SET(obj, name, value) STMT(JS::RootedValue v_(rq.cx); AssignOrToJSVal(rq, &v_, (value)); JS_SetProperty(rq.cx, obj, (name), v_))
// ignore JS_SetProperty return value, because errors should be impossible
// and we can't do anything useful in the case of errors anyway
template<> void ScriptInterface::ToJSVal<SDL_Event_>(JSContext* cx, JS::MutableHandleValue ret, SDL_Event_ const& val)
template<> void ScriptInterface::ToJSVal<SDL_Event_>(const Request& rq, JS::MutableHandleValue ret, SDL_Event_ const& val)
{
JSAutoRequest rq(cx);
const char* typeName;
switch (val.ev.type)
@ -52,7 +51,7 @@ template<> void ScriptInterface::ToJSVal<SDL_Event_>(JSContext* cx, JS::MutableH
default: typeName = "(unknown)"; break;
}
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx));
if (!obj)
{
ret.setUndefined();
@ -69,14 +68,14 @@ template<> void ScriptInterface::ToJSVal<SDL_Event_>(JSContext* cx, JS::MutableH
// SET(obj, "which", (int)val.ev.key.which); // (not in wsdl.h)
// SET(obj, "state", (int)val.ev.key.state); // (not in wsdl.h)
JS::RootedObject keysym(cx, JS_NewPlainObject(cx));
JS::RootedObject keysym(rq.cx, JS_NewPlainObject(rq.cx));
if (!keysym)
{
ret.setUndefined();
return;
}
JS::RootedValue keysymVal(cx, JS::ObjectValue(*keysym));
JS_SetProperty(cx, obj, "keysym", keysymVal);
JS::RootedValue keysymVal(rq.cx, JS::ObjectValue(*keysym));
JS_SetProperty(rq.cx, obj, "keysym", keysymVal);
// SET(keysym, "scancode", (int)val.ev.key.keysym.scancode); // (not in wsdl.h)
SET(keysym, "sym", (int)val.ev.key.keysym.sym);
@ -121,7 +120,7 @@ template<> void ScriptInterface::ToJSVal<SDL_Event_>(JSContext* cx, JS::MutableH
ret.setObject(*obj);
}
template<> void ScriptInterface::ToJSVal<IGUIObject*>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, IGUIObject* const& val)
template<> void ScriptInterface::ToJSVal<IGUIObject*>(const Request& UNUSED(rq), JS::MutableHandleValue ret, IGUIObject* const& val)
{
if (val == nullptr)
ret.setNull();
@ -129,15 +128,15 @@ template<> void ScriptInterface::ToJSVal<IGUIObject*>(JSContext* UNUSED(cx), JS:
ret.setObject(*val->GetJSObject());
}
template<> void ScriptInterface::ToJSVal<CGUIString>(JSContext* cx, JS::MutableHandleValue ret, const CGUIString& val)
template<> void ScriptInterface::ToJSVal<CGUIString>(const Request& rq, JS::MutableHandleValue ret, const CGUIString& val)
{
ScriptInterface::ToJSVal(cx, ret, val.GetOriginalString());
ScriptInterface::ToJSVal(rq, ret, val.GetOriginalString());
}
template<> bool ScriptInterface::FromJSVal<CGUIString>(JSContext* cx, JS::HandleValue v, CGUIString& out)
template<> bool ScriptInterface::FromJSVal<CGUIString>(const Request& rq, JS::HandleValue v, CGUIString& out)
{
std::wstring val;
if (!FromJSVal(cx, v, val))
if (!FromJSVal(rq, v, val))
return false;
out.SetValue(val);
return true;
@ -147,82 +146,76 @@ JSVAL_VECTOR(CVector2D)
JSVAL_VECTOR(std::vector<CVector2D>)
JSVAL_VECTOR(CGUIString)
template<> void ScriptInterface::ToJSVal<CGUIColor>(JSContext* cx, JS::MutableHandleValue ret, const CGUIColor& val)
template<> void ScriptInterface::ToJSVal<CGUIColor>(const Request& rq, JS::MutableHandleValue ret, const CGUIColor& val)
{
ToJSVal<CColor>(cx, ret, val);
ToJSVal<CColor>(rq, ret, val);
}
/**
* The color depends on the predefined color database stored in the current GUI page.
*/
template<> bool ScriptInterface::FromJSVal<CGUIColor>(JSContext* cx, JS::HandleValue v, CGUIColor& out) = delete;
template<> bool ScriptInterface::FromJSVal<CGUIColor>(const Request& rq, JS::HandleValue v, CGUIColor& out) = delete;
template<> void ScriptInterface::ToJSVal<CSize>(JSContext* cx, JS::MutableHandleValue ret, const CSize& val)
template<> void ScriptInterface::ToJSVal<CSize>(const Request& rq, JS::MutableHandleValue ret, const CSize& val)
{
CreateObject(cx, ret, "width", val.cx, "height", val.cy);
CreateObject(rq, ret, "width", val.cx, "height", val.cy);
}
template<> bool ScriptInterface::FromJSVal<CSize>(JSContext* cx, JS::HandleValue v, CSize& out)
template<> bool ScriptInterface::FromJSVal<CSize>(const Request& rq, JS::HandleValue v, CSize& out)
{
if (!v.isObject())
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "CSize value must be an object!");
JS_ReportError(rq.cx, "CSize value must be an object!");
return false;
}
if (!FromJSProperty(cx, v, "width", out.cx))
if (!FromJSProperty(rq, v, "width", out.cx))
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "Failed to get CSize.cx property");
JS_ReportError(rq.cx, "Failed to get CSize.cx property");
return false;
}
if (!FromJSProperty(cx, v, "height", out.cy))
if (!FromJSProperty(rq, v, "height", out.cy))
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "Failed to get CSize.cy property");
JS_ReportError(rq.cx, "Failed to get CSize.cy property");
return false;
}
return true;
}
template<> void ScriptInterface::ToJSVal<CPos>(JSContext* cx, JS::MutableHandleValue ret, const CPos& val)
template<> void ScriptInterface::ToJSVal<CPos>(const Request& rq, JS::MutableHandleValue ret, const CPos& val)
{
CreateObject(cx, ret, "x", val.x, "y", val.y);
CreateObject(rq, ret, "x", val.x, "y", val.y);
}
template<> bool ScriptInterface::FromJSVal<CPos>(JSContext* cx, JS::HandleValue v, CPos& out)
template<> bool ScriptInterface::FromJSVal<CPos>(const Request& rq, JS::HandleValue v, CPos& out)
{
if (!v.isObject())
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "CPos value must be an object!");
JS_ReportError(rq.cx, "CPos value must be an object!");
return false;
}
if (!FromJSProperty(cx, v, "x", out.x))
if (!FromJSProperty(rq, v, "x", out.x))
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "Failed to get CPos.x property");
JS_ReportError(rq.cx, "Failed to get CPos.x property");
return false;
}
if (!FromJSProperty(cx, v, "y", out.y))
if (!FromJSProperty(rq, v, "y", out.y))
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "Failed to get CPos.y property");
JS_ReportError(rq.cx, "Failed to get CPos.y property");
return false;
}
return true;
}
template<> void ScriptInterface::ToJSVal<CRect>(JSContext* cx, JS::MutableHandleValue ret, const CRect& val)
template<> void ScriptInterface::ToJSVal<CRect>(const Request& rq, JS::MutableHandleValue ret, const CRect& val)
{
CreateObject(
cx,
rq,
ret,
"left", val.left,
"right", val.right,
@ -230,37 +223,37 @@ template<> void ScriptInterface::ToJSVal<CRect>(JSContext* cx, JS::MutableHandle
"bottom", val.bottom);
}
template<> void ScriptInterface::ToJSVal<CGUISize>(JSContext* cx, JS::MutableHandleValue ret, const CGUISize& val)
template<> void ScriptInterface::ToJSVal<CGUISize>(const Request& rq, JS::MutableHandleValue ret, const CGUISize& val)
{
val.ToJSVal(cx, ret);
val.ToJSVal(rq, ret);
}
template<> bool ScriptInterface::FromJSVal<CGUISize>(JSContext* cx, JS::HandleValue v, CGUISize& out)
template<> bool ScriptInterface::FromJSVal<CGUISize>(const Request& rq, JS::HandleValue v, CGUISize& out)
{
return out.FromJSVal(cx, v);
return out.FromJSVal(rq, v);
}
template<> void ScriptInterface::ToJSVal<CGUIList>(JSContext* cx, JS::MutableHandleValue ret, const CGUIList& val)
template<> void ScriptInterface::ToJSVal<CGUIList>(const Request& rq, JS::MutableHandleValue ret, const CGUIList& val)
{
ToJSVal(cx, ret, val.m_Items);
ToJSVal(rq, ret, val.m_Items);
}
template<> bool ScriptInterface::FromJSVal<CGUIList>(JSContext* cx, JS::HandleValue v, CGUIList& out)
template<> bool ScriptInterface::FromJSVal<CGUIList>(const Request& rq, JS::HandleValue v, CGUIList& out)
{
return FromJSVal(cx, v, out.m_Items);
return FromJSVal(rq, v, out.m_Items);
}
template<> void ScriptInterface::ToJSVal<CGUISeries>(JSContext* cx, JS::MutableHandleValue ret, const CGUISeries& val)
template<> void ScriptInterface::ToJSVal<CGUISeries>(const Request& rq, JS::MutableHandleValue ret, const CGUISeries& val)
{
ToJSVal(cx, ret, val.m_Series);
ToJSVal(rq, ret, val.m_Series);
}
template<> bool ScriptInterface::FromJSVal<CGUISeries>(JSContext* cx, JS::HandleValue v, CGUISeries& out)
template<> bool ScriptInterface::FromJSVal<CGUISeries>(const Request& rq, JS::HandleValue v, CGUISeries& out)
{
return FromJSVal(cx, v, out.m_Series);
return FromJSVal(rq, v, out.m_Series);
}
template<> void ScriptInterface::ToJSVal<EVAlign>(JSContext* cx, JS::MutableHandleValue ret, const EVAlign& val)
template<> void ScriptInterface::ToJSVal<EVAlign>(const Request& rq, JS::MutableHandleValue ret, const EVAlign& val)
{
std::string word;
switch (val)
@ -279,17 +272,16 @@ template<> void ScriptInterface::ToJSVal<EVAlign>(JSContext* cx, JS::MutableHand
default:
word = "error";
JSAutoRequest rq(cx);
JS_ReportError(cx, "Invalid EVAlign");
JS_ReportError(rq.cx, "Invalid EVAlign");
break;
}
ToJSVal(cx, ret, word);
ToJSVal(rq, ret, word);
}
template<> bool ScriptInterface::FromJSVal<EVAlign>(JSContext* cx, JS::HandleValue v, EVAlign& out)
template<> bool ScriptInterface::FromJSVal<EVAlign>(const Request& rq, JS::HandleValue v, EVAlign& out)
{
std::string word;
FromJSVal(cx, v, word);
FromJSVal(rq, v, word);
if (word == "top")
out = EVAlign_Top;
@ -300,14 +292,13 @@ template<> bool ScriptInterface::FromJSVal<EVAlign>(JSContext* cx, JS::HandleVal
else
{
out = EVAlign_Top;
JSAutoRequest rq(cx);
JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')");
JS_ReportError(rq.cx, "Invalid alignment (should be 'left', 'right' or 'center')");
return false;
}
return true;
}
template<> void ScriptInterface::ToJSVal<EAlign>(JSContext* cx, JS::MutableHandleValue ret, const EAlign& val)
template<> void ScriptInterface::ToJSVal<EAlign>(const Request& rq, JS::MutableHandleValue ret, const EAlign& val)
{
std::string word;
switch (val)
@ -323,17 +314,16 @@ template<> void ScriptInterface::ToJSVal<EAlign>(JSContext* cx, JS::MutableHandl
break;
default:
word = "error";
JSAutoRequest rq(cx);
JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')");
JS_ReportError(rq.cx, "Invalid alignment (should be 'left', 'right' or 'center')");
break;
}
ToJSVal(cx, ret, word);
ToJSVal(rq, ret, word);
}
template<> bool ScriptInterface::FromJSVal<EAlign>(JSContext* cx, JS::HandleValue v, EAlign& out)
template<> bool ScriptInterface::FromJSVal<EAlign>(const Request& rq, JS::HandleValue v, EAlign& out)
{
std::string word;
FromJSVal(cx, v, word);
FromJSVal(rq, v, word);
if (word == "left")
out = EAlign_Left;
@ -344,22 +334,21 @@ template<> bool ScriptInterface::FromJSVal<EAlign>(JSContext* cx, JS::HandleValu
else
{
out = EAlign_Left;
JSAutoRequest rq(cx);
JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')");
JS_ReportError(rq.cx, "Invalid alignment (should be 'left', 'right' or 'center')");
return false;
}
return true;
}
template<> void ScriptInterface::ToJSVal<CGUISpriteInstance>(JSContext* cx, JS::MutableHandleValue ret, const CGUISpriteInstance& val)
template<> void ScriptInterface::ToJSVal<CGUISpriteInstance>(const Request& rq, JS::MutableHandleValue ret, const CGUISpriteInstance& val)
{
ToJSVal(cx, ret, val.GetName());
ToJSVal(rq, ret, val.GetName());
}
template<> bool ScriptInterface::FromJSVal<CGUISpriteInstance>(JSContext* cx, JS::HandleValue v, CGUISpriteInstance& out)
template<> bool ScriptInterface::FromJSVal<CGUISpriteInstance>(const Request& rq, JS::HandleValue v, CGUISpriteInstance& out)
{
std::string name;
if (!FromJSVal(cx, v, name))
if (!FromJSVal(rq, v, name))
return false;
out.SetName(name);

View File

@ -41,9 +41,8 @@ void JSI_GUIManager::PopGuiPage(ScriptInterface::CxPrivate* pCxPrivate, JS::Hand
{
if (g_GUI->GetPageCount() < 2)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Can't pop GUI pages when less than two pages are opened!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Can't pop GUI pages when less than two pages are opened!");
return;
}

View File

@ -43,45 +43,46 @@ void JSI_GUISize::RegisterScriptClass(ScriptInterface& scriptInterface)
bool JSI_GUISize::construct(JSContext* cx, uint argc, JS::Value* vp)
{
JSAutoRequest rq(cx);
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
JS::RootedObject obj(cx, pScriptInterface->CreateCustomObject("GUISize"));
ScriptInterface::Request rq(*pScriptInterface);
JS::RootedObject obj(rq.cx, pScriptInterface->CreateCustomObject("GUISize"));
if (args.length() == 8)
{
JS_SetProperty(cx, obj, "left", args[0]);
JS_SetProperty(cx, obj, "top", args[1]);
JS_SetProperty(cx, obj, "right", args[2]);
JS_SetProperty(cx, obj, "bottom", args[3]);
JS_SetProperty(cx, obj, "rleft", args[4]);
JS_SetProperty(cx, obj, "rtop", args[5]);
JS_SetProperty(cx, obj, "rright", args[6]);
JS_SetProperty(cx, obj, "rbottom", args[7]);
JS_SetProperty(rq.cx, obj, "left", args[0]);
JS_SetProperty(rq.cx, obj, "top", args[1]);
JS_SetProperty(rq.cx, obj, "right", args[2]);
JS_SetProperty(rq.cx, obj, "bottom", args[3]);
JS_SetProperty(rq.cx, obj, "rleft", args[4]);
JS_SetProperty(rq.cx, obj, "rtop", args[5]);
JS_SetProperty(rq.cx, obj, "rright", args[6]);
JS_SetProperty(rq.cx, obj, "rbottom", args[7]);
}
else if (args.length() == 4)
{
JS::RootedValue zero(cx, JS::NumberValue(0));
JS_SetProperty(cx, obj, "left", args[0]);
JS_SetProperty(cx, obj, "top", args[1]);
JS_SetProperty(cx, obj, "right", args[2]);
JS_SetProperty(cx, obj, "bottom", args[3]);
JS_SetProperty(cx, obj, "rleft", zero);
JS_SetProperty(cx, obj, "rtop", zero);
JS_SetProperty(cx, obj, "rright", zero);
JS_SetProperty(cx, obj, "rbottom", zero);
JS::RootedValue zero(rq.cx, JS::NumberValue(0));
JS_SetProperty(rq.cx, obj, "left", args[0]);
JS_SetProperty(rq.cx, obj, "top", args[1]);
JS_SetProperty(rq.cx, obj, "right", args[2]);
JS_SetProperty(rq.cx, obj, "bottom", args[3]);
JS_SetProperty(rq.cx, obj, "rleft", zero);
JS_SetProperty(rq.cx, obj, "rtop", zero);
JS_SetProperty(rq.cx, obj, "rright", zero);
JS_SetProperty(rq.cx, obj, "rbottom", zero);
}
else
{
JS::RootedValue zero(cx, JS::NumberValue(0));
JS_SetProperty(cx, obj, "left", zero);
JS_SetProperty(cx, obj, "top", zero);
JS_SetProperty(cx, obj, "right", zero);
JS_SetProperty(cx, obj, "bottom", zero);
JS_SetProperty(cx, obj, "rleft", zero);
JS_SetProperty(cx, obj, "rtop", zero);
JS_SetProperty(cx, obj, "rright", zero);
JS_SetProperty(cx, obj, "rbottom", zero);
JS::RootedValue zero(rq.cx, JS::NumberValue(0));
JS_SetProperty(rq.cx, obj, "left", zero);
JS_SetProperty(rq.cx, obj, "top", zero);
JS_SetProperty(rq.cx, obj, "right", zero);
JS_SetProperty(rq.cx, obj, "bottom", zero);
JS_SetProperty(rq.cx, obj, "rleft", zero);
JS_SetProperty(rq.cx, obj, "rtop", zero);
JS_SetProperty(rq.cx, obj, "rright", zero);
JS_SetProperty(rq.cx, obj, "rbottom", zero);
}
args.rval().setObject(*obj);
@ -99,11 +100,11 @@ CStr JSI_GUISize::ToPercentString(double pix, double per)
bool JSI_GUISize::toString(JSContext* cx, uint argc, JS::Value* vp)
{
// JSAutoRequest not needed for the calls below
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
CStr buffer;
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
ScriptInterface::Request rq(*pScriptInterface);
double val, valr;
#define SIDE(side) \
@ -120,6 +121,6 @@ bool JSI_GUISize::toString(JSContext* cx, uint argc, JS::Value* vp)
SIDE(bottom);
#undef SIDE
ScriptInterface::ToJSVal(cx, args.rval(), buffer);
ScriptInterface::ToJSVal(rq, args.rval(), buffer);
return true;
}

View File

@ -52,19 +52,19 @@ void JSI_IGUIObject::RegisterScriptClass(ScriptInterface& scriptInterface)
bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp)
{
JSAutoRequest rq(cx);
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
ScriptInterface::Request rq(*pScriptInterface);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(cx, obj, &JSI_IGUIObject::JSI_class);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, obj, &JSI_IGUIObject::JSI_class);
if (!e)
return false;
JS::RootedValue idval(cx);
if (!JS_IdToValue(cx, id, &idval))
JS::RootedValue idval(rq.cx);
if (!JS_IdToValue(rq.cx, id, &idval))
return false;
std::string propName;
if (!ScriptInterface::FromJSVal(cx, idval, propName))
if (!ScriptInterface::FromJSVal(rq, idval, propName))
return false;
// Skip registered functions and inherited properties
@ -105,7 +105,7 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
}
else if (propName == "children")
{
ScriptInterface::CreateArray(cx, vp);
ScriptInterface::CreateArray(rq, vp);
for (size_t i = 0; i < e->m_Children.size(); ++i)
pScriptInterface->SetPropertyInt(vp, i, e->m_Children[i]);
@ -114,12 +114,12 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
}
else if (propName == "name")
{
ScriptInterface::ToJSVal(cx, vp, e->GetName());
ScriptInterface::ToJSVal(rq, vp, e->GetName());
return true;
}
else if (e->SettingExists(propName))
{
e->m_Settings[propName]->ToJSVal(cx, vp);
e->m_Settings[propName]->ToJSVal(rq, vp);
return true;
}
@ -129,36 +129,37 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result)
{
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(cx, obj, &JSI_IGUIObject::JSI_class);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, obj, &JSI_IGUIObject::JSI_class);
if (!e)
return result.fail(JSMSG_NOT_NONNULL_OBJECT);
JSAutoRequest rq(cx);
JS::RootedValue idval(cx);
if (!JS_IdToValue(cx, id, &idval))
JS::RootedValue idval(rq.cx);
if (!JS_IdToValue(rq.cx, id, &idval))
return result.fail(JSMSG_NOT_NONNULL_OBJECT);
std::string propName;
if (!ScriptInterface::FromJSVal(cx, idval, propName))
if (!ScriptInterface::FromJSVal(rq, idval, propName))
return result.fail(JSMSG_UNDEFINED_PROP);
if (propName == "name")
{
std::string value;
if (!ScriptInterface::FromJSVal(cx, vp, value))
if (!ScriptInterface::FromJSVal(rq, vp, value))
return result.fail(JSMSG_UNDEFINED_PROP);
e->SetName(value);
return result.succeed();
}
JS::RootedObject vpObj(cx);
JS::RootedObject vpObj(rq.cx);
if (vp.isObject())
vpObj = &vp.toObject();
// Use onWhatever to set event handlers
if (propName.substr(0, 2) == "on")
{
if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(cx, &vp.toObject()))
if (vp.isPrimitive() || vp.isNull() || !JS_ObjectIsFunction(rq.cx, &vp.toObject()))
{
LOGERROR("on- event-handlers must be functions");
return result.fail(JSMSG_NOT_FUNCTION);
@ -171,7 +172,7 @@ bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
}
if (e->SettingExists(propName))
return e->m_Settings[propName]->FromJSVal(cx, vp, true) ? result.succeed() : result.fail(JSMSG_TYPE_ERR_BAD_ARGS);
return e->m_Settings[propName]->FromJSVal(rq, vp, true) ? result.succeed() : result.fail(JSMSG_TYPE_ERR_BAD_ARGS);
LOGERROR("Property '%s' does not exist!", propName.c_str());
return result.fail(JSMSG_UNDEFINED_PROP);
@ -179,17 +180,18 @@ bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
bool JSI_IGUIObject::deleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result)
{
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(cx, obj, &JSI_IGUIObject::JSI_class);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, obj, &JSI_IGUIObject::JSI_class);
if (!e)
return result.fail(JSMSG_NOT_NONNULL_OBJECT);
JSAutoRequest rq(cx);
JS::RootedValue idval(cx);
if (!JS_IdToValue(cx, id, &idval))
JS::RootedValue idval(rq.cx);
if (!JS_IdToValue(rq.cx, id, &idval))
return result.fail(JSMSG_NOT_NONNULL_OBJECT);
std::string propName;
if (!ScriptInterface::FromJSVal(cx, idval, propName))
if (!ScriptInterface::FromJSVal(rq, idval, propName))
return result.fail(JSMSG_UNDEFINED_PROP);
// event handlers
@ -206,21 +208,24 @@ bool JSI_IGUIObject::deleteProperty(JSContext* cx, JS::HandleObject obj, JS::Han
bool JSI_IGUIObject::toString(JSContext* cx, uint argc, JS::Value* vp)
{
// No JSAutoRequest needed for these calls
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(cx, args, &JSI_IGUIObject::JSI_class);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, args, &JSI_IGUIObject::JSI_class);
if (!e)
return false;
ScriptInterface::ToJSVal(cx, args.rval(), "[GUIObject: " + e->GetName() + "]");
ScriptInterface::ToJSVal(rq, args.rval(), "[GUIObject: " + e->GetName() + "]");
return true;
}
bool JSI_IGUIObject::focus(JSContext* cx, uint argc, JS::Value* vp)
{
// No JSAutoRequest needed for these calls
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(cx, args, &JSI_IGUIObject::JSI_class);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, args, &JSI_IGUIObject::JSI_class);
if (!e)
return false;
@ -231,9 +236,10 @@ bool JSI_IGUIObject::focus(JSContext* cx, uint argc, JS::Value* vp)
bool JSI_IGUIObject::blur(JSContext* cx, uint argc, JS::Value* vp)
{
// No JSAutoRequest needed for these calls
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(cx, args, &JSI_IGUIObject::JSI_class);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, args, &JSI_IGUIObject::JSI_class);
if (!e)
return false;
@ -244,15 +250,15 @@ bool JSI_IGUIObject::blur(JSContext* cx, uint argc, JS::Value* vp)
bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp)
{
JSAutoRequest rq(cx);
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(cx, args, &JSI_IGUIObject::JSI_class);
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
IGUIObject* e = ScriptInterface::GetPrivate<IGUIObject>(rq, args, &JSI_IGUIObject::JSI_class);
if (!e)
return false;
e->UpdateCachedSize();
ScriptInterface::ToJSVal(cx, args.rval(), e->m_CachedActualSize);
ScriptInterface::ToJSVal(rq, args.rval(), e->m_CachedActualSize);
return true;
}

View File

@ -140,29 +140,28 @@ bool CGUISize::FromString(const CStr& Value)
return true;
}
void CGUISize::ToJSVal(JSContext* cx, JS::MutableHandleValue ret) const
void CGUISize::ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue ret) const
{
JSAutoRequest rq(cx);
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(rq.cx)->pScriptInterface;
ret.setObjectOrNull(pScriptInterface->CreateCustomObject("GUISize"));
if (!ret.isObject())
{
JS_ReportError(cx, "CGUISize value is not an Object");
JS_ReportError(rq.cx, "CGUISize value is not an Object");
return;
}
JS::RootedObject obj(cx, &ret.toObject());
if (!JS_InstanceOf(cx, obj, &JSI_GUISize::JSI_class, nullptr))
JS::RootedObject obj(rq.cx, &ret.toObject());
if (!JS_InstanceOf(rq.cx, obj, &JSI_GUISize::JSI_class, nullptr))
{
JS_ReportError(cx, "CGUISize value is not a CGUISize class instance");
JS_ReportError(rq.cx, "CGUISize value is not a CGUISize class instance");
return;
}
#define P(x, y, z)\
if (!pScriptInterface->SetProperty(ret, #z, x.y)) \
{ \
JS_ReportError(cx, "Could not SetProperty '%s'", #z); \
JS_ReportError(rq.cx, "Could not SetProperty '%s'", #z); \
return; \
}
P(pixel, left, left);
@ -176,23 +175,22 @@ void CGUISize::ToJSVal(JSContext* cx, JS::MutableHandleValue ret) const
#undef P
}
bool CGUISize::FromJSVal(JSContext* cx, JS::HandleValue v)
bool CGUISize::FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue v)
{
JSAutoRequest rq(cx);
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(rq.cx)->pScriptInterface;
if (v.isString())
{
CStrW str;
if (!ScriptInterface::FromJSVal(cx, v, str))
if (!ScriptInterface::FromJSVal(rq, v, str))
{
JS_ReportError(cx, "CGUISize could not read JS string");
JS_ReportError(rq.cx, "CGUISize could not read JS string");
return false;
}
if (!FromString(str.ToUTF8()))
{
JS_ReportError(cx, "CGUISize could not parse JS string");
JS_ReportError(rq.cx, "CGUISize could not parse JS string");
return false;
}
return true;
@ -200,21 +198,21 @@ bool CGUISize::FromJSVal(JSContext* cx, JS::HandleValue v)
if (!v.isObject())
{
JS_ReportError(cx, "CGUISize value is not an String, nor Object");
JS_ReportError(rq.cx, "CGUISize value is not an String, nor Object");
return false;
}
JS::RootedObject obj(cx, &v.toObject());
if (!JS_InstanceOf(cx, obj, &JSI_GUISize::JSI_class, nullptr))
JS::RootedObject obj(rq.cx, &v.toObject());
if (!JS_InstanceOf(rq.cx, obj, &JSI_GUISize::JSI_class, nullptr))
{
JS_ReportError(cx, "CGUISize value is not a CGUISize class instance");
JS_ReportError(rq.cx, "CGUISize value is not a CGUISize class instance");
return false;
}
#define P(x, y, z) \
if (!pScriptInterface->GetProperty(v, #z, x.y))\
{\
JS_ReportError(cx, "CGUISize could not get object property '%s'", #z);\
JS_ReportError(rq.cx, "CGUISize could not get object property '%s'", #z);\
return false;\
}

View File

@ -67,8 +67,8 @@ public:
return pixel == other.pixel && percent == other.percent;
}
void ToJSVal(JSContext* cx, JS::MutableHandleValue ret) const;
bool FromJSVal(JSContext* cx, JS::HandleValue v);
void ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue ret) const;
bool FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue v);
};
#endif // INCLUDED_CGUISIZE

View File

@ -62,10 +62,9 @@ public:
// Load up a test page.
const ScriptInterface& scriptInterface = *(g_GUI->GetScriptInterface());
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue val(cx);
scriptInterface.CreateObject(cx, &val);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue val(rq.cx);
scriptInterface.CreateObject(rq, &val);
std::shared_ptr<ScriptInterface::StructuredClone> data = scriptInterface.WriteStructuredClone(JS::NullHandleValue);
g_GUI->PushPage(L"hotkey/page_hotkey.xml", data, JS::UndefinedHandleValue);
@ -84,21 +83,20 @@ public:
in_dispatch_event(&ev);
const ScriptInterface& pageScriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface());
JSContext* pcx = pageScriptInterface.GetContext();
JSAutoRequest pagerq(pcx);
JS::RootedValue global(pcx, pageScriptInterface.GetGlobalObject());
ScriptInterface::Request prq(pageScriptInterface);
JS::RootedValue global(prq.cx, pageScriptInterface.GetGlobalObject());
// Ensure that our hotkey state was synchronised with the event itself.
bool hotkey_pressed_value = false;
JS::RootedValue js_hotkey_pressed_value(pageScriptInterface.GetContext());
JS::RootedValue js_hotkey_pressed_value(prq.cx);
pageScriptInterface.GetProperty(global, "state_before", &js_hotkey_pressed_value);
ScriptInterface::FromJSVal(pcx, js_hotkey_pressed_value, hotkey_pressed_value);
ScriptInterface::FromJSVal(prq, js_hotkey_pressed_value, hotkey_pressed_value);
TS_ASSERT_EQUALS(hotkey_pressed_value, true);
hotkey_pressed_value = false;
pageScriptInterface.GetProperty(global, "state_after", &js_hotkey_pressed_value);
ScriptInterface::FromJSVal(pcx, js_hotkey_pressed_value, hotkey_pressed_value);
ScriptInterface::FromJSVal(prq, js_hotkey_pressed_value, hotkey_pressed_value);
TS_ASSERT_EQUALS(hotkey_pressed_value, true);
// We are listening to KeyDown events, so repeat shouldn't matter.
@ -109,12 +107,12 @@ public:
hotkey_pressed_value = false;
pageScriptInterface.GetProperty(global, "state_before", &js_hotkey_pressed_value);
ScriptInterface::FromJSVal(pcx, js_hotkey_pressed_value, hotkey_pressed_value);
ScriptInterface::FromJSVal(prq, js_hotkey_pressed_value, hotkey_pressed_value);
TS_ASSERT_EQUALS(hotkey_pressed_value, true);
hotkey_pressed_value = false;
pageScriptInterface.GetProperty(global, "state_after", &js_hotkey_pressed_value);
ScriptInterface::FromJSVal(pcx, js_hotkey_pressed_value, hotkey_pressed_value);
ScriptInterface::FromJSVal(prq, js_hotkey_pressed_value, hotkey_pressed_value);
TS_ASSERT_EQUALS(hotkey_pressed_value, true);
hotkeyNotification.ev.type = SDL_KEYUP;
@ -124,12 +122,12 @@ public:
hotkey_pressed_value = true;
pageScriptInterface.GetProperty(global, "state_before", &js_hotkey_pressed_value);
ScriptInterface::FromJSVal(pcx, js_hotkey_pressed_value, hotkey_pressed_value);
ScriptInterface::FromJSVal(prq, js_hotkey_pressed_value, hotkey_pressed_value);
TS_ASSERT_EQUALS(hotkey_pressed_value, false);
hotkey_pressed_value = true;
pageScriptInterface.GetProperty(global, "state_after", &js_hotkey_pressed_value);
ScriptInterface::FromJSVal(pcx, js_hotkey_pressed_value, hotkey_pressed_value);
ScriptInterface::FromJSVal(prq, js_hotkey_pressed_value, hotkey_pressed_value);
TS_ASSERT_EQUALS(hotkey_pressed_value, false);
}

View File

@ -537,18 +537,17 @@ void XmppClient::handleOOB(const glooxwrapper::JID&, const glooxwrapper::OOB&)
*/
void XmppClient::GUIGetPlayerList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
ScriptInterface::CreateArray(cx, ret);
ScriptInterface::CreateArray(rq, ret);
int j = 0;
for (const std::pair<glooxwrapper::string, SPlayer>& p : m_PlayerMap)
{
JS::RootedValue player(cx);
JS::RootedValue player(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&player,
"name", p.first,
"presence", p.second.m_Presence,
@ -566,10 +565,9 @@ void XmppClient::GUIGetPlayerList(const ScriptInterface& scriptInterface, JS::Mu
*/
void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
ScriptInterface::CreateArray(cx, ret);
ScriptInterface::CreateArray(rq, ret);
int j = 0;
const char* stats[] = { "name", "ip", "port", "stunIP", "stunPort", "hostUsername", "state",
@ -578,8 +576,8 @@ void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::Muta
for(const glooxwrapper::Tag* const& t : m_GameList)
{
JS::RootedValue game(cx);
ScriptInterface::CreateObject(cx, &game);
JS::RootedValue game(rq.cx);
ScriptInterface::CreateObject(rq, &game);
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i)
scriptInterface.SetProperty(game, stats[i], t->findAttribute(stats[i]));
@ -595,18 +593,17 @@ void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::Muta
*/
void XmppClient::GUIGetBoardList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
ScriptInterface::CreateArray(cx, ret);
ScriptInterface::CreateArray(rq, ret);
int j = 0;
const char* attributes[] = { "name", "rank", "rating" };
for(const glooxwrapper::Tag* const& t : m_BoardList)
{
JS::RootedValue board(cx);
ScriptInterface::CreateObject(cx, &board);
JS::RootedValue board(rq.cx);
ScriptInterface::CreateObject(rq, &board);
for (size_t i = 0; i < ARRAY_SIZE(attributes); ++i)
scriptInterface.SetProperty(board, attributes[i], t->findAttribute(attributes[i]));
@ -622,18 +619,17 @@ void XmppClient::GUIGetBoardList(const ScriptInterface& scriptInterface, JS::Mut
*/
void XmppClient::GUIGetProfile(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
ScriptInterface::CreateArray(cx, ret);
ScriptInterface::CreateArray(rq, ret);
int j = 0;
const char* stats[] = { "player", "rating", "totalGamesPlayed", "highestRating", "wins", "losses", "rank" };
for (const glooxwrapper::Tag* const& t : m_Profile)
{
JS::RootedValue profile(cx);
ScriptInterface::CreateObject(cx, &profile);
JS::RootedValue profile(rq.cx);
ScriptInterface::CreateObject(rq, &profile);
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i)
scriptInterface.SetProperty(profile, stats[i], t->findAttribute(stats[i]));
@ -646,18 +642,17 @@ void XmppClient::GUIGetProfile(const ScriptInterface& scriptInterface, JS::Mutab
* Message interfaces *
*****************************************************/
void SetGUIMessageProperty(JSContext* UNUSED(cx), JS::HandleObject UNUSED(messageObj))
void SetGUIMessageProperty(const ScriptInterface::Request& UNUSED(rq), JS::HandleObject UNUSED(messageObj))
{
}
template<typename T, typename... Args>
void SetGUIMessageProperty(JSContext* cx, JS::HandleObject messageObj, const std::string& propertyName, const T& propertyValue, Args const&... args)
void SetGUIMessageProperty(const ScriptInterface::Request& rq, JS::HandleObject messageObj, const std::string& propertyName, const T& propertyValue, Args const&... args)
{
// JSAutoRequest is the responsibility of the caller
JS::RootedValue scriptPropertyValue(cx);
ScriptInterface::AssignOrToJSVal(cx, &scriptPropertyValue, propertyValue);
JS_DefineProperty(cx, messageObj, propertyName.c_str(), scriptPropertyValue, JSPROP_ENUMERATE);
SetGUIMessageProperty(cx, messageObj, args...);
JS::RootedValue scriptPropertyValue(rq.cx);
ScriptInterface::AssignOrToJSVal(rq, &scriptPropertyValue, propertyValue);
JS_DefineProperty(rq.cx, messageObj, propertyName.c_str(), scriptPropertyValue, JSPROP_ENUMERATE);
SetGUIMessageProperty(rq, messageObj, args...);
}
template<typename... Args>
@ -669,19 +664,18 @@ void XmppClient::CreateGUIMessage(
{
if (!m_ScriptInterface)
return;
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue message(cx);
ScriptInterface::Request rq(m_ScriptInterface);
JS::RootedValue message(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&message,
"type", type,
"level", level,
"historic", false,
"time", static_cast<double>(time));
JS::RootedObject messageObj(cx, message.toObjectOrNull());
SetGUIMessageProperty(cx, messageObj, args...);
JS::RootedObject messageObj(rq.cx, message.toObjectOrNull());
SetGUIMessageProperty(rq, messageObj, args...);
m_ScriptInterface->FreezeObject(message, true);
m_GuiMessageQueue.push_back(JS::Heap<JS::Value>(message));
}
@ -703,13 +697,12 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface)
if ((m_isConnected && !m_initialLoadComplete) || m_GuiMessageQueue.empty())
return JS::UndefinedValue();
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
// Optimize for batch message processing that is more
// performance demanding than processing a lone message.
JS::RootedValue messages(cx);
ScriptInterface::CreateArray(cx, &messages);
JS::RootedValue messages(rq.cx);
ScriptInterface::CreateArray(rq, &messages);
int j = 0;
@ -719,7 +712,7 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface)
// Store historic chat messages.
// Only store relevant messages to minimize memory footprint.
JS::RootedValue rootedMessage(cx, message);
JS::RootedValue rootedMessage(rq.cx, message);
std::string type;
m_ScriptInterface->GetProperty(rootedMessage, "type", type);
if (type != "chat")
@ -730,8 +723,8 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& scriptInterface)
if (level != "room-message" && level != "private-message")
continue;
JS::RootedValue historicMessage(cx);
if (JS_StructuredClone(cx, rootedMessage, &historicMessage, nullptr, nullptr))
JS::RootedValue historicMessage(rq.cx);
if (JS_StructuredClone(rq.cx, rootedMessage, &historicMessage, nullptr, nullptr))
{
m_ScriptInterface->SetProperty(historicMessage, "historic", true);
m_ScriptInterface->FreezeObject(historicMessage, true);
@ -751,11 +744,10 @@ JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInter
if (m_HistoricGuiMessages.empty())
return JS::UndefinedValue();
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
JS::RootedValue messages(cx);
ScriptInterface::CreateArray(cx, &messages);
JS::RootedValue messages(rq.cx);
ScriptInterface::CreateArray(rq, &messages);
int j = 0;
for (const JS::Heap<JS::Value>& message : m_HistoricGuiMessages)

View File

@ -23,39 +23,39 @@
#include "lobby/XmppClient.h"
#include "scriptinterface/ScriptInterface.h"
template<> void ScriptInterface::ToJSVal<glooxwrapper::string>(JSContext* cx, JS::MutableHandleValue ret, const glooxwrapper::string& val)
template<> void ScriptInterface::ToJSVal<glooxwrapper::string>(const Request& rq, JS::MutableHandleValue ret, const glooxwrapper::string& val)
{
ToJSVal(cx, ret, wstring_from_utf8(val.to_string()));
ToJSVal(rq, ret, wstring_from_utf8(val.to_string()));
}
template<> void ScriptInterface::ToJSVal<gloox::Presence::PresenceType>(JSContext* cx, JS::MutableHandleValue ret, const gloox::Presence::PresenceType& val)
template<> void ScriptInterface::ToJSVal<gloox::Presence::PresenceType>(const Request& rq, JS::MutableHandleValue ret, const gloox::Presence::PresenceType& val)
{
ToJSVal(cx, ret, XmppClient::GetPresenceString(val));
ToJSVal(rq, ret, XmppClient::GetPresenceString(val));
}
template<> void ScriptInterface::ToJSVal<gloox::MUCRoomRole>(JSContext* cx, JS::MutableHandleValue ret, const gloox::MUCRoomRole& val)
template<> void ScriptInterface::ToJSVal<gloox::MUCRoomRole>(const Request& rq, JS::MutableHandleValue ret, const gloox::MUCRoomRole& val)
{
ToJSVal(cx, ret, XmppClient::GetRoleString(val));
ToJSVal(rq, ret, XmppClient::GetRoleString(val));
}
template<> void ScriptInterface::ToJSVal<gloox::StanzaError>(JSContext* cx, JS::MutableHandleValue ret, const gloox::StanzaError& val)
template<> void ScriptInterface::ToJSVal<gloox::StanzaError>(const Request& rq, JS::MutableHandleValue ret, const gloox::StanzaError& val)
{
ToJSVal(cx, ret, wstring_from_utf8(XmppClient::StanzaErrorToString(val)));
ToJSVal(rq, ret, wstring_from_utf8(XmppClient::StanzaErrorToString(val)));
}
template<> void ScriptInterface::ToJSVal<gloox::ConnectionError>(JSContext* cx, JS::MutableHandleValue ret, const gloox::ConnectionError& val)
template<> void ScriptInterface::ToJSVal<gloox::ConnectionError>(const Request& rq, JS::MutableHandleValue ret, const gloox::ConnectionError& val)
{
ToJSVal(cx, ret, wstring_from_utf8(XmppClient::ConnectionErrorToString(val)));
ToJSVal(rq, ret, wstring_from_utf8(XmppClient::ConnectionErrorToString(val)));
}
template<> void ScriptInterface::ToJSVal<gloox::RegistrationResult>(JSContext* cx, JS::MutableHandleValue ret, const gloox::RegistrationResult& val)
template<> void ScriptInterface::ToJSVal<gloox::RegistrationResult>(const Request& rq, JS::MutableHandleValue ret, const gloox::RegistrationResult& val)
{
ToJSVal(cx, ret, wstring_from_utf8(XmppClient::RegistrationResultToString(val)));
ToJSVal(rq, ret, wstring_from_utf8(XmppClient::RegistrationResultToString(val)));
}
template<> void ScriptInterface::ToJSVal<gloox::CertStatus>(JSContext* cx, JS::MutableHandleValue ret, const gloox::CertStatus& val)
template<> void ScriptInterface::ToJSVal<gloox::CertStatus>(const Request& rq, JS::MutableHandleValue ret, const gloox::CertStatus& val)
{
ToJSVal(cx, ret, wstring_from_utf8(XmppClient::CertificateErrorToString(val)));
ToJSVal(rq, ret, wstring_from_utf8(XmppClient::CertificateErrorToString(val)));
}
#endif // CONFIG2_LOBBY

View File

@ -87,9 +87,8 @@ void JSI_Lobby::StartXmppClient(ScriptInterface::CxPrivate* pCxPrivate, const st
{
if (g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call StartXmppClient with an already initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call StartXmppClient with an already initialized XmppClient!");
return;
}
@ -109,9 +108,8 @@ void JSI_Lobby::StartRegisterXmppClient(ScriptInterface::CxPrivate* pCxPrivate,
{
if (g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call StartRegisterXmppClient with an already initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call StartRegisterXmppClient with an already initialized XmppClient!");
return;
}
@ -130,9 +128,8 @@ void JSI_Lobby::StopXmppClient(ScriptInterface::CxPrivate* pCxPrivate)
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call StopXmppClient without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call StopXmppClient without an initialized XmppClient!");
return;
}
@ -144,9 +141,8 @@ void JSI_Lobby::ConnectXmppClient(ScriptInterface::CxPrivate* pCxPrivate)
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call ConnectXmppClient without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call ConnectXmppClient without an initialized XmppClient!");
return;
}
@ -157,9 +153,8 @@ void JSI_Lobby::DisconnectXmppClient(ScriptInterface::CxPrivate* pCxPrivate)
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call DisconnectXmppClient without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call DisconnectXmppClient without an initialized XmppClient!");
return;
}
@ -170,9 +165,8 @@ bool JSI_Lobby::IsXmppClientConnected(ScriptInterface::CxPrivate* pCxPrivate)
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call IsXmppClientConnected without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call IsXmppClientConnected without an initialized XmppClient!");
return false;
}
@ -183,9 +177,8 @@ void JSI_Lobby::SendGetBoardList(ScriptInterface::CxPrivate* pCxPrivate)
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call SendGetBoardList without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call SendGetBoardList without an initialized XmppClient!");
return;
}
@ -196,9 +189,8 @@ void JSI_Lobby::SendGetProfile(ScriptInterface::CxPrivate* pCxPrivate, const std
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call SendGetProfile without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call SendGetProfile without an initialized XmppClient!");
return;
}
@ -209,9 +201,8 @@ void JSI_Lobby::SendGameReport(ScriptInterface::CxPrivate* pCxPrivate, JS::Handl
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call SendGameReport without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call SendGameReport without an initialized XmppClient!");
return;
}
@ -222,9 +213,8 @@ void JSI_Lobby::SendRegisterGame(ScriptInterface::CxPrivate* pCxPrivate, JS::Han
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call SendRegisterGame without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call SendRegisterGame without an initialized XmppClient!");
return;
}
@ -242,9 +232,8 @@ void JSI_Lobby::SendUnregisterGame(ScriptInterface::CxPrivate* pCxPrivate)
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call SendUnregisterGame without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call SendUnregisterGame without an initialized XmppClient!");
return;
}
@ -255,9 +244,8 @@ void JSI_Lobby::SendChangeStateGame(ScriptInterface::CxPrivate* pCxPrivate, cons
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call SendChangeStateGame without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call SendChangeStateGame without an initialized XmppClient!");
return;
}
@ -266,16 +254,15 @@ void JSI_Lobby::SendChangeStateGame(ScriptInterface::CxPrivate* pCxPrivate, cons
JS::Value JSI_Lobby::GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pCxPrivate);
if (!g_XmppClient)
{
JS_ReportError(cx, "Cannot call GetPlayerList without an initialized XmppClient!");
JS_ReportError(rq.cx, "Cannot call GetPlayerList without an initialized XmppClient!");
return JS::UndefinedValue();
}
JS::RootedValue playerList(cx);
JS::RootedValue playerList(rq.cx);
g_XmppClient->GUIGetPlayerList(*(pCxPrivate->pScriptInterface), &playerList);
return playerList;
@ -283,16 +270,15 @@ JS::Value JSI_Lobby::GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate)
JS::Value JSI_Lobby::GetGameList(ScriptInterface::CxPrivate* pCxPrivate)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pCxPrivate);
if (!g_XmppClient)
{
JS_ReportError(cx, "Cannot call GetGameList without an initialized XmppClient!");
JS_ReportError(rq.cx, "Cannot call GetGameList without an initialized XmppClient!");
return JS::UndefinedValue();
}
JS::RootedValue gameList(cx);
JS::RootedValue gameList(rq.cx);
g_XmppClient->GUIGetGameList(*(pCxPrivate->pScriptInterface), &gameList);
return gameList;
@ -300,16 +286,15 @@ JS::Value JSI_Lobby::GetGameList(ScriptInterface::CxPrivate* pCxPrivate)
JS::Value JSI_Lobby::GetBoardList(ScriptInterface::CxPrivate* pCxPrivate)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pCxPrivate);
if (!g_XmppClient)
{
JS_ReportError(cx, "Cannot call GetBoardList without an initialized XmppClient!");
JS_ReportError(rq.cx, "Cannot call GetBoardList without an initialized XmppClient!");
return JS::UndefinedValue();
}
JS::RootedValue boardList(cx);
JS::RootedValue boardList(rq.cx);
g_XmppClient->GUIGetBoardList(*(pCxPrivate->pScriptInterface), &boardList);
return boardList;
@ -317,16 +302,15 @@ JS::Value JSI_Lobby::GetBoardList(ScriptInterface::CxPrivate* pCxPrivate)
JS::Value JSI_Lobby::GetProfile(ScriptInterface::CxPrivate* pCxPrivate)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pCxPrivate);
if (!g_XmppClient)
{
JS_ReportError(cx, "Cannot call GetProfile without an initialized XmppClient!");
JS_ReportError(rq.cx, "Cannot call GetProfile without an initialized XmppClient!");
return JS::UndefinedValue();
}
JS::RootedValue profileFetch(cx);
JS::RootedValue profileFetch(rq.cx);
g_XmppClient->GUIGetProfile(*(pCxPrivate->pScriptInterface), &profileFetch);
return profileFetch;
@ -336,9 +320,8 @@ bool JSI_Lobby::LobbyGuiPollHasPlayerListUpdate(ScriptInterface::CxPrivate* pCxP
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyGuiPollHasPlayerListUpdate without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyGuiPollHasPlayerListUpdate without an initialized XmppClient!");
return false;
}
@ -357,9 +340,8 @@ JS::Value JSI_Lobby::LobbyGuiPollHistoricMessages(ScriptInterface::CxPrivate* pC
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyGuiPollHistoricMessages without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyGuiPollHistoricMessages without an initialized XmppClient!");
return JS::UndefinedValue();
}
@ -370,9 +352,8 @@ void JSI_Lobby::LobbySendMessage(ScriptInterface::CxPrivate* pCxPrivate, const s
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbySendMessage without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbySendMessage without an initialized XmppClient!");
return;
}
@ -383,9 +364,8 @@ void JSI_Lobby::LobbySetPlayerPresence(ScriptInterface::CxPrivate* pCxPrivate, c
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbySetPlayerPresence without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbySetPlayerPresence without an initialized XmppClient!");
return;
}
@ -396,9 +376,8 @@ void JSI_Lobby::LobbySetNick(ScriptInterface::CxPrivate* pCxPrivate, const std::
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbySetNick without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbySetNick without an initialized XmppClient!");
return;
}
@ -409,9 +388,8 @@ std::wstring JSI_Lobby::LobbyGetNick(ScriptInterface::CxPrivate* pCxPrivate)
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyGetNick without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyGetNick without an initialized XmppClient!");
return std::wstring();
}
@ -424,9 +402,8 @@ void JSI_Lobby::LobbyKick(ScriptInterface::CxPrivate* pCxPrivate, const std::wst
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyKick without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyKick without an initialized XmppClient!");
return;
}
@ -437,9 +414,8 @@ void JSI_Lobby::LobbyBan(ScriptInterface::CxPrivate* pCxPrivate, const std::wstr
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyBan without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyBan without an initialized XmppClient!");
return;
}
@ -450,9 +426,8 @@ const char* JSI_Lobby::LobbyGetPlayerPresence(ScriptInterface::CxPrivate* pCxPri
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyGetPlayerPresence without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyGetPlayerPresence without an initialized XmppClient!");
return "";
}
@ -463,9 +438,8 @@ const char* JSI_Lobby::LobbyGetPlayerRole(ScriptInterface::CxPrivate* pCxPrivate
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyGetPlayerRole without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyGetPlayerRole without an initialized XmppClient!");
return "";
}
@ -476,9 +450,8 @@ std::wstring JSI_Lobby::LobbyGetPlayerRating(ScriptInterface::CxPrivate* pCxPriv
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyGetPlayerRating without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyGetPlayerRating without an initialized XmppClient!");
return std::wstring();
}
@ -536,9 +509,8 @@ std::wstring JSI_Lobby::LobbyGetRoomSubject(ScriptInterface::CxPrivate* pCxPriva
{
if (!g_XmppClient)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Cannot call LobbyGetRoomSubject without an initialized XmppClient!");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Cannot call LobbyGetRoomSubject without an initialized XmppClient!");
return std::wstring();
}

View File

@ -213,8 +213,7 @@ static InReaction MainInputHandler(const SDL_Event_* ev)
// dispatch all pending events to the various receivers.
static void PumpEvents()
{
JSContext* cx = g_GUI->GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(g_GUI->GetScriptInterface());
PROFILE3("dispatch events");
@ -224,8 +223,8 @@ static void PumpEvents()
PROFILE2("event");
if (g_GUI)
{
JS::RootedValue tmpVal(cx);
ScriptInterface::ToJSVal(cx, &tmpVal, ev);
JS::RootedValue tmpVal(rq.cx);
ScriptInterface::ToJSVal(rq, &tmpVal, ev);
std::string data = g_GUI->GetScriptInterface()->StringifyJSON(&tmpVal);
PROFILE2_ATTR("%s", data.c_str());
}

View File

@ -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
@ -71,7 +71,7 @@ CNetClient::CNetClient(CGame* game, bool isLocalClient) :
m_Session(NULL),
m_UserName(L"anonymous"),
m_HostID((u32)-1), m_ClientTurnManager(NULL), m_Game(game),
m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetContext()),
m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetJSRuntime()),
m_IsLocalClient(isLocalClient),
m_LastConnectionCheck(0),
m_Rejoin(false)
@ -251,11 +251,10 @@ void CNetClient::GuiPoll(JS::MutableHandleValue ret)
std::string CNetClient::TestReadGuiMessages()
{
JSContext* cx = GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(GetScriptInterface());
std::string r;
JS::RootedValue msg(cx);
JS::RootedValue msg(rq.cx);
while (true)
{
GuiPoll(&msg);
@ -273,18 +272,17 @@ const ScriptInterface& CNetClient::GetScriptInterface()
void CNetClient::PostPlayerAssignmentsToScript()
{
JSContext* cx = GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(GetScriptInterface());
JS::RootedValue newAssignments(cx);
ScriptInterface::CreateObject(cx, &newAssignments);
JS::RootedValue newAssignments(rq.cx);
ScriptInterface::CreateObject(rq, &newAssignments);
for (const std::pair<CStr, PlayerAssignment>& p : m_PlayerAssignments)
{
JS::RootedValue assignment(cx);
JS::RootedValue assignment(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&assignment,
"name", p.second.m_Name,
"player", p.second.m_PlayerID,

View File

@ -156,11 +156,10 @@ public:
template<typename... Args>
void PushGuiMessage(Args const&... args)
{
JSContext* cx = GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(GetScriptInterface());
JS::RootedValue message(cx);
ScriptInterface::CreateObject(cx, &message, args...);
JS::RootedValue message(rq.cx);
ScriptInterface::CreateObject(rq, &message, args...);
m_GuiMessageQueue.push_back(JS::Heap<JS::Value>(message));
}

View File

@ -419,8 +419,7 @@ bool CNetServerWorker::RunStep()
m_ScriptInterface->GetRuntime()->MaybeIncrementalGC(0.5f);
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
std::vector<bool> newStartGame;
std::vector<std::string> newGameAttributes;
@ -441,7 +440,7 @@ bool CNetServerWorker::RunStep()
if (!newGameAttributes.empty())
{
JS::RootedValue gameAttributesVal(cx);
JS::RootedValue gameAttributesVal(rq.cx);
GetScriptInterface().ParseJSON(newGameAttributes.back(), &gameAttributesVal);
UpdateGameAttributes(&gameAttributesVal);
}
@ -1138,9 +1137,8 @@ bool CNetServerWorker::OnSimulationCommand(void* context, CFsmEvent* event)
// unless cheating is enabled
bool cheatsEnabled = false;
const ScriptInterface& scriptInterface = server.GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue settings(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue settings(rq.cx);
scriptInterface.GetProperty(server.m_GameAttributes, "settings", &settings);
if (scriptInterface.HasProperty(settings, "CheatsEnabled"))
scriptInterface.GetProperty(settings, "CheatsEnabled", cheatsEnabled);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* Copyright (C) 2013-2016 SuperTuxKart-Team.
* This file is part of 0 A.D.
*
@ -390,11 +390,10 @@ JS::Value StunClient::FindStunEndpointHost(const ScriptInterface& scriptInterfac
addr.host = ntohl(m_IP);
enet_address_get_host_ip(&addr, ipStr, ARRAY_SIZE(ipStr));
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue stunEndpoint(cx);
ScriptInterface::CreateObject(cx, &stunEndpoint, "ip", ipStr, "port", m_Port);
JS::RootedValue stunEndpoint(rq.cx);
ScriptInterface::CreateObject(rq, &stunEndpoint, "ip", ipStr, "port", m_Port);
return stunEndpoint;
}

View File

@ -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
@ -155,9 +155,8 @@ JS::Value JSI_Network::PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate)
return JS::UndefinedValue();
// Convert from net client context to GUI script context
JSContext* cxNet = g_NetClient->GetScriptInterface().GetContext();
JSAutoRequest rqNet(cxNet);
JS::RootedValue pollNet(cxNet);
ScriptInterface::Request rqNet(g_NetClient->GetScriptInterface());
JS::RootedValue pollNet(rqNet.cx);
g_NetClient->GuiPoll(&pollNet);
return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(g_NetClient->GetScriptInterface(), pollNet);
}
@ -167,9 +166,8 @@ void JSI_Network::SetNetworkGameAttributes(ScriptInterface::CxPrivate* pCxPrivat
ENSURE(g_NetClient);
// TODO: This is a workaround because we need to pass a MutableHandle to a JSAPI functions somewhere (with no obvious reason).
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue attribs(cx, attribs1);
ScriptInterface::Request rq(pCxPrivate);
JS::RootedValue attribs(rq.cx, attribs1);
g_NetClient->SendGameSetupMessage(&attribs, *(pCxPrivate->pScriptInterface));
}

View File

@ -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
@ -137,8 +137,7 @@ public:
// and prints a load of debug output so you can see if anything funny's going on
ScriptInterface scriptInterface("Engine", "Test", g_ScriptRuntime);
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
TestStdoutLogger logger;
@ -150,9 +149,9 @@ public:
CNetServer server;
JS::RootedValue attrs(cx);
JS::RootedValue attrs(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&attrs,
"mapType", "scenario",
"map", "maps/scenarios/Saharan Oases",
@ -184,9 +183,9 @@ public:
wait(clients, 100);
{
JS::RootedValue cmd(cx);
JS::RootedValue cmd(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&cmd,
"type", "debug-print",
"message", "[>>> client1 test sim command]\\n");
@ -194,9 +193,9 @@ public:
}
{
JS::RootedValue cmd(cx);
JS::RootedValue cmd(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&cmd,
"type", "debug-print",
"message", "[>>> client2 test sim command]\\n");
@ -217,8 +216,7 @@ public:
void test_rejoin_DISABLED()
{
ScriptInterface scriptInterface("Engine", "Test", g_ScriptRuntime);
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
TestStdoutLogger logger;
@ -230,9 +228,9 @@ public:
CNetServer server;
JS::RootedValue attrs(cx);
JS::RootedValue attrs(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&attrs,
"mapType", "scenario",
"map", "maps/scenarios/Saharan Oases",
@ -268,9 +266,9 @@ public:
wait(clients, 100);
{
JS::RootedValue cmd(cx);
JS::RootedValue cmd(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&cmd,
"type", "debug-print",
"message", "[>>> client1 test sim command 1]\\n");
@ -285,9 +283,9 @@ public:
wait(clients, 100);
{
JS::RootedValue cmd(cx);
JS::RootedValue cmd(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&cmd,
"type", "debug-print",
"message", "[>>> client1 test sim command 2]\\n");
@ -344,9 +342,9 @@ public:
// CTurnManager::TurnNeedsFullHash to always return true)
{
JS::RootedValue cmd(cx);
JS::RootedValue cmd(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&cmd,
"type", "debug-print",
"message", "[>>> client1 test sim command 3]\\n");
@ -361,9 +359,9 @@ public:
wait(clients, 100);
{
JS::RootedValue cmd(cx);
JS::RootedValue cmd(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&cmd,
"type", "debug-print",
"message", "[>>> client1 test sim command 4]\\n");

View File

@ -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
@ -27,11 +27,10 @@ public:
void test_sim()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
JS::RootedValue val(cx);
ScriptInterface::CreateArray(cx, &val);
JS::RootedValue val(rq.cx);
ScriptInterface::CreateArray(rq, &val);
script.SetPropertyInt(val, 0, 4);
CSimulationMessage msg(script, 1, 2, 3, val);

View File

@ -544,12 +544,8 @@ void CConsole::UseHistoryFile(const VfsPath& filename, int max_history_lines)
void CConsole::ProcessBuffer(const wchar_t* szLine)
{
shared_ptr<ScriptInterface> pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface();
JSContext* cx = pScriptInterface->GetContext();
JSAutoRequest rq(cx);
if (szLine == NULL) return;
if (wcslen(szLine) <= 0) return;
if (!szLine || wcslen(szLine) <= 0)
return;
ENSURE(wcslen(szLine) < CONSOLE_BUFFER_SIZE);
@ -558,8 +554,10 @@ void CConsole::ProcessBuffer(const wchar_t* szLine)
// a crash it's a useful record.
// Process it as JavaScript
shared_ptr<ScriptInterface> pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface();
ScriptInterface::Request rq(*pScriptInterface);
JS::RootedValue rval(cx);
JS::RootedValue rval(rq.cx);
pScriptInterface->Eval(szLine, &rval);
if (!rval.isUndefined())
InsertMessage(pScriptInterface->ToString(&rval));

View File

@ -191,10 +191,9 @@ bool CGame::StartVisualReplay(const OsPath& replayPath)
std::getline(*m_ReplayStream, line);
const ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue attribs(cx);
JS::RootedValue attribs(rq.cx);
scriptInterface.ParseJSON(line, &attribs);
StartGame(&attribs, "");
@ -209,8 +208,7 @@ bool CGame::StartVisualReplay(const OsPath& replayPath)
void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& savedState)
{
const ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
m_InitialSavedState = savedState;
m_IsSavedGame = !savedState.empty();
@ -240,7 +238,7 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
{
// Load random map attributes
std::wstring scriptFile;
JS::RootedValue settings(cx);
JS::RootedValue settings(rq.cx);
scriptInterface.GetProperty(attribs, "script", scriptFile);
scriptInterface.GetProperty(attribs, "settings", &settings);
@ -250,7 +248,7 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
else
{
std::wstring mapFile;
JS::RootedValue settings(cx);
JS::RootedValue settings(rq.cx);
scriptInterface.GetProperty(attribs, "map", mapFile);
scriptInterface.GetProperty(attribs, "settings", &settings);
@ -325,9 +323,9 @@ PSRETURN CGame::ReallyStartGame()
if (g_GUI && g_GUI->GetPageCount())
{
shared_ptr<ScriptInterface> scriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface();
JSContext* cx = scriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue global(cx, scriptInterface->GetGlobalObject());
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue global(rq.cx, scriptInterface->GetGlobalObject());
if (scriptInterface->HasProperty(global, "reallyStartGame"))
scriptInterface->CallFunctionVoid(global, "reallyStartGame");
}

View File

@ -184,15 +184,14 @@ retry:
void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task)
{
const ScriptInterface& scriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface());
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::AutoValueVector paramData(cx);
JS::AutoValueVector paramData(rq.cx);
paramData.append(JS::NumberValue(percent));
JS::RootedValue valPendingTask(cx);
scriptInterface.ToJSVal(cx, &valPendingTask, pending_task);
JS::RootedValue valPendingTask(rq.cx);
scriptInterface.ToJSVal(rq, &valPendingTask, pending_task);
paramData.append(valPendingTask);
g_GUI->SendEventToAll(g_EventNameGameLoadProgress, paramData);
@ -517,23 +516,22 @@ void InitPsAutostart(bool networked, JS::HandleValue attrs)
{
// The GUI has not been initialized yet, so use the simulation scriptinterface for this variable
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue playerAssignments(cx);
ScriptInterface::CreateObject(cx, &playerAssignments);
JS::RootedValue playerAssignments(rq.cx);
ScriptInterface::CreateObject(rq, &playerAssignments);
if (!networked)
{
JS::RootedValue localPlayer(cx);
ScriptInterface::CreateObject(cx, &localPlayer, "player", g_Game->GetPlayerID());
JS::RootedValue localPlayer(rq.cx);
ScriptInterface::CreateObject(rq, &localPlayer, "player", g_Game->GetPlayerID());
scriptInterface.SetProperty(playerAssignments, "local", localPlayer);
}
JS::RootedValue sessionInitData(cx);
JS::RootedValue sessionInitData(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&sessionInitData,
"attribs", attrs,
"playerAssignments", playerAssignments);
@ -1061,12 +1059,11 @@ void InitGraphics(const CmdLineArgs& args, int flags, const std::vector<CStr>& i
const bool setup_gui = ((flags & INIT_NO_GUI) == 0);
// We only want to display the splash screen at startup
shared_ptr<ScriptInterface> scriptInterface = g_GUI->GetScriptInterface();
JSContext* cx = scriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue data(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue data(rq.cx);
if (g_GUI)
{
ScriptInterface::CreateObject(cx, &data, "isStartup", true);
ScriptInterface::CreateObject(rq, &data, "isStartup", true);
if (!installedMods.empty())
scriptInterface->SetProperty(data, "installedMods", installedMods);
}
@ -1221,16 +1218,15 @@ bool Autostart(const CmdLineArgs& args)
g_Game = new CGame(!args.Has("autostart-disable-replay"));
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue attrs(cx);
JS::RootedValue settings(cx);
JS::RootedValue playerData(cx);
JS::RootedValue attrs(rq.cx);
JS::RootedValue settings(rq.cx);
JS::RootedValue playerData(rq.cx);
ScriptInterface::CreateObject(cx, &attrs);
ScriptInterface::CreateObject(cx, &settings);
ScriptInterface::CreateArray(cx, &playerData);
ScriptInterface::CreateObject(rq, &attrs);
ScriptInterface::CreateObject(rq, &settings);
ScriptInterface::CreateArray(rq, &playerData);
// The directory in front of the actual map name indicates which type
// of map is being loaded. Drawback of this approach is the association
@ -1245,7 +1241,7 @@ bool Autostart(const CmdLineArgs& args)
{
// Random map definition will be loaded from JSON file, so we need to parse it
std::wstring scriptPath = L"maps/" + autoStartName.FromUTF8() + L".json";
JS::RootedValue scriptData(cx);
JS::RootedValue scriptData(rq.cx);
scriptInterface.ReadJSONFile(scriptPath, &scriptData);
if (!scriptData.isUndefined() && scriptInterface.GetProperty(scriptData, "settings", &settings))
{
@ -1282,11 +1278,11 @@ bool Autostart(const CmdLineArgs& args)
// Set up player data
for (size_t i = 0; i < numPlayers; ++i)
{
JS::RootedValue player(cx);
JS::RootedValue player(rq.cx);
// We could load player_defaults.json here, but that would complicate the logic
// even more and autostart is only intended for developers anyway
ScriptInterface::CreateObject(cx, &player, "Civ", "athen");
ScriptInterface::CreateObject(rq, &player, "Civ", "athen");
scriptInterface.SetPropertyInt(playerData, i, player);
}
@ -1348,7 +1344,7 @@ bool Autostart(const CmdLineArgs& args)
// attrs.settings = { PlayerData: [ { AI: ... }, ... ] }
// or = { PlayerData: [ null, { AI: ... }, ... ] } when gaia set
int offset = 1;
JS::RootedValue player(cx);
JS::RootedValue player(rq.cx);
if (scriptInterface.GetPropertyInt(playerData, 0, &player) && player.isNull())
offset = 0;
@ -1361,7 +1357,7 @@ bool Autostart(const CmdLineArgs& args)
int playerID = civArgs[i].BeforeFirst(":").ToInt();
// Instead of overwriting existing player data, modify the array
JS::RootedValue player(cx);
JS::RootedValue player(rq.cx);
if (!scriptInterface.GetPropertyInt(playerData, playerID-offset, &player) || player.isUndefined())
{
if (mapDirectory == L"skirmishes")
@ -1370,7 +1366,7 @@ bool Autostart(const CmdLineArgs& args)
LOGWARNING("Autostart: Invalid player %d in autostart-team option", playerID);
continue;
}
ScriptInterface::CreateObject(cx, &player);
ScriptInterface::CreateObject(rq, &player);
}
int teamID = civArgs[i].AfterFirst(":").ToInt() - 1;
@ -1392,7 +1388,7 @@ bool Autostart(const CmdLineArgs& args)
int playerID = aiArgs[i].BeforeFirst(":").ToInt();
// Instead of overwriting existing player data, modify the array
JS::RootedValue player(cx);
JS::RootedValue player(rq.cx);
if (!scriptInterface.GetPropertyInt(playerData, playerID-offset, &player) || player.isUndefined())
{
if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes")
@ -1401,7 +1397,7 @@ bool Autostart(const CmdLineArgs& args)
LOGWARNING("Autostart: Invalid player %d in autostart-ai option", playerID);
continue;
}
ScriptInterface::CreateObject(cx, &player);
ScriptInterface::CreateObject(rq, &player);
}
scriptInterface.SetProperty(player, "AI", aiArgs[i].AfterFirst(":"));
@ -1419,7 +1415,7 @@ bool Autostart(const CmdLineArgs& args)
int playerID = civArgs[i].BeforeFirst(":").ToInt();
// Instead of overwriting existing player data, modify the array
JS::RootedValue player(cx);
JS::RootedValue player(rq.cx);
if (!scriptInterface.GetPropertyInt(playerData, playerID-offset, &player) || player.isUndefined())
{
if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes")
@ -1428,7 +1424,7 @@ bool Autostart(const CmdLineArgs& args)
LOGWARNING("Autostart: Invalid player %d in autostart-aidiff option", playerID);
continue;
}
ScriptInterface::CreateObject(cx, &player);
ScriptInterface::CreateObject(rq, &player);
}
scriptInterface.SetProperty(player, "AIDiff", civArgs[i].AfterFirst(":").ToInt());
@ -1446,7 +1442,7 @@ bool Autostart(const CmdLineArgs& args)
int playerID = civArgs[i].BeforeFirst(":").ToInt();
// Instead of overwriting existing player data, modify the array
JS::RootedValue player(cx);
JS::RootedValue player(rq.cx);
if (!scriptInterface.GetPropertyInt(playerData, playerID-offset, &player) || player.isUndefined())
{
if (mapDirectory == L"skirmishes")
@ -1455,7 +1451,7 @@ bool Autostart(const CmdLineArgs& args)
LOGWARNING("Autostart: Invalid player %d in autostart-civ option", playerID);
continue;
}
ScriptInterface::CreateObject(cx, &player);
ScriptInterface::CreateObject(rq, &player);
}
scriptInterface.SetProperty(player, "Civ", civArgs[i].AfterFirst(":"));
@ -1479,12 +1475,12 @@ bool Autostart(const CmdLineArgs& args)
// Add additional scripts to the TriggerScripts property
std::vector<CStrW> triggerScriptsVector;
JS::RootedValue triggerScripts(cx);
JS::RootedValue triggerScripts(rq.cx);
if (scriptInterface.HasProperty(settings, "TriggerScripts"))
{
scriptInterface.GetProperty(settings, "TriggerScripts", &triggerScripts);
FromJSVal_vector(cx, triggerScripts, triggerScriptsVector);
FromJSVal_vector(rq, triggerScripts, triggerScriptsVector);
}
if (!CRenderer::IsInitialised())
@ -1504,9 +1500,9 @@ bool Autostart(const CmdLineArgs& args)
for (const CStr& victory : victoryConditions)
{
JS::RootedValue scriptData(cx);
JS::RootedValue data(cx);
JS::RootedValue victoryScripts(cx);
JS::RootedValue scriptData(rq.cx);
JS::RootedValue data(rq.cx);
JS::RootedValue victoryScripts(rq.cx);
CStrW scriptPath = L"simulation/data/settings/victory_conditions/" + victory.FromUTF8() + L".json";
scriptInterface.ReadJSONFile(scriptPath, &scriptData);
@ -1514,7 +1510,7 @@ bool Autostart(const CmdLineArgs& args)
&& scriptInterface.GetProperty(data, "Scripts", &victoryScripts) && !victoryScripts.isUndefined())
{
std::vector<CStrW> victoryScriptsVector;
FromJSVal_vector(cx, victoryScripts, victoryScriptsVector);
FromJSVal_vector(rq, victoryScripts, victoryScriptsVector);
triggerScriptsVector.insert(triggerScriptsVector.end(), victoryScriptsVector.begin(), victoryScriptsVector.end());
}
else
@ -1524,7 +1520,7 @@ bool Autostart(const CmdLineArgs& args)
}
}
ToJSVal_vector(cx, &triggerScripts, triggerScriptsVector);
ToJSVal_vector(rq, &triggerScripts, triggerScriptsVector);
scriptInterface.SetProperty(settings, "TriggerScripts", triggerScripts);
int wonderDuration = 10;
@ -1606,9 +1602,8 @@ bool AutostartVisualReplay(const std::string& replayFile)
g_Game->StartVisualReplay(replayFile);
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue attrs(cx, g_Game->GetSimulation2()->GetInitAttributes());
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue attrs(rq.cx, g_Game->GetSimulation2()->GetInitAttributes());
InitPsAutostart(false, attrs);
@ -1618,10 +1613,9 @@ bool AutostartVisualReplay(const std::string& replayFile)
void CancelLoad(const CStrW& message)
{
shared_ptr<ScriptInterface> pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface();
JSContext* cx = pScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pScriptInterface);
JS::RootedValue global(cx, pScriptInterface->GetGlobalObject());
JS::RootedValue global(rq.cx, pScriptInterface->GetGlobalObject());
LDR_Cancel();

View File

@ -78,10 +78,9 @@ static void ReportGLLimits(const ScriptInterface& scriptInterface, JS::HandleVal
#if ARCH_X86_X64
void ConvertCaches(const ScriptInterface& scriptInterface, x86_x64::IdxCache idxCache, JS::MutableHandleValue ret)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
ScriptInterface::CreateArray(cx, ret);
ScriptInterface::CreateArray(rq, ret);
for (size_t idxLevel = 0; idxLevel < x86_x64::Cache::maxLevels; ++idxLevel)
{
@ -89,10 +88,10 @@ void ConvertCaches(const ScriptInterface& scriptInterface, x86_x64::IdxCache idx
if (pcache->m_Type == x86_x64::Cache::kNull || pcache->m_NumEntries == 0)
continue;
JS::RootedValue cache(cx);
JS::RootedValue cache(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&cache,
"type", static_cast<u32>(pcache->m_Type),
"level", static_cast<u32>(pcache->m_Level),
@ -107,10 +106,9 @@ void ConvertCaches(const ScriptInterface& scriptInterface, x86_x64::IdxCache idx
void ConvertTLBs(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
ScriptInterface::CreateArray(cx, ret);
ScriptInterface::CreateArray(rq, ret);
for(size_t i = 0; ; i++)
{
@ -118,10 +116,10 @@ void ConvertTLBs(const ScriptInterface& scriptInterface, JS::MutableHandleValue
if (!ptlb)
break;
JS::RootedValue tlb(cx);
JS::RootedValue tlb(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&tlb,
"type", static_cast<u32>(ptlb->m_Type),
"level", static_cast<u32>(ptlb->m_Level),
@ -144,8 +142,8 @@ void RunHardwareDetection()
TIMER(L"RunHardwareDetection");
ScriptInterface scriptInterface("Engine", "HWDetect", g_ScriptRuntime);
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JSI_Debug::RegisterScriptFunctions(scriptInterface); // Engine.DisplayErrorDialog
JSI_ConfigDB::RegisterScriptFunctions(scriptInterface);
@ -169,8 +167,8 @@ void RunHardwareDetection()
// (We'll use this same data for the opt-in online reporting system, so it
// includes some fields that aren't directly useful for the hwdetect script)
JS::RootedValue settings(cx);
ScriptInterface::CreateObject(cx, &settings);
JS::RootedValue settings(rq.cx);
ScriptInterface::CreateObject(rq, &settings);
scriptInterface.SetProperty(settings, "os_unix", OS_UNIX);
scriptInterface.SetProperty(settings, "os_bsd", OS_BSD);
@ -263,7 +261,7 @@ void RunHardwareDetection()
scriptInterface.SetProperty(settings, "x86_caps[2]", caps2);
scriptInterface.SetProperty(settings, "x86_caps[3]", caps3);
JS::RootedValue tmpVal(cx);
JS::RootedValue tmpVal(rq.cx);
ConvertCaches(scriptInterface, x86_x64::L1I, &tmpVal);
scriptInterface.SetProperty(settings, "x86_icaches", tmpVal);
ConvertCaches(scriptInterface, x86_x64::L1D, &tmpVal);
@ -285,7 +283,7 @@ void RunHardwareDetection()
scriptInterface.StringifyJSON(&settings, true));
// Run the detection script:
JS::RootedValue global(cx, scriptInterface.GetGlobalObject());
JS::RootedValue global(rq.cx, scriptInterface.GetGlobalObject());
scriptInterface.CallFunctionVoid(global, "RunHardwareDetection", settings);
}

View File

@ -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
@ -39,9 +39,8 @@ CmdLineArgs g_args;
JS::Value Mod::GetAvailableMods(const ScriptInterface& scriptInterface)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
ScriptInterface::Request rq(scriptInterface);
JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx));
const Paths paths(g_args);
@ -68,12 +67,12 @@ JS::Value Mod::GetAvailableMods(const ScriptInterface& scriptInterface)
if (modinfo.Load(vfs, L"mod.json", false) != PSRETURN_OK)
continue;
JS::RootedValue json(cx);
JS::RootedValue json(rq.cx);
if (!scriptInterface.ParseJSON(modinfo.GetAsString(), &json))
continue;
// Valid mod, add it to our structure
JS_SetProperty(cx, obj, utf8_from_wstring(iter->string()).c_str(), json);
JS_SetProperty(rq.cx, obj, utf8_from_wstring(iter->string()).c_str(), json);
}
GetDirectoryEntries(modUserPath, NULL, &modDirsUser);
@ -94,12 +93,12 @@ JS::Value Mod::GetAvailableMods(const ScriptInterface& scriptInterface)
if (modinfo.Load(vfs, L"mod.json", false) != PSRETURN_OK)
continue;
JS::RootedValue json(cx);
JS::RootedValue json(rq.cx);
if (!scriptInterface.ParseJSON(modinfo.GetAsString(), &json))
continue;
// Valid mod, add it to our structure
JS_SetProperty(cx, obj, utf8_from_wstring(iter->string()).c_str(), json);
JS_SetProperty(rq.cx, obj, utf8_from_wstring(iter->string()).c_str(), json);
}
return JS::ObjectValue(*obj);
@ -108,10 +107,9 @@ JS::Value Mod::GetAvailableMods(const ScriptInterface& scriptInterface)
void Mod::CacheEnabledModVersions(const shared_ptr<ScriptRuntime>& scriptRuntime)
{
ScriptInterface scriptInterface("Engine", "CacheEnabledModVersions", scriptRuntime);
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue availableMods(cx, GetAvailableMods(scriptInterface));
JS::RootedValue availableMods(rq.cx, GetAvailableMods(scriptInterface));
g_LoadedModVersions.clear();
@ -122,7 +120,7 @@ void Mod::CacheEnabledModVersions(const shared_ptr<ScriptRuntime>& scriptRuntime
continue;
CStr version;
JS::RootedValue modData(cx);
JS::RootedValue modData(rq.cx);
if (scriptInterface.GetProperty(availableMods, mod.c_str(), &modData))
scriptInterface.GetProperty(modData, "version", version);
@ -132,23 +130,21 @@ void Mod::CacheEnabledModVersions(const shared_ptr<ScriptRuntime>& scriptRuntime
JS::Value Mod::GetLoadedModsWithVersions(const ScriptInterface& scriptInterface)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue returnValue(cx);
scriptInterface.ToJSVal(cx, &returnValue, g_LoadedModVersions);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue returnValue(rq.cx);
scriptInterface.ToJSVal(rq, &returnValue, g_LoadedModVersions);
return returnValue;
}
JS::Value Mod::GetEngineInfo(const ScriptInterface& scriptInterface)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue mods(cx, Mod::GetLoadedModsWithVersions(scriptInterface));
JS::RootedValue metainfo(cx);
JS::RootedValue mods(rq.cx, Mod::GetLoadedModsWithVersions(scriptInterface));
JS::RootedValue metainfo(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&metainfo,
"engine_version", engine_version,
"mods", mods);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2018 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
@ -61,19 +61,22 @@ CModInstaller::ModInstallationResult CModInstaller::Install(
return FAIL_ON_MOD_LOAD;
// Extract the name of the mod
ScriptInterface scriptInterface("Engine", "ModInstaller", scriptRuntime);
JSContext* cx = scriptInterface.GetContext();
JS::RootedValue json_val(cx);
if (!scriptInterface.ParseJSON(modinfo.GetAsString(), &json_val))
return FAIL_ON_PARSE_JSON;
JS::RootedObject json_obj(cx, json_val.toObjectOrNull());
JS::RootedValue name_val(cx);
if (!JS_GetProperty(cx, json_obj, "name", &name_val))
return FAIL_ON_EXTRACT_NAME;
CStr modName;
ScriptInterface::FromJSVal(cx, name_val, modName);
if (modName.empty())
return FAIL_ON_EXTRACT_NAME;
{
ScriptInterface scriptInterface("Engine", "ModInstaller", scriptRuntime);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue json_val(rq.cx);
if (!scriptInterface.ParseJSON(modinfo.GetAsString(), &json_val))
return FAIL_ON_PARSE_JSON;
JS::RootedObject json_obj(rq.cx, json_val.toObjectOrNull());
JS::RootedValue name_val(rq.cx);
if (!JS_GetProperty(rq.cx, json_obj, "name", &name_val))
return FAIL_ON_EXTRACT_NAME;
ScriptInterface::FromJSVal(rq, name_val, modName);
if (modName.empty())
return FAIL_ON_EXTRACT_NAME;
}
const OsPath modDir = m_ModsDir / modName;
const OsPath modPath = modDir / (modName + ".zip");

View File

@ -586,10 +586,9 @@ bool ModIo::VerifyDownloadedFile(std::string& err)
bool ModIo::ParseGameIdResponse(const ScriptInterface& scriptInterface, const std::string& responseData, int& id, std::string& err)
{
#define CLEANUP() id = -1;
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue gameResponse(cx);
JS::RootedValue gameResponse(rq.cx);
if (!scriptInterface.ParseJSON(responseData, &gameResponse))
FAIL("Failed to parse response as JSON.");
@ -597,35 +596,35 @@ bool ModIo::ParseGameIdResponse(const ScriptInterface& scriptInterface, const st
if (!gameResponse.isObject())
FAIL("response not an object.");
JS::RootedObject gameResponseObj(cx, gameResponse.toObjectOrNull());
JS::RootedValue dataVal(cx);
if (!JS_GetProperty(cx, gameResponseObj, "data", &dataVal))
JS::RootedObject gameResponseObj(rq.cx, gameResponse.toObjectOrNull());
JS::RootedValue dataVal(rq.cx);
if (!JS_GetProperty(rq.cx, gameResponseObj, "data", &dataVal))
FAIL("data property not in response.");
// [{"id": 42, ...}, ...]
if (!dataVal.isObject())
FAIL("data property not an object.");
JS::RootedObject data(cx, dataVal.toObjectOrNull());
JS::RootedObject data(rq.cx, dataVal.toObjectOrNull());
u32 length;
bool isArray;
if (!JS_IsArrayObject(cx, data, &isArray) || !isArray || !JS_GetArrayLength(cx, data, &length) || !length)
if (!JS_IsArrayObject(rq.cx, data, &isArray) || !isArray || !JS_GetArrayLength(rq.cx, data, &length) || !length)
FAIL("data property not an array with at least one element.");
// {"id": 42, ...}
JS::RootedValue first(cx);
if (!JS_GetElement(cx, data, 0, &first))
JS::RootedValue first(rq.cx);
if (!JS_GetElement(rq.cx, data, 0, &first))
FAIL("Couldn't get first element.");
if (!first.isObject())
FAIL("First element not an object.");
JS::RootedObject firstObj(cx, &first.toObject());
JS::RootedObject firstObj(rq.cx, &first.toObject());
bool hasIdProperty;
if (!JS_HasProperty(cx, firstObj, "id", &hasIdProperty) || !hasIdProperty)
if (!JS_HasProperty(rq.cx, firstObj, "id", &hasIdProperty) || !hasIdProperty)
FAIL("No id property in first element.");
JS::RootedValue idProperty(cx);
ENSURE(JS_GetProperty(cx, firstObj, "id", &idProperty));
JS::RootedValue idProperty(rq.cx);
ENSURE(JS_GetProperty(rq.cx, firstObj, "id", &idProperty));
// Make sure the property is not set to something that could be converted to a bogus value
// TODO: We should be able to convert JS::Values to C++ variables in a way that actually
@ -634,7 +633,7 @@ bool ModIo::ParseGameIdResponse(const ScriptInterface& scriptInterface, const st
FAIL("id property not a number.");
id = -1;
if (!ScriptInterface::FromJSVal(cx, idProperty, id) || id <= 0)
if (!ScriptInterface::FromJSVal(rq, idProperty, id) || id <= 0)
FAIL("Invalid id.");
return true;
@ -658,10 +657,9 @@ bool ModIo::ParseModsResponse(const ScriptInterface& scriptInterface, const std:
// Make sure we don't end up passing partial results back
#define CLEANUP() modData.clear();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue modResponse(cx);
JS::RootedValue modResponse(rq.cx);
if (!scriptInterface.ParseJSON(responseData, &modResponse))
FAIL("Failed to parse response as JSON.");
@ -669,19 +667,19 @@ bool ModIo::ParseModsResponse(const ScriptInterface& scriptInterface, const std:
if (!modResponse.isObject())
FAIL("response not an object.");
JS::RootedObject modResponseObj(cx, modResponse.toObjectOrNull());
JS::RootedValue dataVal(cx);
if (!JS_GetProperty(cx, modResponseObj, "data", &dataVal))
JS::RootedObject modResponseObj(rq.cx, modResponse.toObjectOrNull());
JS::RootedValue dataVal(rq.cx);
if (!JS_GetProperty(rq.cx, modResponseObj, "data", &dataVal))
FAIL("data property not in response.");
// [modobj1, modobj2, ... ]
if (!dataVal.isObject())
FAIL("data property not an object.");
JS::RootedObject rData(cx, dataVal.toObjectOrNull());
JS::RootedObject rData(rq.cx, dataVal.toObjectOrNull());
u32 length;
bool isArray;
if (!JS_IsArrayObject(cx, rData, &isArray) || !isArray || !JS_GetArrayLength(cx, rData, &length) || !length)
if (!JS_IsArrayObject(rq.cx, rData, &isArray) || !isArray || !JS_GetArrayLength(rq.cx, rData, &length) || !length)
FAIL("data property not an array with at least one element.");
modData.clear();
@ -698,8 +696,8 @@ bool ModIo::ParseModsResponse(const ScriptInterface& scriptInterface, const std:
{
modData.emplace_back();
ModIoModData& data = modData.back();
JS::RootedValue el(cx);
if (!JS_GetElement(cx, rData, i, &el) || !el.isObject())
JS::RootedValue el(rq.cx);
if (!JS_GetElement(rq.cx, rData, i, &el) || !el.isObject())
INVALIDATE_DATA_AND_CONTINUE("Failed to get array element object.")
bool ok = true;
@ -708,7 +706,7 @@ bool ModIo::ParseModsResponse(const ScriptInterface& scriptInterface, const std:
for (const std::string& prop : { __VA_ARGS__ }) \
{ \
std::string val; \
if (!ScriptInterface::FromJSProperty(cx, obj, prop.c_str(), val, true)) \
if (!ScriptInterface::FromJSProperty(rq, obj, prop.c_str(), val, true)) \
{ \
ok = false; \
copyStringError = "Failed to get " + prop + " from " + #obj + "."; \
@ -723,9 +721,9 @@ bool ModIo::ParseModsResponse(const ScriptInterface& scriptInterface, const std:
COPY_STRINGS_ELSE_CONTINUE("", el, "name", "name_id", "summary")
// Now copy over the modfile part, but without the pointless substructure
JS::RootedObject elObj(cx, el.toObjectOrNull());
JS::RootedValue modFile(cx);
if (!JS_GetProperty(cx, elObj, "modfile", &modFile))
JS::RootedObject elObj(rq.cx, el.toObjectOrNull());
JS::RootedValue modFile(rq.cx);
if (!JS_GetProperty(rq.cx, elObj, "modfile", &modFile))
INVALIDATE_DATA_AND_CONTINUE("Failed to get modfile data.");
if (!modFile.isObject())
@ -733,36 +731,36 @@ bool ModIo::ParseModsResponse(const ScriptInterface& scriptInterface, const std:
COPY_STRINGS_ELSE_CONTINUE("", modFile, "version", "filesize");
JS::RootedObject modFileObj(cx, modFile.toObjectOrNull());
JS::RootedValue filehash(cx);
if (!JS_GetProperty(cx, modFileObj, "filehash", &filehash))
JS::RootedObject modFileObj(rq.cx, modFile.toObjectOrNull());
JS::RootedValue filehash(rq.cx);
if (!JS_GetProperty(rq.cx, modFileObj, "filehash", &filehash))
INVALIDATE_DATA_AND_CONTINUE("Failed to get filehash data.");
COPY_STRINGS_ELSE_CONTINUE("filehash_", filehash, "md5");
JS::RootedValue download(cx);
if (!JS_GetProperty(cx, modFileObj, "download", &download))
JS::RootedValue download(rq.cx);
if (!JS_GetProperty(rq.cx, modFileObj, "download", &download))
INVALIDATE_DATA_AND_CONTINUE("Failed to get download data.");
COPY_STRINGS_ELSE_CONTINUE("", download, "binary_url");
// Parse metadata_blob (sig+deps)
std::string metadata_blob;
if (!ScriptInterface::FromJSProperty(cx, modFile, "metadata_blob", metadata_blob, true))
if (!ScriptInterface::FromJSProperty(rq, modFile, "metadata_blob", metadata_blob, true))
INVALIDATE_DATA_AND_CONTINUE("Failed to get metadata_blob from modFile.");
JS::RootedValue metadata(cx);
JS::RootedValue metadata(rq.cx);
if (!scriptInterface.ParseJSON(metadata_blob, &metadata))
INVALIDATE_DATA_AND_CONTINUE("Failed to parse metadata_blob as JSON.");
if (!metadata.isObject())
INVALIDATE_DATA_AND_CONTINUE("metadata_blob is not decoded as an object.");
if (!ScriptInterface::FromJSProperty(cx, metadata, "dependencies", data.dependencies, true))
if (!ScriptInterface::FromJSProperty(rq, metadata, "dependencies", data.dependencies, true))
INVALIDATE_DATA_AND_CONTINUE("Failed to get dependencies from metadata_blob.");
std::vector<std::string> minisigs;
if (!ScriptInterface::FromJSProperty(cx, metadata, "minisigs", minisigs, true))
if (!ScriptInterface::FromJSProperty(rq, metadata, "minisigs", minisigs, true))
INVALIDATE_DATA_AND_CONTINUE("Failed to get minisigs from metadata_blob.");
// Check we did find a valid matching signature.

View File

@ -502,12 +502,11 @@ namespace
void operator() (AbstractProfileTable* table)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
JS::RootedValue t(cx);
JS::RootedValue t(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&t,
"cols", DumpCols(table),
"data", DumpRows(table));
@ -529,24 +528,23 @@ namespace
JS::Value DumpRows(AbstractProfileTable* table)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
JS::RootedValue data(cx);
ScriptInterface::CreateObject(cx, &data);
JS::RootedValue data(rq.cx);
ScriptInterface::CreateObject(rq, &data);
const std::vector<ProfileColumn>& columns = table->GetColumns();
for (size_t r = 0; r < table->GetNumberRows(); ++r)
{
JS::RootedValue row(cx);
ScriptInterface::CreateArray(cx, &row);
JS::RootedValue row(rq.cx);
ScriptInterface::CreateArray(rq, &row);
m_ScriptInterface.SetProperty(data, table->GetCellText(r, 0).c_str(), row);
if (table->GetChild(r))
{
JS::RootedValue childRows(cx, DumpRows(table->GetChild(r)));
JS::RootedValue childRows(rq.cx, DumpRows(table->GetChild(r)));
m_ScriptInterface.SetPropertyInt(row, 0, childRows);
}

View File

@ -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
@ -64,15 +64,14 @@ CReplayLogger::~CReplayLogger()
void CReplayLogger::StartGame(JS::MutableHandleValue attribs)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
// Add timestamp, since the file-modification-date can change
m_ScriptInterface.SetProperty(attribs, "timestamp", (double)std::time(nullptr));
// Add engine version and currently loaded mods for sanity checks when replaying
m_ScriptInterface.SetProperty(attribs, "engine_version", engine_version);
JS::RootedValue mods(cx, Mod::GetLoadedModsWithVersions(m_ScriptInterface));
JS::RootedValue mods(rq.cx, Mod::GetLoadedModsWithVersions(m_ScriptInterface));
m_ScriptInterface.SetProperty(attribs, "mods", mods);
m_Directory = createDateIndexSubdirectory(VisualReplay::GetDirectoryPath());
@ -84,8 +83,7 @@ void CReplayLogger::StartGame(JS::MutableHandleValue attribs)
void CReplayLogger::Turn(u32 n, u32 turnLength, std::vector<SimulationCommand>& commands)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
*m_Stream << "turn " << n << " " << turnLength << "\n";
@ -114,11 +112,10 @@ void CReplayLogger::SaveMetadata(const CSimulation2& simulation)
}
ScriptInterface& scriptInterface = simulation.GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue arg(cx);
JS::RootedValue metadata(cx);
JS::RootedValue arg(rq.cx);
JS::RootedValue metadata(rq.cx);
cmpGuiInterface->ScriptCall(INVALID_PLAYER, L"GetReplayMetadata", arg, &metadata);
const OsPath fileName = g_Game->GetReplayLogger().GetDirectory() / L"metadata.json";
@ -165,15 +162,14 @@ CStr CReplayPlayer::ModListToString(const std::vector<std::vector<CStr>>& list)
void CReplayPlayer::CheckReplayMods(const ScriptInterface& scriptInterface, JS::HandleValue attribs) const
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
std::vector<std::vector<CStr>> replayMods;
scriptInterface.GetProperty(attribs, "mods", replayMods);
std::vector<std::vector<CStr>> enabledMods;
JS::RootedValue enabledModsJS(cx, Mod::GetLoadedModsWithVersions(scriptInterface));
scriptInterface.FromJSVal(cx, enabledModsJS, enabledMods);
JS::RootedValue enabledModsJS(rq.cx, Mod::GetLoadedModsWithVersions(scriptInterface));
scriptInterface.FromJSVal(rq, enabledModsJS, enabledMods);
CStr warn;
if (replayMods.size() != enabledMods.size())
@ -233,8 +229,7 @@ void CReplayPlayer::Replay(const bool serializationtest, const int rejointesttur
u32 turnLength = 0;
{
JSContext* cx = g_Game->GetSimulation2()->GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(g_Game->GetSimulation2()->GetScriptInterface());
std::string type;
while ((*m_Stream >> type).good())
@ -243,7 +238,7 @@ void CReplayPlayer::Replay(const bool serializationtest, const int rejointesttur
{
std::string line;
std::getline(*m_Stream, line);
JS::RootedValue attribs(cx);
JS::RootedValue attribs(rq.cx);
ENSURE(g_Game->GetSimulation2()->GetScriptInterface().ParseJSON(line, &attribs));
CheckReplayMods(g_Game->GetSimulation2()->GetScriptInterface(), attribs);
@ -268,10 +263,10 @@ void CReplayPlayer::Replay(const bool serializationtest, const int rejointesttur
std::string line;
std::getline(*m_Stream, line);
JS::RootedValue data(cx);
JS::RootedValue data(rq.cx);
g_Game->GetSimulation2()->GetScriptInterface().ParseJSON(line, &data);
g_Game->GetSimulation2()->GetScriptInterface().FreezeObject(data, true);
commands.emplace_back(SimulationCommand(player, cx, data));
commands.emplace_back(SimulationCommand(player, rq.cx, data));
}
else if (type == "hash" || type == "hash-quick")
{

View File

@ -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
@ -52,8 +52,7 @@ Status SavedGames::SavePrefix(const CStrW& prefix, const CStrW& description, CSi
Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const shared_ptr<ScriptInterface::StructuredClone>& guiMetadataClone)
{
JSContext* cx = simulation.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(simulation.GetScriptInterface());
// Determine the filename to save under
const VfsPath basenameFormat(L"saves/" + name);
@ -78,13 +77,13 @@ Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation
if (!simulation.SerializeState(simStateStream))
WARN_RETURN(ERR::FAIL);
JS::RootedValue initAttributes(cx, simulation.GetInitAttributes());
JS::RootedValue mods(cx, Mod::GetLoadedModsWithVersions(simulation.GetScriptInterface()));
JS::RootedValue initAttributes(rq.cx, simulation.GetInitAttributes());
JS::RootedValue mods(rq.cx, Mod::GetLoadedModsWithVersions(simulation.GetScriptInterface()));
JS::RootedValue metadata(cx);
JS::RootedValue metadata(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&metadata,
"engine_version", engine_version,
"time", static_cast<double>(now),
@ -92,17 +91,17 @@ Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation
"mods", mods,
"initAttributes", initAttributes);
JS::RootedValue guiMetadata(cx);
JS::RootedValue guiMetadata(rq.cx);
simulation.GetScriptInterface().ReadStructuredClone(guiMetadataClone, &guiMetadata);
// get some camera data
const CVector3D cameraPosition = g_Game->GetView()->GetCameraPosition();
const CVector3D cameraRotation = g_Game->GetView()->GetCameraRotation();
JS::RootedValue cameraMetadata(cx);
JS::RootedValue cameraMetadata(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&cameraMetadata,
"PosX", cameraPosition.X,
"PosY", cameraPosition.Y,
@ -174,9 +173,6 @@ public:
void ReadEntry(const VfsPath& pathname, const CFileInfo& fileInfo, PIArchiveFile archiveFile)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
if (pathname == L"metadata.json")
{
std::string buffer;
@ -230,11 +226,10 @@ Status SavedGames::Load(const std::wstring& name, const ScriptInterface& scriptI
JS::Value SavedGames::GetSavedGames(const ScriptInterface& scriptInterface)
{
TIMER(L"GetSavedGames");
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue games(cx);
ScriptInterface::CreateArray(cx, &games);
JS::RootedValue games(rq.cx);
ScriptInterface::CreateArray(rq, &games);
Status err;
@ -267,11 +262,11 @@ JS::Value SavedGames::GetSavedGames(const ScriptInterface& scriptInterface)
DEBUG_WARN_ERR(err);
continue; // skip this file
}
JS::RootedValue metadata(cx, loader.GetMetadata());
JS::RootedValue metadata(rq.cx, loader.GetMetadata());
JS::RootedValue game(cx);
JS::RootedValue game(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&game,
"id", pathnames[i].Basename(),
"metadata", metadata);

View File

@ -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
@ -71,9 +71,6 @@ bool VisualReplay::StartVisualReplay(const OsPath& directory)
bool VisualReplay::ReadCacheFile(const ScriptInterface& scriptInterface, JS::MutableHandleObject cachedReplaysObject)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
if (!FileExists(GetCacheFilePath()))
return false;
@ -81,12 +78,14 @@ bool VisualReplay::ReadCacheFile(const ScriptInterface& scriptInterface, JS::Mut
CStr cacheStr((std::istreambuf_iterator<char>(cacheStream)), std::istreambuf_iterator<char>());
cacheStream.close();
JS::RootedValue cachedReplays(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue cachedReplays(rq.cx);
if (scriptInterface.ParseJSON(cacheStr, &cachedReplays))
{
cachedReplaysObject.set(&cachedReplays.toObject());
bool isArray;
if (JS_IsArrayObject(cx, cachedReplaysObject, &isArray) && isArray)
if (JS_IsArrayObject(rq.cx, cachedReplaysObject, &isArray) && isArray)
return true;
}
@ -97,10 +96,9 @@ bool VisualReplay::ReadCacheFile(const ScriptInterface& scriptInterface, JS::Mut
void VisualReplay::StoreCacheFile(const ScriptInterface& scriptInterface, JS::HandleObject replays)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue replaysRooted(cx, JS::ObjectValue(*replays));
JS::RootedValue replaysRooted(rq.cx, JS::ObjectValue(*replays));
std::ofstream cacheStream(OsString(GetTempCacheFilePath()).c_str(), std::ofstream::out | std::ofstream::trunc);
cacheStream << scriptInterface.StringifyJSON(&replaysRooted);
cacheStream.close();
@ -113,26 +111,25 @@ void VisualReplay::StoreCacheFile(const ScriptInterface& scriptInterface, JS::Ha
JS::HandleObject VisualReplay::ReloadReplayCache(const ScriptInterface& scriptInterface, bool compareFiles)
{
TIMER(L"ReloadReplayCache");
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
// Maps the filename onto the index and size
typedef std::map<OsPath, std::pair<u32, off_t>> replayCacheMap;
replayCacheMap fileList;
JS::RootedObject cachedReplaysObject(cx);
JS::RootedObject cachedReplaysObject(rq.cx);
if (ReadCacheFile(scriptInterface, &cachedReplaysObject))
{
// Create list of files included in the cache
u32 cacheLength = 0;
JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength);
JS_GetArrayLength(rq.cx, cachedReplaysObject, &cacheLength);
for (u32 j = 0; j < cacheLength; ++j)
{
JS::RootedValue replay(cx);
JS_GetElement(cx, cachedReplaysObject, j, &replay);
JS::RootedValue replay(rq.cx);
JS_GetElement(rq.cx, cachedReplaysObject, j, &replay);
JS::RootedValue file(cx);
JS::RootedValue file(rq.cx);
OsPath fileName;
double fileSize;
scriptInterface.GetProperty(replay, "directory", fileName);
@ -142,7 +139,7 @@ JS::HandleObject VisualReplay::ReloadReplayCache(const ScriptInterface& scriptIn
}
}
JS::RootedObject replays(cx, JS_NewArrayObject(cx, 0));
JS::RootedObject replays(rq.cx, JS_NewArrayObject(rq.cx, 0));
DirectoryNames directories;
if (GetDirectoryEntries(GetDirectoryPath(), nullptr, &directories) != INFO::OK)
@ -182,7 +179,7 @@ JS::HandleObject VisualReplay::ReloadReplayCache(const ScriptInterface& scriptIn
if (isNew)
{
JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, directory));
JS::RootedValue replayData(rq.cx, LoadReplayData(scriptInterface, directory));
if (replayData.isNull())
{
if (!FileExists(replayFile))
@ -191,12 +188,12 @@ JS::HandleObject VisualReplay::ReloadReplayCache(const ScriptInterface& scriptIn
GetFileInfo(replayFile, &fileInfo);
ScriptInterface::CreateObject(
cx,
rq,
&replayData,
"directory", directory.string(),
"fileSize", static_cast<double>(fileInfo.Size()));
}
JS_SetElement(cx, replays, i++, replayData);
JS_SetElement(rq.cx, replays, i++, replayData);
newReplays = true;
}
else
@ -219,9 +216,9 @@ JS::HandleObject VisualReplay::ReloadReplayCache(const ScriptInterface& scriptIn
if (!copyFromOldCache.empty())
for (u32 j : copyFromOldCache)
{
JS::RootedValue replay(cx);
JS_GetElement(cx, cachedReplaysObject, j, &replay);
JS_SetElement(cx, replays, i++, replay);
JS::RootedValue replay(rq.cx);
JS_GetElement(rq.cx, cachedReplaysObject, j, &replay);
JS_SetElement(rq.cx, replays, i++, replay);
}
}
StoreCacheFile(scriptInterface, replays);
@ -231,19 +228,19 @@ JS::HandleObject VisualReplay::ReloadReplayCache(const ScriptInterface& scriptIn
JS::Value VisualReplay::GetReplays(const ScriptInterface& scriptInterface, bool compareFiles)
{
TIMER(L"GetReplays");
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedObject replays(cx, ReloadReplayCache(scriptInterface, compareFiles));
ScriptInterface::Request rq(scriptInterface);
JS::RootedObject replays(rq.cx, ReloadReplayCache(scriptInterface, compareFiles));
// Only take entries with data
JS::RootedValue replaysWithoutNullEntries(cx);
ScriptInterface::CreateArray(cx, &replaysWithoutNullEntries);
JS::RootedValue replaysWithoutNullEntries(rq.cx);
ScriptInterface::CreateArray(rq, &replaysWithoutNullEntries);
u32 replaysLength = 0;
JS_GetArrayLength(cx, replays, &replaysLength);
JS_GetArrayLength(rq.cx, replays, &replaysLength);
for (u32 j = 0, i = 0; j < replaysLength; ++j)
{
JS::RootedValue replay(cx);
JS_GetElement(cx, replays, j, &replay);
JS::RootedValue replay(rq.cx);
JS_GetElement(rq.cx, replays, j, &replay);
if (scriptInterface.HasProperty(replay, "attribs"))
scriptInterface.SetPropertyInt(replaysWithoutNullEntries, i++, replay);
}
@ -369,9 +366,8 @@ JS::Value VisualReplay::LoadReplayData(const ScriptInterface& scriptInterface, c
// Parse header / first line
CStr header;
std::getline(*replayStream, header);
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue attribs(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue attribs(rq.cx);
if (!scriptInterface.ParseJSON(header, &attribs))
{
LOGERROR("Couldn't parse replay header of %s", replayFile.string8().c_str());
@ -404,10 +400,10 @@ JS::Value VisualReplay::LoadReplayData(const ScriptInterface& scriptInterface, c
return JS::NullValue();
// Return the actual data
JS::RootedValue replayData(cx);
JS::RootedValue replayData(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&replayData,
"directory", directory.string(),
"fileSize", static_cast<double>(fileSize),
@ -430,10 +426,9 @@ bool VisualReplay::DeleteReplay(const OsPath& replayDirectory)
JS::Value VisualReplay::GetReplayAttributes(ScriptInterface::CxPrivate* pCxPrivate, const OsPath& directoryName)
{
// Create empty JS object
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue attribs(cx);
ScriptInterface::CreateObject(cx, &attribs);
ScriptInterface::Request rq(pCxPrivate);
JS::RootedValue attribs(rq.cx);
ScriptInterface::CreateObject(rq, &attribs);
// Return empty object if file doesn't exist
const OsPath replayFile = GetDirectoryPath() / directoryName / L"commands.txt";
@ -455,20 +450,19 @@ JS::Value VisualReplay::GetReplayAttributes(ScriptInterface::CxPrivate* pCxPriva
void VisualReplay::AddReplayToCache(const ScriptInterface& scriptInterface, const CStrW& directoryName)
{
TIMER(L"AddReplayToCache");
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue replayData(cx, LoadReplayData(scriptInterface, OsPath(directoryName)));
JS::RootedValue replayData(rq.cx, LoadReplayData(scriptInterface, OsPath(directoryName)));
if (replayData.isNull())
return;
JS::RootedObject cachedReplaysObject(cx);
JS::RootedObject cachedReplaysObject(rq.cx);
if (!ReadCacheFile(scriptInterface, &cachedReplaysObject))
cachedReplaysObject = JS_NewArrayObject(cx, 0);
cachedReplaysObject = JS_NewArrayObject(rq.cx, 0);
u32 cacheLength = 0;
JS_GetArrayLength(cx, cachedReplaysObject, &cacheLength);
JS_SetElement(cx, cachedReplaysObject, cacheLength, replayData);
JS_GetArrayLength(rq.cx, cachedReplaysObject, &cacheLength);
JS_SetElement(rq.cx, cachedReplaysObject, cacheLength, replayData);
StoreCacheFile(scriptInterface, cachedReplaysObject);
}
@ -491,9 +485,8 @@ JS::Value VisualReplay::GetReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate
if (!HasReplayMetadata(directoryName))
return JS::NullValue();
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue metadata(cx);
ScriptInterface::Request rq(pCxPrivate);
JS::RootedValue metadata(rq.cx);
std::ifstream* stream = new std::ifstream(OsString(GetDirectoryPath() / directoryName / L"metadata.json").c_str());
ENSURE(stream->good());

View File

@ -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
@ -48,10 +48,9 @@ void JSI_Game::StartGame(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue
// Convert from GUI script context to sim script context
CSimulation2* sim = g_Game->GetSimulation2();
JSContext* cxSim = sim->GetScriptInterface().GetContext();
JSAutoRequest rqSim(cxSim);
ScriptInterface::Request rqSim(sim->GetScriptInterface());
JS::RootedValue gameAttribs(cxSim,
JS::RootedValue gameAttribs(rqSim.cx,
sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), attribs));
g_Game->SetPlayerID(playerID);
@ -101,9 +100,8 @@ bool JSI_Game::IsPaused(ScriptInterface::CxPrivate* pCxPrivate)
{
if (!g_Game)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Game is not started");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Game is not started");
return false;
}
@ -114,9 +112,8 @@ void JSI_Game::SetPaused(ScriptInterface::CxPrivate* pCxPrivate, bool pause, boo
{
if (!g_Game)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "Game is not started");
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "Game is not started");
return;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2018 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
@ -73,15 +73,14 @@ std::wstring JSI_Main::GetMatchID(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)
JS::Value JSI_Main::LoadMapSettings(ScriptInterface::CxPrivate* pCxPrivate, const VfsPath& pathname)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(pCxPrivate);
CMapSummaryReader reader;
if (reader.LoadMap(pathname) != PSRETURN_OK)
return JS::UndefinedValue();
JS::RootedValue settings(cx);
JS::RootedValue settings(rq.cx);
reader.GetMapSettings(*(pCxPrivate->pScriptInterface), &settings);
return settings;
}

View File

@ -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
@ -86,19 +86,18 @@ JS::Value JSI_ModIo::GetMods(ScriptInterface::CxPrivate* pCxPrivate)
}
ScriptInterface* scriptInterface = pCxPrivate->pScriptInterface;
JSContext* cx = scriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
const std::vector<ModIoModData>& availableMods = g_ModIo->GetMods();
JS::RootedValue mods(cx);
ScriptInterface::CreateArray(cx, &mods, availableMods.size());
JS::RootedValue mods(rq.cx);
ScriptInterface::CreateArray(rq, &mods, availableMods.size());
u32 i = 0;
for (const ModIoModData& mod : availableMods)
{
JS::RootedValue m(cx);
ScriptInterface::CreateObject(cx, &m);
JS::RootedValue m(rq.cx);
ScriptInterface::CreateObject(rq, &m);
for (const std::pair<std::string, std::string>& prop : mod.properties)
scriptInterface->SetProperty(m, prop.first.c_str(), prop.second, true);
@ -133,13 +132,12 @@ JS::Value JSI_ModIo::GetDownloadProgress(ScriptInterface::CxPrivate* pCxPrivate)
}
ScriptInterface* scriptInterface = pCxPrivate->pScriptInterface;
JSContext* cx = scriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
const DownloadProgressData& progress = g_ModIo->GetDownloadProgress();
JS::RootedValue progressData(cx);
ScriptInterface::CreateObject(cx, &progressData);
JS::RootedValue progressData(rq.cx);
ScriptInterface::CreateObject(rq, &progressData);
scriptInterface->SetProperty(progressData, "status", statusStrings.at(progress.status), true);
scriptInterface->SetProperty(progressData, "progress", progress.progress, true);
scriptInterface->SetProperty(progressData, "error", progress.error, true);

View File

@ -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
@ -78,8 +78,7 @@ JS::Value JSI_SavedGame::StartSavedGame(ScriptInterface::CxPrivate* pCxPrivate,
// The GUI calls this function from the GUI context and expects the return value in the same context.
// The game we start from here creates another context and expects data in this context.
JSContext* cxGui = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cxGui);
ScriptInterface::Request rqGui(pCxPrivate);
ENSURE(!g_NetServer);
ENSURE(!g_NetClient);
@ -87,7 +86,7 @@ JS::Value JSI_SavedGame::StartSavedGame(ScriptInterface::CxPrivate* pCxPrivate,
ENSURE(!g_Game);
// Load the saved game data from disk
JS::RootedValue guiContextMetadata(cxGui);
JS::RootedValue guiContextMetadata(rqGui.cx);
std::string savedState;
Status err = SavedGames::Load(name, *(pCxPrivate->pScriptInterface), &guiContextMetadata, savedState);
if (err < 0)
@ -97,12 +96,11 @@ JS::Value JSI_SavedGame::StartSavedGame(ScriptInterface::CxPrivate* pCxPrivate,
{
CSimulation2* sim = g_Game->GetSimulation2();
JSContext* cxGame = sim->GetScriptInterface().GetContext();
JSAutoRequest rq(cxGame);
ScriptInterface::Request rqGame(sim->GetScriptInterface());
JS::RootedValue gameContextMetadata(cxGame,
JS::RootedValue gameContextMetadata(rqGame.cx,
sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), guiContextMetadata));
JS::RootedValue gameInitAttributes(cxGame);
JS::RootedValue gameInitAttributes(rqGame.cx);
sim->GetScriptInterface().GetProperty(gameContextMetadata, "initAttributes", &gameInitAttributes);
int playerID;

View File

@ -48,15 +48,17 @@
// state held across multiple BuildDirEntListCB calls; init by BuildDirEntList.
struct BuildDirEntListState
{
JSContext* cx;
ScriptInterface* pScriptInterface;
JS::PersistentRootedObject filename_array;
int cur_idx;
BuildDirEntListState(JSContext* cx_)
: cx(cx_),
filename_array(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())),
BuildDirEntListState(ScriptInterface* scriptInterface)
: pScriptInterface(scriptInterface),
filename_array(scriptInterface->GetJSRuntime()),
cur_idx(0)
{
ScriptInterface::Request rq(pScriptInterface);
filename_array = JS_NewArrayObject(rq.cx, JS::HandleValueArray::empty());
}
};
@ -64,12 +66,12 @@ struct BuildDirEntListState
static Status BuildDirEntListCB(const VfsPath& pathname, const CFileInfo& UNUSED(fileINfo), uintptr_t cbData)
{
BuildDirEntListState* s = (BuildDirEntListState*)cbData;
JSAutoRequest rq(s->cx);
ScriptInterface::Request rq(s->pScriptInterface);
JS::RootedObject filenameArrayObj(s->cx, s->filename_array);
JS::RootedValue val(s->cx);
ScriptInterface::ToJSVal( s->cx, &val, CStrW(pathname.string()) );
JS_SetElement(s->cx, filenameArrayObj, s->cur_idx++, val);
JS::RootedObject filenameArrayObj(rq.cx, s->filename_array);
JS::RootedValue val(rq.cx);
ScriptInterface::ToJSVal(rq, &val, CStrW(pathname.string()) );
JS_SetElement(rq.cx, filenameArrayObj, s->cur_idx++, val);
return INFO::OK;
}
@ -91,11 +93,8 @@ JS::Value JSI_VFS::BuildDirEntList(ScriptInterface::CxPrivate* pCxPrivate, const
int flags = recurse ? vfs::DIR_RECURSIVE : 0;
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
// build array in the callback function
BuildDirEntListState state(cx);
BuildDirEntListState state(pCxPrivate->pScriptInterface);
vfs::ForEachFile(g_VFS, path, BuildDirEntListCB, (uintptr_t)&state, filter, flags);
return JS::ObjectValue(*state.filename_array);
@ -130,9 +129,6 @@ unsigned int JSI_VFS::GetFileSize(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)
// Return file contents in a string. Assume file is UTF-8 encoded text.
JS::Value JSI_VFS::ReadFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
CVFSFile file;
if (file.Load(g_VFS, filename) != PSRETURN_OK)
return JS::NullValue();
@ -143,18 +139,15 @@ JS::Value JSI_VFS::ReadFile(ScriptInterface::CxPrivate* pCxPrivate, const std::w
contents.Replace("\r\n", "\n");
// Decode as UTF-8
JS::RootedValue ret(cx);
ScriptInterface::ToJSVal(cx, &ret, contents.FromUTF8());
ScriptInterface::Request rq(pCxPrivate);
JS::RootedValue ret(rq.cx);
ScriptInterface::ToJSVal(rq, &ret, contents.FromUTF8());
return ret;
}
// Return file contents as an array of lines. Assume file is UTF-8 encoded text.
JS::Value JSI_VFS::ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename)
{
const ScriptInterface& scriptInterface = *pCxPrivate->pScriptInterface;
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
CVFSFile file;
if (file.Load(g_VFS, filename) != PSRETURN_OK)
return JS::NullValue();
@ -167,8 +160,11 @@ JS::Value JSI_VFS::ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const s
// split into array of strings (one per line)
std::stringstream ss(contents);
JS::RootedValue line_array(cx);
ScriptInterface::CreateArray(cx, &line_array);
const ScriptInterface& scriptInterface = *pCxPrivate->pScriptInterface;
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue line_array(rq.cx);
ScriptInterface::CreateArray(rq, &line_array);
std::string line;
int cur_line = 0;
@ -176,8 +172,8 @@ JS::Value JSI_VFS::ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const s
while (std::getline(ss, line))
{
// Decode each line as UTF-8
JS::RootedValue val(cx);
ScriptInterface::ToJSVal(cx, &val, CStr(line).FromUTF8());
JS::RootedValue val(rq.cx);
ScriptInterface::ToJSVal(rq, &val, CStr(line).FromUTF8());
scriptInterface.SetPropertyInt(line_array, cur_line++, val);
}
@ -189,22 +185,22 @@ JS::Value JSI_VFS::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const st
if (!PathRestrictionMet(pCxPrivate, validPaths, filePath))
return JS::NullValue();
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue out(cx);
pCxPrivate->pScriptInterface->ReadJSONFile(filePath, &out);
const ScriptInterface& scriptInterface = *pCxPrivate->pScriptInterface;
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue out(rq.cx);
scriptInterface.ReadJSONFile(filePath, &out);
return out;
}
void JSI_VFS::WriteJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filePath, JS::HandleValue val1)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
const ScriptInterface& scriptInterface = *pCxPrivate->pScriptInterface;
ScriptInterface::Request rq(scriptInterface);
// TODO: This is a workaround because we need to pass a MutableHandle to StringifyJSON.
JS::RootedValue val(cx, val1);
JS::RootedValue val(rq.cx, val1);
std::string str(pCxPrivate->pScriptInterface->StringifyJSON(&val, false));
std::string str(scriptInterface.StringifyJSON(&val, false));
VfsPath path(filePath);
WriteBuffer buf;
@ -227,9 +223,8 @@ bool JSI_VFS::PathRestrictionMet(ScriptInterface::CxPrivate* pCxPrivate, const s
allowedPaths += L"\"" + validPaths[i] + L"\"";
}
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS_ReportError(cx, "This part of the engine may only read from %s!", utf8_from_wstring(allowedPaths).c_str());
ScriptInterface::Request rq(pCxPrivate);
JS_ReportError(rq.cx, "This part of the engine may only read from %s!", utf8_from_wstring(allowedPaths).c_str());
return false;
}

View File

@ -298,9 +298,9 @@ void RLInterface::TryApplyMessage()
g_Game = new CGame(m_ScenarioConfig.saveReplay);
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue attrs(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue attrs(rq.cx);
scriptInterface.ParseJSON(m_ScenarioConfig.content, &attrs);
g_Game->SetPlayerID(m_ScenarioConfig.playerID);
@ -316,12 +316,12 @@ void RLInterface::TryApplyMessage()
}
else
{
JS::RootedValue initData(cx);
scriptInterface.CreateObject(cx, &initData);
JS::RootedValue initData(rq.cx);
scriptInterface.CreateObject(rq, &initData);
scriptInterface.SetProperty(initData, "attribs", attrs);
JS::RootedValue playerAssignments(cx);
scriptInterface.CreateObject(cx, &playerAssignments);
JS::RootedValue playerAssignments(rq.cx);
scriptInterface.CreateObject(rq, &playerAssignments);
scriptInterface.SetProperty(initData, "playerAssignments", playerAssignments);
g_GUI->SwitchPage(L"page_loading.xml", &scriptInterface, initData);
@ -339,14 +339,14 @@ void RLInterface::TryApplyMessage()
m_msgLock.unlock();
return;
}
const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
CLocalTurnManager* turnMgr = static_cast<CLocalTurnManager*>(g_Game->GetTurnManager());
const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
ScriptInterface::Request rq(scriptInterface);
for (Command command : msg.commands)
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue commandJSON(cx);
JS::RootedValue commandJSON(rq.cx);
scriptInterface.ParseJSON(command.json_cmd, &commandJSON);
turnMgr->PostCommand(command.playerID, commandJSON);
}
@ -376,11 +376,11 @@ void RLInterface::TryApplyMessage()
std::string RLInterface::GetGameState()
{
const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
ScriptInterface::Request rq(scriptInterface);
const CSimContext simContext = g_Game->GetSimulation2()->GetSimContext();
CmpPtr<ICmpAIInterface> cmpAIInterface(simContext.GetSystemEntity());
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue state(cx);
JS::RootedValue state(rq.cx);
cmpAIInterface->GetFullRepresentation(&state, true);
return scriptInterface.StringifyJSON(&state, false);
}

View File

@ -43,7 +43,7 @@ template <typename T> struct MaybeRef;
#define CONVERT_ARG(z, i, data) \
bool typeConvRet##i; \
T##i a##i = ScriptInterface::AssignOrFromJSVal<T##i>( \
cx, \
rq, \
i < args.length() ? args[i] : JS::UndefinedHandleValue, \
typeConvRet##i); \
if (!typeConvRet##i) return false;

View File

@ -61,7 +61,7 @@ PASS_BY_VALUE_IN_NATIVE_WRAPPER(double)
// (NativeWrapperDecls.h set up a lot of the macros we use here)
// ScriptInterface_NativeWrapper<T>::call(cx, rval, fptr, args...) will call fptr(cbdata, args...),
// ScriptInterface_NativeWrapper<T>::call(rq, rval, fptr, args...) will call fptr(cbdata, args...),
// and if T != void then it will store the result in rval:
// Templated on the return type so void can be handled separately
@ -69,9 +69,9 @@ template <typename R>
struct ScriptInterface_NativeWrapper
{
template<typename F, typename... Ts>
static void call(JSContext* cx, JS::MutableHandleValue rval, F fptr, Ts... params)
static void call(const ScriptInterface::Request& rq, JS::MutableHandleValue rval, F fptr, Ts... params)
{
ScriptInterface::AssignOrToJSValUnrooted<R>(cx, rval, fptr(ScriptInterface::GetScriptInterfaceAndCBData(cx), params...));
ScriptInterface::AssignOrToJSValUnrooted<R>(rq, rval, fptr(ScriptInterface::GetScriptInterfaceAndCBData(rq.cx), params...));
}
};
@ -80,9 +80,9 @@ template <>
struct ScriptInterface_NativeWrapper<void>
{
template<typename F, typename... Ts>
static void call(JSContext* cx, JS::MutableHandleValue UNUSED(rval), F fptr, Ts... params)
static void call(const ScriptInterface::Request& rq, JS::MutableHandleValue UNUSED(rval), F fptr, Ts... params)
{
fptr(ScriptInterface::GetScriptInterfaceAndCBData(cx), params...);
fptr(ScriptInterface::GetScriptInterfaceAndCBData(rq.cx), params...);
}
};
@ -92,9 +92,9 @@ template <typename R, typename TC>
struct ScriptInterface_NativeMethodWrapper
{
template<typename F, typename... Ts>
static void call(JSContext* cx, JS::MutableHandleValue rval, TC* c, F fptr, Ts... params)
static void call(const ScriptInterface::Request& rq, JS::MutableHandleValue rval, TC* c, F fptr, Ts... params)
{
ScriptInterface::AssignOrToJSValUnrooted<R>(cx, rval, (c->*fptr)(params...));
ScriptInterface::AssignOrToJSValUnrooted<R>(rq, rval, (c->*fptr)(params...));
}
};
@ -102,7 +102,7 @@ template <typename TC>
struct ScriptInterface_NativeMethodWrapper<void, TC>
{
template<typename F, typename... Ts>
static void call(JSContext* UNUSED(cx), JS::MutableHandleValue UNUSED(rval), TC* c, F fptr, Ts... params)
static void call(const ScriptInterface::Request& UNUSED(rq), JS::MutableHandleValue UNUSED(rval), TC* c, F fptr, Ts... params)
{
(c->*fptr)(params...);
}
@ -114,12 +114,12 @@ struct ScriptInterface_NativeMethodWrapper<void, TC>
bool ScriptInterface::call(JSContext* cx, uint argc, JS::Value* vp) \
{ \
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
JSAutoRequest rq(cx); \
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
JS::RootedValue rval(cx); \
ScriptInterface_NativeWrapper<R>::template call<R( ScriptInterface::CxPrivate* T0_TAIL_MAYBE_REF(z,i)) T0_TAIL(z,i)>(cx, &rval, fptr A0_TAIL(z,i)); \
JS::RootedValue rval(rq.cx); \
ScriptInterface_NativeWrapper<R>::template call<R( ScriptInterface::CxPrivate* T0_TAIL_MAYBE_REF(z,i)) T0_TAIL(z,i)>(rq, &rval, fptr A0_TAIL(z,i)); \
args.rval().set(rval); \
return !ScriptInterface::IsExceptionPending(cx); \
return !ScriptInterface::IsExceptionPending(rq); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
@ -130,14 +130,14 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
bool ScriptInterface::callMethod(JSContext* cx, uint argc, JS::Value* vp) \
{ \
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
JSAutoRequest rq(cx); \
TC* c = ScriptInterface::GetPrivate<TC>(cx, args, CLS); \
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
TC* c = ScriptInterface::GetPrivate<TC>(rq, args, CLS); \
if (! c) return false; \
BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
JS::RootedValue rval(cx); \
ScriptInterface_NativeMethodWrapper<R, TC>::template call<R (TC::*)(T0_MAYBE_REF(z,i)) T0_TAIL(z,i)>(cx, &rval, c, fptr A0_TAIL(z,i)); \
JS::RootedValue rval(rq.cx); \
ScriptInterface_NativeMethodWrapper<R, TC>::template call<R (TC::*)(T0_MAYBE_REF(z,i)) T0_TAIL(z,i)>(rq, &rval, c, fptr A0_TAIL(z,i)); \
args.rval().set(rval); \
return !ScriptInterface::IsExceptionPending(cx); \
return !ScriptInterface::IsExceptionPending(rq); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
@ -148,27 +148,27 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
bool ScriptInterface::callMethodConst(JSContext* cx, uint argc, JS::Value* vp) \
{ \
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
JSAutoRequest rq(cx); \
TC* c = ScriptInterface::GetPrivate<TC>(cx, args, CLS); \
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
TC* c = ScriptInterface::GetPrivate<TC>(rq, args, CLS); \
if (! c) return false; \
BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
JS::RootedValue rval(cx); \
ScriptInterface_NativeMethodWrapper<R, TC>::template call<R (TC::*)(T0_MAYBE_REF(z,i)) const T0_TAIL(z,i)>(cx, &rval, c, fptr A0_TAIL(z,i)); \
JS::RootedValue rval(rq.cx); \
ScriptInterface_NativeMethodWrapper<R, TC>::template call<R (TC::*)(T0_MAYBE_REF(z,i)) const T0_TAIL(z,i)>(rq, &rval, c, fptr A0_TAIL(z,i)); \
args.rval().set(rval); \
return !ScriptInterface::IsExceptionPending(cx); \
return !ScriptInterface::IsExceptionPending(rq); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
template<int i, typename T, typename... Ts>
static void AssignOrToJSValHelper(JSContext* cx, JS::AutoValueVector& argv, const T& a, const Ts&... params)
static void AssignOrToJSValHelper(const ScriptInterface::Request& rq, JS::AutoValueVector& argv, const T& a, const Ts&... params)
{
ScriptInterface::AssignOrToJSVal(cx, argv[i], a);
AssignOrToJSValHelper<i+1>(cx, argv, params...);
ScriptInterface::AssignOrToJSVal(rq, argv[i], a);
AssignOrToJSValHelper<i+1>(rq, argv, params...);
}
template<int i, typename... Ts>
static void AssignOrToJSValHelper(JSContext* UNUSED(cx), JS::AutoValueVector& UNUSED(argv))
static void AssignOrToJSValHelper(const ScriptInterface::Request& UNUSED(rq), JS::AutoValueVector& UNUSED(argv))
{
cassert(sizeof...(Ts) == 0);
// Nop, for terminating the template recursion.
@ -177,37 +177,34 @@ static void AssignOrToJSValHelper(JSContext* UNUSED(cx), JS::AutoValueVector& UN
template<typename R, typename... Ts>
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, R& ret, const Ts&... params) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::AutoValueVector argv(cx);
ScriptInterface::Request rq(this);
JS::RootedValue jsRet(rq.cx);
JS::AutoValueVector argv(rq.cx);
argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(cx, argv, params...);
AssignOrToJSValHelper<0>(rq, argv, params...);
if (!CallFunction_(val, name, argv, &jsRet))
return false;
return FromJSVal(cx, jsRet, ret);
return FromJSVal(rq, jsRet, ret);
}
template<typename R, typename... Ts>
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::Rooted<R>* ret, const Ts&... params) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(this);
JS::MutableHandle<R> jsRet(ret);
JS::AutoValueVector argv(cx);
JS::AutoValueVector argv(rq.cx);
argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(cx, argv, params...);
AssignOrToJSValHelper<0>(rq, argv, params...);
return CallFunction_(val, name, argv, jsRet);
}
template<typename R, typename... Ts>
bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::MutableHandle<R> ret, const Ts&... params) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::AutoValueVector argv(cx);
ScriptInterface::Request rq(this);
JS::AutoValueVector argv(rq.cx);
argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(cx, argv, params...);
AssignOrToJSValHelper<0>(rq, argv, params...);
return CallFunction_(val, name, argv, ret);
}
@ -215,12 +212,11 @@ bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::Mu
template<typename... Ts>
bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const Ts&... params) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::AutoValueVector argv(cx);
ScriptInterface::Request rq(this);
JS::RootedValue jsRet(rq.cx);
JS::AutoValueVector argv(rq.cx);
argv.resize(sizeof...(Ts));
AssignOrToJSValHelper<0>(cx, argv, params...);
AssignOrToJSValHelper<0>(rq, argv, params...);
return CallFunction_(val, name, argv, &jsRet);
}

View File

@ -24,10 +24,10 @@
#include "ps/utf16string.h"
#include "ps/CStr.h"
#define FAIL(msg) STMT(JS_ReportError(cx, msg); return false)
#define FAIL(msg) STMT(JS_ReportError(rq.cx, msg); return false)
// Implicit type conversions often hide bugs, so warn about them
#define WARN_IF_NOT(c, v) STMT(if (!(c)) { JS_ReportWarning(cx, "Script value conversion check failed: %s (got type %s)", #c, InformalValueTypeName(v)); })
#define WARN_IF_NOT(c, v) STMT(if (!(c)) { JS_ReportWarning(rq.cx, "Script value conversion check failed: %s (got type %s)", #c, InformalValueTypeName(v)); })
// TODO: SpiderMonkey: Follow upstream progresses about JS_InformalValueTypeName in the API
// https://bugzilla.mozilla.org/show_bug.cgi?id=1285917
@ -50,77 +50,69 @@ static const char* InformalValueTypeName(const JS::Value& v)
return "value";
}
template<> bool ScriptInterface::FromJSVal<bool>(JSContext* cx, JS::HandleValue v, bool& out)
template<> bool ScriptInterface::FromJSVal<bool>(const Request& rq, JS::HandleValue v, bool& out)
{
JSAutoRequest rq(cx);
WARN_IF_NOT(v.isBoolean(), v);
out = JS::ToBoolean(v);
return true;
}
template<> bool ScriptInterface::FromJSVal<float>(JSContext* cx, JS::HandleValue v, float& out)
template<> bool ScriptInterface::FromJSVal<float>(const Request& rq, JS::HandleValue v, float& out)
{
JSAutoRequest rq(cx);
double tmp;
WARN_IF_NOT(v.isNumber(), v);
if (!JS::ToNumber(cx, v, &tmp))
if (!JS::ToNumber(rq.cx, v, &tmp))
return false;
out = tmp;
return true;
}
template<> bool ScriptInterface::FromJSVal<double>(JSContext* cx, JS::HandleValue v, double& out)
template<> bool ScriptInterface::FromJSVal<double>(const Request& rq, JS::HandleValue v, double& out)
{
JSAutoRequest rq(cx);
WARN_IF_NOT(v.isNumber(), v);
if (!JS::ToNumber(cx, v, &out))
if (!JS::ToNumber(rq.cx, v, &out))
return false;
return true;
}
template<> bool ScriptInterface::FromJSVal<i32>(JSContext* cx, JS::HandleValue v, i32& out)
template<> bool ScriptInterface::FromJSVal<i32>(const Request& rq, JS::HandleValue v, i32& out)
{
JSAutoRequest rq(cx);
WARN_IF_NOT(v.isNumber(), v);
if (!JS::ToInt32(cx, v, &out))
if (!JS::ToInt32(rq.cx, v, &out))
return false;
return true;
}
template<> bool ScriptInterface::FromJSVal<u32>(JSContext* cx, JS::HandleValue v, u32& out)
template<> bool ScriptInterface::FromJSVal<u32>(const Request& rq, JS::HandleValue v, u32& out)
{
JSAutoRequest rq(cx);
WARN_IF_NOT(v.isNumber(), v);
if (!JS::ToUint32(cx, v, &out))
if (!JS::ToUint32(rq.cx, v, &out))
return false;
return true;
}
template<> bool ScriptInterface::FromJSVal<u16>(JSContext* cx, JS::HandleValue v, u16& out)
template<> bool ScriptInterface::FromJSVal<u16>(const Request& rq, JS::HandleValue v, u16& out)
{
JSAutoRequest rq(cx);
WARN_IF_NOT(v.isNumber(), v);
if (!JS::ToUint16(cx, v, &out))
if (!JS::ToUint16(rq.cx, v, &out))
return false;
return true;
}
template<> bool ScriptInterface::FromJSVal<u8>(JSContext* cx, JS::HandleValue v, u8& out)
template<> bool ScriptInterface::FromJSVal<u8>(const Request& rq, JS::HandleValue v, u8& out)
{
JSAutoRequest rq(cx);
u16 tmp;
WARN_IF_NOT(v.isNumber(), v);
if (!JS::ToUint16(cx, v, &tmp))
if (!JS::ToUint16(rq.cx, v, &tmp))
return false;
out = (u8)tmp;
return true;
}
template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, JS::HandleValue v, std::wstring& out)
template<> bool ScriptInterface::FromJSVal<std::wstring>(const Request& rq, JS::HandleValue v, std::wstring& out)
{
JSAutoRequest rq(cx);
WARN_IF_NOT(v.isString() || v.isNumber(), v); // allow implicit number conversions
JS::RootedString str(cx, JS::ToString(cx, v));
JS::RootedString str(rq.cx, JS::ToString(rq.cx, v));
if (!str)
FAIL("Argument must be convertible to a string");
@ -128,7 +120,7 @@ template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, JS::Hand
{
size_t length;
JS::AutoCheckCannotGC nogc;
const JS::Latin1Char* ch = JS_GetLatin1StringCharsAndLength(cx, nogc, str, &length);
const JS::Latin1Char* ch = JS_GetLatin1StringCharsAndLength(rq.cx, nogc, str, &length);
if (!ch)
FAIL("JS_GetLatin1StringCharsAndLength failed");
@ -138,7 +130,7 @@ template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, JS::Hand
{
size_t length;
JS::AutoCheckCannotGC nogc;
const char16_t* ch = JS_GetTwoByteStringCharsAndLength(cx, nogc, str, &length);
const char16_t* ch = JS_GetTwoByteStringCharsAndLength(rq.cx, nogc, str, &length);
if (!ch)
FAIL("JS_GetTwoByteStringsCharsAndLength failed"); // out of memory
@ -147,57 +139,56 @@ template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, JS::Hand
return true;
}
template<> bool ScriptInterface::FromJSVal<Path>(JSContext* cx, JS::HandleValue v, Path& out)
template<> bool ScriptInterface::FromJSVal<Path>(const Request& rq, JS::HandleValue v, Path& out)
{
std::wstring string;
if (!FromJSVal(cx, v, string))
if (!FromJSVal(rq, v, string))
return false;
out = string;
return true;
}
template<> bool ScriptInterface::FromJSVal<std::string>(JSContext* cx, JS::HandleValue v, std::string& out)
template<> bool ScriptInterface::FromJSVal<std::string>(const Request& rq, JS::HandleValue v, std::string& out)
{
std::wstring wideout;
if (!FromJSVal(cx, v, wideout))
if (!FromJSVal(rq, v, wideout))
return false;
out = CStrW(wideout).ToUTF8();
return true;
}
template<> bool ScriptInterface::FromJSVal<CStr8>(JSContext* cx, JS::HandleValue v, CStr8& out)
template<> bool ScriptInterface::FromJSVal<CStr8>(const Request& rq, JS::HandleValue v, CStr8& out)
{
return ScriptInterface::FromJSVal(cx, v, static_cast<std::string&>(out));
return ScriptInterface::FromJSVal(rq, v, static_cast<std::string&>(out));
}
template<> bool ScriptInterface::FromJSVal<CStrW>(JSContext* cx, JS::HandleValue v, CStrW& out)
template<> bool ScriptInterface::FromJSVal<CStrW>(const Request& rq, JS::HandleValue v, CStrW& out)
{
return ScriptInterface::FromJSVal(cx, v, static_cast<std::wstring&>(out));
return ScriptInterface::FromJSVal(rq, v, static_cast<std::wstring&>(out));
}
template<> bool ScriptInterface::FromJSVal<Entity>(JSContext* cx, JS::HandleValue v, Entity& out)
template<> bool ScriptInterface::FromJSVal<Entity>(const Request& rq, JS::HandleValue v, Entity& out)
{
JSAutoRequest rq(cx);
if (!v.isObject())
FAIL("Argument must be an object");
JS::RootedObject obj(cx, &v.toObject());
JS::RootedValue templateName(cx);
JS::RootedValue id(cx);
JS::RootedValue player(cx);
JS::RootedValue position(cx);
JS::RootedValue rotation(cx);
JS::RootedObject obj(rq.cx, &v.toObject());
JS::RootedValue templateName(rq.cx);
JS::RootedValue id(rq.cx);
JS::RootedValue player(rq.cx);
JS::RootedValue position(rq.cx);
JS::RootedValue rotation(rq.cx);
// TODO: Report type errors
if (!JS_GetProperty(cx, obj, "player", &player) || !FromJSVal(cx, player, out.playerID))
if (!JS_GetProperty(rq.cx, obj, "player", &player) || !FromJSVal(rq, player, out.playerID))
FAIL("Failed to read Entity.player property");
if (!JS_GetProperty(cx, obj, "templateName", &templateName) || !FromJSVal(cx, templateName, out.templateName))
if (!JS_GetProperty(rq.cx, obj, "templateName", &templateName) || !FromJSVal(rq, templateName, out.templateName))
FAIL("Failed to read Entity.templateName property");
if (!JS_GetProperty(cx, obj, "id", &id) || !FromJSVal(cx, id, out.entityID))
if (!JS_GetProperty(rq.cx, obj, "id", &id) || !FromJSVal(rq, id, out.entityID))
FAIL("Failed to read Entity.id property");
if (!JS_GetProperty(cx, obj, "position", &position) || !FromJSVal(cx, position, out.position))
if (!JS_GetProperty(rq.cx, obj, "position", &position) || !FromJSVal(rq, position, out.position))
FAIL("Failed to read Entity.position property");
if (!JS_GetProperty(cx, obj, "rotation", &rotation) || !FromJSVal(cx, rotation, out.rotation))
if (!JS_GetProperty(rq.cx, obj, "rotation", &rotation) || !FromJSVal(rq, rotation, out.rotation))
FAIL("Failed to read Entity.rotation property");
return true;
@ -206,71 +197,69 @@ template<> bool ScriptInterface::FromJSVal<Entity>(JSContext* cx, JS::HandleValu
////////////////////////////////////////////////////////////////
// Primitive types:
template<> void ScriptInterface::ToJSVal<bool>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, const bool& val)
template<> void ScriptInterface::ToJSVal<bool>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const bool& val)
{
ret.setBoolean(val);
}
template<> void ScriptInterface::ToJSVal<float>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, const float& val)
template<> void ScriptInterface::ToJSVal<float>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const float& val)
{
ret.set(JS::NumberValue(val));
}
template<> void ScriptInterface::ToJSVal<double>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, const double& val)
template<> void ScriptInterface::ToJSVal<double>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const double& val)
{
ret.set(JS::NumberValue(val));
}
template<> void ScriptInterface::ToJSVal<i32>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, const i32& val)
template<> void ScriptInterface::ToJSVal<i32>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const i32& val)
{
ret.set(JS::NumberValue(val));
}
template<> void ScriptInterface::ToJSVal<u16>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, const u16& val)
template<> void ScriptInterface::ToJSVal<u16>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u16& val)
{
ret.set(JS::NumberValue(val));
}
template<> void ScriptInterface::ToJSVal<u8>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, const u8& val)
template<> void ScriptInterface::ToJSVal<u8>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u8& val)
{
ret.set(JS::NumberValue(val));
}
template<> void ScriptInterface::ToJSVal<u32>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, const u32& val)
template<> void ScriptInterface::ToJSVal<u32>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u32& val)
{
ret.set(JS::NumberValue(val));
}
template<> void ScriptInterface::ToJSVal<std::wstring>(JSContext* cx, JS::MutableHandleValue ret, const std::wstring& val)
template<> void ScriptInterface::ToJSVal<std::wstring>(const Request& rq, JS::MutableHandleValue ret, const std::wstring& val)
{
JSAutoRequest rq(cx);
utf16string utf16(val.begin(), val.end());
JS::RootedString str(cx, JS_NewUCStringCopyN(cx, reinterpret_cast<const char16_t*> (utf16.c_str()), utf16.length()));
JS::RootedString str(rq.cx, JS_NewUCStringCopyN(rq.cx, reinterpret_cast<const char16_t*> (utf16.c_str()), utf16.length()));
if (str)
ret.setString(str);
else
ret.setUndefined();
}
template<> void ScriptInterface::ToJSVal<Path>(JSContext* cx, JS::MutableHandleValue ret, const Path& val)
template<> void ScriptInterface::ToJSVal<Path>(const Request& rq, JS::MutableHandleValue ret, const Path& val)
{
ToJSVal(cx, ret, val.string());
ToJSVal(rq, ret, val.string());
}
template<> void ScriptInterface::ToJSVal<std::string>(JSContext* cx, JS::MutableHandleValue ret, const std::string& val)
template<> void ScriptInterface::ToJSVal<std::string>(const Request& rq, JS::MutableHandleValue ret, const std::string& val)
{
ToJSVal(cx, ret, static_cast<const std::wstring>(CStr(val).FromUTF8()));
ToJSVal(rq, ret, static_cast<const std::wstring>(CStr(val).FromUTF8()));
}
template<> void ScriptInterface::ToJSVal<const wchar_t*>(JSContext* cx, JS::MutableHandleValue ret, const wchar_t* const& val)
template<> void ScriptInterface::ToJSVal<const wchar_t*>(const Request& rq, JS::MutableHandleValue ret, const wchar_t* const& val)
{
ToJSVal(cx, ret, std::wstring(val));
ToJSVal(rq, ret, std::wstring(val));
}
template<> void ScriptInterface::ToJSVal<const char*>(JSContext* cx, JS::MutableHandleValue ret, const char* const& val)
template<> void ScriptInterface::ToJSVal<const char*>(const Request& rq, JS::MutableHandleValue ret, const char* const& val)
{
JSAutoRequest rq(cx);
JS::RootedString str(cx, JS_NewStringCopyZ(cx, val));
JS::RootedString str(rq.cx, JS_NewStringCopyZ(rq.cx, val));
if (str)
ret.setString(str);
else
@ -278,13 +267,13 @@ template<> void ScriptInterface::ToJSVal<const char*>(JSContext* cx, JS::Mutable
}
#define TOJSVAL_CHAR(N) \
template<> void ScriptInterface::ToJSVal<wchar_t[N]>(JSContext* cx, JS::MutableHandleValue ret, const wchar_t (&val)[N]) \
template<> void ScriptInterface::ToJSVal<wchar_t[N]>(const Request& rq, JS::MutableHandleValue ret, const wchar_t (&val)[N]) \
{ \
ToJSVal(cx, ret, static_cast<const wchar_t*>(val)); \
ToJSVal(rq, ret, static_cast<const wchar_t*>(val)); \
} \
template<> void ScriptInterface::ToJSVal<char[N]>(JSContext* cx, JS::MutableHandleValue ret, const char (&val)[N]) \
template<> void ScriptInterface::ToJSVal<char[N]>(const Request& rq, JS::MutableHandleValue ret, const char (&val)[N]) \
{ \
ToJSVal(cx, ret, static_cast<const char*>(val)); \
ToJSVal(rq, ret, static_cast<const char*>(val)); \
}
TOJSVAL_CHAR(3)
@ -311,14 +300,14 @@ TOJSVAL_CHAR(35)
TOJSVAL_CHAR(256)
#undef TOJSVAL_CHAR
template<> void ScriptInterface::ToJSVal<CStrW>(JSContext* cx, JS::MutableHandleValue ret, const CStrW& val)
template<> void ScriptInterface::ToJSVal<CStrW>(const Request& rq, JS::MutableHandleValue ret, const CStrW& val)
{
ToJSVal(cx, ret, static_cast<const std::wstring&>(val));
ToJSVal(rq, ret, static_cast<const std::wstring&>(val));
}
template<> void ScriptInterface::ToJSVal<CStr8>(JSContext* cx, JS::MutableHandleValue ret, const CStr8& val)
template<> void ScriptInterface::ToJSVal<CStr8>(const Request& rq, JS::MutableHandleValue ret, const CStr8& val)
{
ToJSVal(cx, ret, static_cast<const std::string&>(val));
ToJSVal(rq, ret, static_cast<const std::string&>(val));
}
////////////////////////////////////////////////////////////////
@ -337,27 +326,27 @@ JSVAL_VECTOR(std::vector<std::string>)
class IComponent;
template<> void ScriptInterface::ToJSVal<std::vector<IComponent*> >(JSContext* cx, JS::MutableHandleValue ret, const std::vector<IComponent*>& val)
template<> void ScriptInterface::ToJSVal<std::vector<IComponent*> >(const Request& rq, JS::MutableHandleValue ret, const std::vector<IComponent*>& val)
{
ToJSVal_vector(cx, ret, val);
ToJSVal_vector(rq, ret, val);
}
template<> bool ScriptInterface::FromJSVal<std::vector<Entity> >(JSContext* cx, JS::HandleValue v, std::vector<Entity>& out)
template<> bool ScriptInterface::FromJSVal<std::vector<Entity> >(const Request& rq, JS::HandleValue v, std::vector<Entity>& out)
{
return FromJSVal_vector(cx, v, out);
return FromJSVal_vector(rq, v, out);
}
template<> void ScriptInterface::ToJSVal<CVector2D>(JSContext* cx, JS::MutableHandleValue ret, const CVector2D& val)
template<> void ScriptInterface::ToJSVal<CVector2D>(const Request& rq, JS::MutableHandleValue ret, const CVector2D& val)
{
std::vector<float> vec = {val.X, val.Y};
ToJSVal_vector(cx, ret, vec);
ToJSVal_vector(rq, ret, vec);
}
template<> bool ScriptInterface::FromJSVal<CVector2D>(JSContext* cx, JS::HandleValue v, CVector2D& out)
template<> bool ScriptInterface::FromJSVal<CVector2D>(const Request& rq, JS::HandleValue v, CVector2D& out)
{
std::vector<float> vec;
if (!FromJSVal_vector(cx, v, vec))
if (!FromJSVal_vector(rq, v, vec))
return false;
if (vec.size() != 2)

View File

@ -23,10 +23,9 @@
#include <limits>
template<typename T> static void ToJSVal_vector(JSContext* cx, JS::MutableHandleValue ret, const std::vector<T>& val)
template<typename T> static void ToJSVal_vector(const ScriptInterface::Request& rq, JS::MutableHandleValue ret, const std::vector<T>& val)
{
JSAutoRequest rq(cx);
JS::RootedObject obj(cx, JS_NewArrayObject(cx, 0));
JS::RootedObject obj(rq.cx, JS_NewArrayObject(rq.cx, 0));
if (!obj)
{
ret.setUndefined();
@ -36,39 +35,38 @@ template<typename T> static void ToJSVal_vector(JSContext* cx, JS::MutableHandle
ENSURE(val.size() <= std::numeric_limits<u32>::max());
for (u32 i = 0; i < val.size(); ++i)
{
JS::RootedValue el(cx);
ScriptInterface::ToJSVal<T>(cx, &el, val[i]);
JS_SetElement(cx, obj, i, el);
JS::RootedValue el(rq.cx);
ScriptInterface::ToJSVal<T>(rq, &el, val[i]);
JS_SetElement(rq.cx, obj, i, el);
}
ret.setObject(*obj);
}
#define FAIL(msg) STMT(JS_ReportError(cx, msg); return false)
#define FAIL(msg) STMT(JS_ReportError(rq.cx, msg); return false)
template<typename T> static bool FromJSVal_vector(JSContext* cx, JS::HandleValue v, std::vector<T>& out)
template<typename T> static bool FromJSVal_vector(const ScriptInterface::Request& rq, JS::HandleValue v, std::vector<T>& out)
{
JSAutoRequest rq(cx);
JS::RootedObject obj(cx);
JS::RootedObject obj(rq.cx);
if (!v.isObject())
FAIL("Argument must be an array");
bool isArray;
obj = &v.toObject();
if ((!JS_IsArrayObject(cx, obj, &isArray) || !isArray) && !JS_IsTypedArrayObject(obj))
if ((!JS_IsArrayObject(rq.cx, obj, &isArray) || !isArray) && !JS_IsTypedArrayObject(obj))
FAIL("Argument must be an array");
u32 length;
if (!JS_GetArrayLength(cx, obj, &length))
if (!JS_GetArrayLength(rq.cx, obj, &length))
FAIL("Failed to get array length");
out.reserve(length);
for (u32 i = 0; i < length; ++i)
{
JS::RootedValue el(cx);
if (!JS_GetElement(cx, obj, i, &el))
JS::RootedValue el(rq.cx);
if (!JS_GetElement(rq.cx, obj, i, &el))
FAIL("Failed to read array element");
T el2;
if (!ScriptInterface::FromJSVal<T>(cx, el, el2))
if (!ScriptInterface::FromJSVal<T>(rq, el, el2))
return false;
out.push_back(el2);
}
@ -78,35 +76,34 @@ template<typename T> static bool FromJSVal_vector(JSContext* cx, JS::HandleValue
#undef FAIL
#define JSVAL_VECTOR(T) \
template<> void ScriptInterface::ToJSVal<std::vector<T> >(JSContext* cx, JS::MutableHandleValue ret, const std::vector<T>& val) \
template<> void ScriptInterface::ToJSVal<std::vector<T> >(const ScriptInterface::Request& rq, JS::MutableHandleValue ret, const std::vector<T>& val) \
{ \
ToJSVal_vector(cx, ret, val); \
ToJSVal_vector(rq, ret, val); \
} \
template<> bool ScriptInterface::FromJSVal<std::vector<T> >(JSContext* cx, JS::HandleValue v, std::vector<T>& out) \
template<> bool ScriptInterface::FromJSVal<std::vector<T> >(const ScriptInterface::Request& rq, JS::HandleValue v, std::vector<T>& out) \
{ \
return FromJSVal_vector(cx, v, out); \
return FromJSVal_vector(rq, v, out); \
}
template<typename T> bool ScriptInterface::FromJSProperty(JSContext* cx, const JS::HandleValue val, const char* name, T& ret, bool strict)
template<typename T> bool ScriptInterface::FromJSProperty(const ScriptInterface::Request& rq, const JS::HandleValue val, const char* name, T& ret, bool strict)
{
if (!val.isObject())
return false;
JSAutoRequest rq(cx);
JS::RootedObject obj(cx, &val.toObject());
JS::RootedObject obj(rq.cx, &val.toObject());
bool hasProperty;
if (!JS_HasProperty(cx, obj, name, &hasProperty) || !hasProperty)
if (!JS_HasProperty(rq.cx, obj, name, &hasProperty) || !hasProperty)
return false;
JS::RootedValue value(cx);
if (!JS_GetProperty(cx, obj, name, &value))
JS::RootedValue value(rq.cx);
if (!JS_GetProperty(rq.cx, obj, name, &value))
return false;
if (strict && value.isNull())
return false;
return FromJSVal(cx, value, ret);
return FromJSVal(rq, value, ret);
}
#endif //INCLUDED_SCRIPTCONVERSIONS

View File

@ -62,13 +62,27 @@ struct ScriptInterface_impl
// members have to be called before the runtime destructor.
shared_ptr<ScriptRuntime> m_runtime;
JSContext* m_cx;
JS::PersistentRootedObject m_glob; // global scope object
JSCompartment* m_formerCompartment;
boost::rand48* m_rng;
JS::PersistentRootedObject m_nativeScope; // native function scope object
friend ScriptInterface::Request;
private:
JSContext* m_cx;
JSCompartment* m_formerCompartment;
};
ScriptInterface::Request::Request(const ScriptInterface& scriptInterface) :
cx(scriptInterface.m->m_cx)
{
JS_BeginRequest(cx);
}
ScriptInterface::Request::~Request()
{
JS_EndRequest(cx);
}
namespace
{
@ -83,7 +97,7 @@ JSClass global_class = {
void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
{
JSAutoRequest rq(cx);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface);
std::stringstream msg;
bool isWarning = JSREPORT_IS_WARNING(report->flags);
@ -105,7 +119,7 @@ void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
JS_GetProperty(cx, excnObj, "stack", &stackVal);
std::string stackText;
ScriptInterface::FromJSVal(cx, stackVal, stackText);
ScriptInterface::FromJSVal(rq, stackVal, stackText);
std::istringstream stream(stackText);
for (std::string line; std::getline(stream, line);)
@ -126,10 +140,12 @@ void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
bool print(JSContext* cx, uint argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
for (uint i = 0; i < args.length(); ++i)
{
std::wstring str;
if (!ScriptInterface::FromJSVal(cx, args[i], str))
if (!ScriptInterface::FromJSVal(rq, args[i], str))
return false;
debug_printf("%s", utf8_from_wstring(str).c_str());
}
@ -147,8 +163,9 @@ bool logmsg(JSContext* cx, uint argc, JS::Value* vp)
return true;
}
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
std::wstring str;
if (!ScriptInterface::FromJSVal(cx, args[0], str))
if (!ScriptInterface::FromJSVal(rq, args[0], str))
return false;
LOGMESSAGE("%s", utf8_from_wstring(str));
args.rval().setUndefined();
@ -164,8 +181,9 @@ bool warn(JSContext* cx, uint argc, JS::Value* vp)
return true;
}
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
std::wstring str;
if (!ScriptInterface::FromJSVal(cx, args[0], str))
if (!ScriptInterface::FromJSVal(rq, args[0], str))
return false;
LOGWARNING("%s", utf8_from_wstring(str));
args.rval().setUndefined();
@ -181,8 +199,9 @@ bool error(JSContext* cx, uint argc, JS::Value* vp)
return true;
}
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
std::wstring str;
if (!ScriptInterface::FromJSVal(cx, args[0], str))
if (!ScriptInterface::FromJSVal(rq, args[0], str))
return false;
LOGERROR("%s", utf8_from_wstring(str));
args.rval().setUndefined();
@ -191,8 +210,6 @@ bool error(JSContext* cx, uint argc, JS::Value* vp)
bool deepcopy(JSContext* cx, uint argc, JS::Value* vp)
{
JSAutoRequest rq(cx);
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
if (args.length() < 1)
{
@ -200,8 +217,9 @@ bool deepcopy(JSContext* cx, uint argc, JS::Value* vp)
return true;
}
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
JS::RootedValue ret(cx);
if (!JS_StructuredClone(cx, args[0], &ret, NULL, NULL))
if (!JS_StructuredClone(rq.cx, args[0], &ret, NULL, NULL))
return false;
args.rval().set(ret);
@ -211,10 +229,10 @@ bool deepcopy(JSContext* cx, uint argc, JS::Value* vp)
bool deepfreeze(JSContext* cx, uint argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
if (args.length() != 1 || !args.get(0).isObject())
{
JSAutoRequest rq(cx);
JS_ReportError(cx, "deepfreeze requires exactly one object as an argument.");
return false;
}
@ -229,10 +247,11 @@ bool ProfileStart(JSContext* cx, uint argc, JS::Value* vp)
const char* name = "(ProfileStart)";
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
if (args.length() >= 1)
{
std::string str;
if (!ScriptInterface::FromJSVal(cx, args[0], str))
if (!ScriptInterface::FromJSVal(rq, args[0], str))
return false;
typedef boost::flyweight<
@ -270,10 +289,11 @@ bool ProfileAttribute(JSContext* cx, uint argc, JS::Value* vp)
const char* name = "(ProfileAttribute)";
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \
if (args.length() >= 1)
{
std::string str;
if (!ScriptInterface::FromJSVal(cx, args[0], str))
if (!ScriptInterface::FromJSVal(rq, args[0], str))
return false;
typedef boost::flyweight<
@ -409,8 +429,9 @@ ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugN
g_ScriptStatsTable->Add(this, debugName);
}
Request rq(this);
m_CxPrivate.pScriptInterface = this;
JS_SetContextPrivate(m->m_cx, (void*)&m_CxPrivate);
JS_SetContextPrivate(rq.cx, (void*)&m_CxPrivate);
}
ScriptInterface::~ScriptInterface()
@ -455,13 +476,13 @@ bool ScriptInterface::LoadGlobalScripts()
bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng)
{
JSAutoRequest rq(m->m_cx);
JS::RootedValue math(m->m_cx);
JS::RootedObject global(m->m_cx, m->m_glob);
if (JS_GetProperty(m->m_cx, global, "Math", &math) && math.isObject())
Request rq(this);
JS::RootedValue math(rq.cx);
JS::RootedObject global(rq.cx, m->m_glob);
if (JS_GetProperty(rq.cx, global, "Math", &math) && math.isObject())
{
JS::RootedObject mathObj(m->m_cx, &math.toObject());
JS::RootedFunction random(m->m_cx, JS_DefineFunction(m->m_cx, mathObj, "random", Math_random, 0,
JS::RootedObject mathObj(rq.cx, &math.toObject());
JS::RootedFunction random(rq.cx, JS_DefineFunction(rq.cx, mathObj, "random", Math_random, 0,
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT));
if (random)
{
@ -479,11 +500,6 @@ void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) co
m->Register(name, fptr, (uint)nargs);
}
JSContext* ScriptInterface::GetContext() const
{
return m->m_cx;
}
JSRuntime* ScriptInterface::GetJSRuntime() const
{
return m->m_runtime->m_rt;
@ -496,7 +512,7 @@ shared_ptr<ScriptRuntime> ScriptInterface::GetRuntime() const
void ScriptInterface::CallConstructor(JS::HandleValue ctor, JS::HandleValueArray argv, JS::MutableHandleValue out) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
if (!ctor.isObject())
{
LOGERROR("CallConstructor: ctor is not an object");
@ -504,13 +520,13 @@ void ScriptInterface::CallConstructor(JS::HandleValue ctor, JS::HandleValueArray
return;
}
JS::RootedObject ctorObj(m->m_cx, &ctor.toObject());
out.setObjectOrNull(JS_New(m->m_cx, ctorObj, argv));
JS::RootedObject ctorObj(rq.cx, &ctor.toObject());
out.setObjectOrNull(JS_New(rq.cx, ctorObj, argv));
}
void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
std::string typeName = clasp->name;
if (m_CustomObjectTypes.find(typeName) != m_CustomObjectTypes.end())
@ -519,8 +535,8 @@ void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructo
throw PSERROR_Scripting_DefineType_AlreadyExists();
}
JS::RootedObject global(m->m_cx, m->m_glob);
JS::RootedObject obj(m->m_cx, JS_InitClass(m->m_cx, global, nullptr,
JS::RootedObject global(rq.cx, m->m_glob);
JS::RootedObject obj(rq.cx, JS_InitClass(rq.cx, global, nullptr,
clasp,
constructor, minArgs, // Constructor, min args
ps, fs, // Properties, methods
@ -531,7 +547,7 @@ void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructo
CustomType& type = m_CustomObjectTypes[typeName];
type.m_Prototype.init(m->m_cx, obj);
type.m_Prototype.init(rq.cx, obj);
type.m_Class = clasp;
type.m_Constructor = constructor;
}
@ -543,31 +559,30 @@ JSObject* ScriptInterface::CreateCustomObject(const std::string& typeName) const
if (it == m_CustomObjectTypes.end())
throw PSERROR_Scripting_TypeDoesNotExist();
JS::RootedObject prototype(m->m_cx, it->second.m_Prototype.get());
return JS_NewObjectWithGivenProto(m->m_cx, it->second.m_Class, prototype);
Request rq(this);
JS::RootedObject prototype(rq.cx, it->second.m_Prototype.get());
return JS_NewObjectWithGivenProto(rq.cx, it->second.m_Class, prototype);
}
bool ScriptInterface::CallFunction_(JS::HandleValue val, const char* name, JS::HandleValueArray argv, JS::MutableHandleValue ret) const
{
JSAutoRequest rq(m->m_cx);
JS::RootedObject obj(m->m_cx);
if (!JS_ValueToObject(m->m_cx, val, &obj) || !obj)
Request rq(this);
JS::RootedObject obj(rq.cx);
if (!JS_ValueToObject(rq.cx, val, &obj) || !obj)
return false;
// Check that the named function actually exists, to avoid ugly JS error reports
// when calling an undefined value
bool found;
if (!JS_HasProperty(m->m_cx, obj, name, &found) || !found)
if (!JS_HasProperty(rq.cx, obj, name, &found) || !found)
return false;
return JS_CallFunctionName(m->m_cx, obj, name, argv, ret);
return JS_CallFunctionName(rq.cx, obj, name, argv, ret);
}
bool ScriptInterface::CreateObject_(JSContext* cx, JS::MutableHandleObject object)
bool ScriptInterface::CreateObject_(const Request& rq, JS::MutableHandleObject object)
{
// JSAutoRequest is the responsibility of the caller
object.set(JS_NewPlainObject(cx));
object.set(JS_NewPlainObject(rq.cx));
if (!object)
throw PSERROR_Scripting_CreateObjectFailed();
@ -575,40 +590,38 @@ bool ScriptInterface::CreateObject_(JSContext* cx, JS::MutableHandleObject objec
return true;
}
void ScriptInterface::CreateArray(JSContext* cx, JS::MutableHandleValue objectValue, size_t length)
void ScriptInterface::CreateArray(const Request& rq, JS::MutableHandleValue objectValue, size_t length)
{
JSAutoRequest rq(cx);
objectValue.setObjectOrNull(JS_NewArrayObject(cx, length));
objectValue.setObjectOrNull(JS_NewArrayObject(rq.cx, length));
if (!objectValue.isObject())
throw PSERROR_Scripting_CreateObjectFailed();
}
JS::Value ScriptInterface::GetGlobalObject() const
{
JSAutoRequest rq(m->m_cx);
return JS::ObjectValue(*JS::CurrentGlobalOrNull(m->m_cx));
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)
{
JSAutoRequest rq(m->m_cx);
JS::RootedObject global(m->m_cx, m->m_glob);
Request rq(this);
JS::RootedObject global(rq.cx, m->m_glob);
bool found;
if (!JS_HasProperty(m->m_cx, global, name, &found))
if (!JS_HasProperty(rq.cx, global, name, &found))
return false;
if (found)
{
JS::Rooted<JSPropertyDescriptor> desc(m->m_cx);
if (!JS_GetOwnPropertyDescriptor(m->m_cx, global, name, &desc))
JS::Rooted<JSPropertyDescriptor> desc(rq.cx);
if (!JS_GetOwnPropertyDescriptor(rq.cx, global, name, &desc))
return false;
if (!desc.writable())
{
if (!replace)
{
JS_ReportError(m->m_cx, "SetGlobal \"%s\" called multiple times", name);
JS_ReportError(rq.cx, "SetGlobal \"%s\" called multiple times", name);
return false;
}
@ -616,12 +629,12 @@ bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool r
// instead of using SetGlobal.
if (!desc.configurable())
{
JS_ReportError(m->m_cx, "The global \"%s\" is permanent and cannot be hotloaded", name);
JS_ReportError(rq.cx, "The global \"%s\" is permanent and cannot be hotloaded", name);
return false;
}
LOGMESSAGE("Hotloading new value for global \"%s\".", name);
ENSURE(JS_DeleteProperty(m->m_cx, global, name));
ENSURE(JS_DeleteProperty(rq.cx, global, name));
}
}
@ -631,12 +644,12 @@ bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool r
if (enumerate)
attrs |= JSPROP_ENUMERATE;
return JS_DefineProperty(m->m_cx, global, name, value, attrs);
return JS_DefineProperty(rq.cx, global, name, value, attrs);
}
bool ScriptInterface::SetProperty_(JS::HandleValue obj, const char* name, JS::HandleValue value, bool constant, bool enumerate) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
uint attrs = 0;
if (constant)
attrs |= JSPROP_READONLY | JSPROP_PERMANENT;
@ -645,16 +658,16 @@ bool ScriptInterface::SetProperty_(JS::HandleValue obj, const char* name, JS::Ha
if (!obj.isObject())
return false;
JS::RootedObject object(m->m_cx, &obj.toObject());
JS::RootedObject object(rq.cx, &obj.toObject());
if (!JS_DefineProperty(m->m_cx, object, name, value, attrs))
if (!JS_DefineProperty(rq.cx, object, name, value, attrs))
return false;
return true;
}
bool ScriptInterface::SetProperty_(JS::HandleValue obj, const wchar_t* name, JS::HandleValue value, bool constant, bool enumerate) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
uint attrs = 0;
if (constant)
attrs |= JSPROP_READONLY | JSPROP_PERMANENT;
@ -663,17 +676,17 @@ bool ScriptInterface::SetProperty_(JS::HandleValue obj, const wchar_t* name, JS:
if (!obj.isObject())
return false;
JS::RootedObject object(m->m_cx, &obj.toObject());
JS::RootedObject object(rq.cx, &obj.toObject());
utf16string name16(name, name + wcslen(name));
if (!JS_DefineUCProperty(m->m_cx, object, reinterpret_cast<const char16_t*>(name16.c_str()), name16.length(), value, attrs))
if (!JS_DefineUCProperty(rq.cx, object, reinterpret_cast<const char16_t*>(name16.c_str()), name16.length(), value, attrs))
return false;
return true;
}
bool ScriptInterface::SetPropertyInt_(JS::HandleValue obj, int name, JS::HandleValue value, bool constant, bool enumerate) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
uint attrs = 0;
if (constant)
attrs |= JSPROP_READONLY | JSPROP_PERMANENT;
@ -682,10 +695,10 @@ bool ScriptInterface::SetPropertyInt_(JS::HandleValue obj, int name, JS::HandleV
if (!obj.isObject())
return false;
JS::RootedObject object(m->m_cx, &obj.toObject());
JS::RootedObject object(rq.cx, &obj.toObject());
JS::RootedId id(m->m_cx, INT_TO_JSID(name));
if (!JS_DefinePropertyById(m->m_cx, object, id, value, attrs))
JS::RootedId id(rq.cx, INT_TO_JSID(name));
if (!JS_DefinePropertyById(rq.cx, object, id, value, attrs))
return false;
return true;
}
@ -697,9 +710,8 @@ bool ScriptInterface::GetProperty(JS::HandleValue obj, const char* name, JS::Mut
bool ScriptInterface::GetProperty(JS::HandleValue obj, const char* name, JS::MutableHandleObject out) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue val(cx);
Request rq(this);
JS::RootedValue val(rq.cx);
if (!GetProperty_(obj, name, &val))
return false;
if (!val.isObject())
@ -719,25 +731,25 @@ bool ScriptInterface::GetPropertyInt(JS::HandleValue obj, int name, JS::MutableH
bool ScriptInterface::GetProperty_(JS::HandleValue obj, const char* name, JS::MutableHandleValue out) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
if (!obj.isObject())
return false;
JS::RootedObject object(m->m_cx, &obj.toObject());
JS::RootedObject object(rq.cx, &obj.toObject());
if (!JS_GetProperty(m->m_cx, object, name, out))
if (!JS_GetProperty(rq.cx, object, name, out))
return false;
return true;
}
bool ScriptInterface::GetPropertyInt_(JS::HandleValue obj, int name, JS::MutableHandleValue out) const
{
JSAutoRequest rq(m->m_cx);
JS::RootedId nameId(m->m_cx, INT_TO_JSID(name));
Request rq(this);
JS::RootedId nameId(rq.cx, INT_TO_JSID(name));
if (!obj.isObject())
return false;
JS::RootedObject object(m->m_cx, &obj.toObject());
JS::RootedObject object(rq.cx, &obj.toObject());
if (!JS_GetPropertyById(m->m_cx, object, nameId, out))
if (!JS_GetPropertyById(rq.cx, object, nameId, out))
return false;
return true;
}
@ -745,20 +757,20 @@ bool ScriptInterface::GetPropertyInt_(JS::HandleValue obj, int name, JS::Mutable
bool ScriptInterface::HasProperty(JS::HandleValue obj, const char* name) const
{
// TODO: proper errorhandling
JSAutoRequest rq(m->m_cx);
Request rq(this);
if (!obj.isObject())
return false;
JS::RootedObject object(m->m_cx, &obj.toObject());
JS::RootedObject object(rq.cx, &obj.toObject());
bool found;
if (!JS_HasProperty(m->m_cx, object, name, &found))
if (!JS_HasProperty(rq.cx, object, name, &found))
return false;
return found;
}
bool ScriptInterface::EnumeratePropertyNames(JS::HandleValue objVal, bool enumerableOnly, std::vector<std::string>& out) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
if (!objVal.isObjectOrNull())
{
@ -766,18 +778,18 @@ bool ScriptInterface::EnumeratePropertyNames(JS::HandleValue objVal, bool enumer
return false;
}
JS::RootedObject obj(m->m_cx, &objVal.toObject());
JS::AutoIdVector props(m->m_cx);
JS::RootedObject obj(rq.cx, &objVal.toObject());
JS::AutoIdVector props(rq.cx);
// This recurses up the prototype chain on its own.
if (!js::GetPropertyKeys(m->m_cx, obj, enumerableOnly? 0 : JSITER_HIDDEN, &props))
if (!js::GetPropertyKeys(rq.cx, obj, enumerableOnly? 0 : JSITER_HIDDEN, &props))
return false;
out.reserve(out.size() + props.length());
for (size_t i = 0; i < props.length(); ++i)
{
JS::RootedId id(m->m_cx, props[i]);
JS::RootedValue val(m->m_cx);
if (!JS_IdToValue(m->m_cx, id, &val))
JS::RootedId id(rq.cx, props[i]);
JS::RootedValue val(rq.cx);
if (!JS_IdToValue(rq.cx, id, &val))
return false;
// Ignore integer properties for now.
@ -786,7 +798,7 @@ bool ScriptInterface::EnumeratePropertyNames(JS::HandleValue objVal, bool enumer
continue;
std::string propName;
if (!FromJSVal(m->m_cx, val, propName))
if (!FromJSVal(rq, val, propName))
return false;
out.emplace_back(std::move(propName));
@ -797,71 +809,71 @@ bool ScriptInterface::EnumeratePropertyNames(JS::HandleValue objVal, bool enumer
bool ScriptInterface::SetPrototype(JS::HandleValue objVal, JS::HandleValue protoVal)
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
if (!objVal.isObject() || !protoVal.isObject())
return false;
JS::RootedObject obj(m->m_cx, &objVal.toObject());
JS::RootedObject proto(m->m_cx, &protoVal.toObject());
return JS_SetPrototype(m->m_cx, obj, proto);
JS::RootedObject obj(rq.cx, &objVal.toObject());
JS::RootedObject proto(rq.cx, &protoVal.toObject());
return JS_SetPrototype(rq.cx, obj, proto);
}
bool ScriptInterface::FreezeObject(JS::HandleValue objVal, bool deep) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
if (!objVal.isObject())
return false;
JS::RootedObject obj(m->m_cx, &objVal.toObject());
JS::RootedObject obj(rq.cx, &objVal.toObject());
if (deep)
return JS_DeepFreezeObject(m->m_cx, obj);
return JS_DeepFreezeObject(rq.cx, obj);
else
return JS_FreezeObject(m->m_cx, obj);
return JS_FreezeObject(rq.cx, obj);
}
bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& code) const
{
JSAutoRequest rq(m->m_cx);
JS::RootedObject global(m->m_cx, m->m_glob);
Request rq(this);
JS::RootedObject global(rq.cx, m->m_glob);
utf16string codeUtf16(code.begin(), code.end());
uint lineNo = 1;
// 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.
std::string filenameStr = filename.string8();
JS::CompileOptions options(m->m_cx);
JS::CompileOptions options(rq.cx);
options.setFileAndLine(filenameStr.c_str(), lineNo);
options.setIsRunOnce(false);
JS::RootedFunction func(m->m_cx);
JS::AutoObjectVector emptyScopeChain(m->m_cx);
if (!JS::CompileFunction(m->m_cx, emptyScopeChain, options, NULL, 0, NULL,
JS::RootedFunction func(rq.cx);
JS::AutoObjectVector emptyScopeChain(rq.cx);
if (!JS::CompileFunction(rq.cx, emptyScopeChain, options, NULL, 0, NULL,
reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &func))
return false;
JS::RootedValue rval(m->m_cx);
return JS_CallFunction(m->m_cx, nullptr, func, JS::HandleValueArray::empty(), &rval);
JS::RootedValue rval(rq.cx);
return JS_CallFunction(rq.cx, nullptr, func, JS::HandleValueArray::empty(), &rval);
}
bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstring& code) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
utf16string codeUtf16(code.begin(), code.end());
uint lineNo = 1;
// 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.
std::string filenameStr = filename.string8();
JS::RootedValue rval(m->m_cx);
JS::CompileOptions opts(m->m_cx);
JS::RootedValue rval(rq.cx);
JS::CompileOptions opts(rq.cx);
opts.setFileAndLine(filenameStr.c_str(), lineNo);
return JS::Evaluate(m->m_cx, opts,
return JS::Evaluate(rq.cx, opts,
reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval);
}
bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
if (!VfsFileExists(path))
{
LOGERROR("File '%s' does not exist", path.string8());
@ -886,68 +898,68 @@ bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const
// Passing a temporary string there will cause undefined behaviour, so we create a separate string to avoid the temporary.
std::string filenameStr = path.string8();
JS::RootedValue rval(m->m_cx);
JS::CompileOptions opts(m->m_cx);
JS::RootedValue rval(rq.cx);
JS::CompileOptions opts(rq.cx);
opts.setFileAndLine(filenameStr.c_str(), lineNo);
return JS::Evaluate(m->m_cx, opts,
return JS::Evaluate(rq.cx, opts,
reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval);
}
bool ScriptInterface::Eval(const char* code) const
{
JSAutoRequest rq(m->m_cx);
JS::RootedValue rval(m->m_cx);
Request rq(this);
JS::RootedValue rval(rq.cx);
return Eval_(code, &rval);
}
bool ScriptInterface::Eval_(const char* code, JS::MutableHandleValue rval) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
utf16string codeUtf16(code, code+strlen(code));
JS::CompileOptions opts(m->m_cx);
JS::CompileOptions opts(rq.cx);
opts.setFileAndLine("(eval)", 1);
return JS::Evaluate(m->m_cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval);
return JS::Evaluate(rq.cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval);
}
bool ScriptInterface::Eval_(const wchar_t* code, JS::MutableHandleValue rval) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
utf16string codeUtf16(code, code+wcslen(code));
JS::CompileOptions opts(m->m_cx);
JS::CompileOptions opts(rq.cx);
opts.setFileAndLine("(eval)", 1);
return JS::Evaluate(m->m_cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval);
return JS::Evaluate(rq.cx, opts, reinterpret_cast<const char16_t*>(codeUtf16.c_str()), (uint)codeUtf16.length(), rval);
}
bool ScriptInterface::ParseJSON(const std::string& string_utf8, JS::MutableHandleValue out) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
std::wstring attrsW = wstring_from_utf8(string_utf8);
utf16string string(attrsW.begin(), attrsW.end());
if (JS_ParseJSON(m->m_cx, reinterpret_cast<const char16_t*>(string.c_str()), (u32)string.size(), out))
if (JS_ParseJSON(rq.cx, reinterpret_cast<const char16_t*>(string.c_str()), (u32)string.size(), out))
return true;
LOGERROR("JS_ParseJSON failed!");
if (!JS_IsExceptionPending(m->m_cx))
if (!JS_IsExceptionPending(rq.cx))
return false;
JS::RootedValue exc(m->m_cx);
if (!JS_GetPendingException(m->m_cx, &exc))
JS::RootedValue exc(rq.cx);
if (!JS_GetPendingException(rq.cx, &exc))
return false;
JS_ClearPendingException(m->m_cx);
JS_ClearPendingException(rq.cx);
// We expect an object of type SyntaxError
if (!exc.isObject())
return false;
JS::RootedValue rval(m->m_cx);
JS::RootedObject excObj(m->m_cx, &exc.toObject());
if (!JS_CallFunctionName(m->m_cx, excObj, "toString", JS::HandleValueArray::empty(), &rval))
JS::RootedValue rval(rq.cx);
JS::RootedObject excObj(rq.cx, &exc.toObject());
if (!JS_CallFunctionName(rq.cx, excObj, "toString", JS::HandleValueArray::empty(), &rval))
return false;
std::wstring error;
ScriptInterface::FromJSVal(m->m_cx, rval, error);
ScriptInterface::FromJSVal(rq, rval, error);
LOGERROR("%s", utf8_from_wstring(error));
return false;
}
@ -995,12 +1007,12 @@ struct Stringifier
// It probably has historical reasons and could be changed by SpiderMonkey in the future.
std::string ScriptInterface::StringifyJSON(JS::MutableHandleValue obj, bool indent) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
Stringifier str;
JS::RootedValue indentVal(m->m_cx, indent ? JS::Int32Value(2) : JS::UndefinedValue());
if (!JS_Stringify(m->m_cx, obj, nullptr, indentVal, &Stringifier::callback, &str))
JS::RootedValue indentVal(rq.cx, indent ? JS::Int32Value(2) : JS::UndefinedValue());
if (!JS_Stringify(rq.cx, obj, nullptr, indentVal, &Stringifier::callback, &str))
{
JS_ClearPendingException(m->m_cx);
JS_ClearPendingException(rq.cx);
LOGERROR("StringifyJSON failed");
return std::string();
}
@ -1011,7 +1023,7 @@ std::string ScriptInterface::StringifyJSON(JS::MutableHandleValue obj, bool inde
std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
if (obj.isUndefined())
return "(void 0)";
@ -1021,12 +1033,12 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) c
if (pretty)
{
Stringifier str;
JS::RootedValue indentVal(m->m_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
JSErrorReporter er = JS_SetErrorReporter(m->m_runtime->m_rt, NULL);
bool ok = JS_Stringify(m->m_cx, obj, nullptr, indentVal, &Stringifier::callback, &str);
bool ok = JS_Stringify(rq.cx, obj, nullptr, indentVal, &Stringifier::callback, &str);
// Restore error reporter
JS_SetErrorReporter(m->m_runtime->m_rt, er);
@ -1035,7 +1047,7 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) c
return str.stream.str();
// Clear the exception set when Stringify failed
JS_ClearPendingException(m->m_cx);
JS_ClearPendingException(rq.cx);
}
// Caller didn't want pretty output, or JSON conversion failed (e.g. due to cycles),
@ -1048,29 +1060,28 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) c
void ScriptInterface::ReportError(const char* msg) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
// JS_ReportError by itself doesn't seem to set a JS-style exception, and so
// script callers will be unable to catch anything. So use JS_SetPendingException
// to make sure there really is a script-level exception. But just set it to undefined
// because there's not much value yet in throwing a real exception object.
JS_SetPendingException(m->m_cx, JS::UndefinedHandleValue);
JS_SetPendingException(rq.cx, JS::UndefinedHandleValue);
// And report the actual error
JS_ReportError(m->m_cx, "%s", msg);
JS_ReportError(rq.cx, "%s", msg);
// TODO: Why doesn't JS_ReportPendingException(m->m_cx); work?
// TODO: Why doesn't JS_ReportPendingException(cx); work?
}
bool ScriptInterface::IsExceptionPending(JSContext* cx)
bool ScriptInterface::IsExceptionPending(const Request& rq)
{
JSAutoRequest rq(cx);
return JS_IsExceptionPending(cx) ? true : false;
return JS_IsExceptionPending(rq.cx) ? true : false;
}
JS::Value ScriptInterface::CloneValueFromOtherContext(const ScriptInterface& otherContext, JS::HandleValue val) const
{
PROFILE("CloneValueFromOtherContext");
JSAutoRequest rq(m->m_cx);
JS::RootedValue out(m->m_cx);
Request rq(this);
JS::RootedValue out(rq.cx);
shared_ptr<StructuredClone> structuredClone = otherContext.WriteStructuredClone(val);
ReadStructuredClone(structuredClone, &out);
return out.get();
@ -1089,10 +1100,10 @@ ScriptInterface::StructuredClone::~StructuredClone()
shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClone(JS::HandleValue v) const
{
JSAutoRequest rq(m->m_cx);
Request rq(this);
u64* data = NULL;
size_t nbytes = 0;
if (!JS_WriteStructuredClone(m->m_cx, v, &data, &nbytes, NULL, NULL, JS::UndefinedHandleValue))
if (!JS_WriteStructuredClone(rq.cx, v, &data, &nbytes, NULL, NULL, JS::UndefinedHandleValue))
{
debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!");
return shared_ptr<StructuredClone>();
@ -1106,6 +1117,6 @@ shared_ptr<ScriptInterface::StructuredClone> ScriptInterface::WriteStructuredClo
void ScriptInterface::ReadStructuredClone(const shared_ptr<ScriptInterface::StructuredClone>& ptr, JS::MutableHandleValue ret) const
{
JSAutoRequest rq(m->m_cx);
JS_ReadStructuredClone(m->m_cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, ret, NULL, NULL);
Request rq(this);
JS_ReadStructuredClone(rq.cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, ret, NULL, NULL);
}

View File

@ -91,10 +91,29 @@ public:
void SetCallbackData(void* pCBData);
static CxPrivate* GetScriptInterfaceAndCBData(JSContext* cx);
JSContext* GetContext() const;
JSRuntime* GetJSRuntime() const;
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.
*/
struct Request
{
Request() = delete;
Request(const Request& rq) = delete;
Request& operator=(const Request& rq) = delete;
Request(const ScriptInterface& scriptInterface);
Request(const ScriptInterface* scriptInterface) : Request(*scriptInterface) {}
Request(shared_ptr<ScriptInterface> scriptInterface) : Request(*scriptInterface) {}
Request(const CxPrivate* cxPrivate) : Request(cxPrivate->pScriptInterface) {}
~Request();
JSContext* cx;
};
friend struct Request;
/**
* Load global scripts that most script contexts need,
* located in the /globalscripts directory. VFS must be initialized.
@ -123,12 +142,11 @@ public:
* Can throw an exception.
*/
template<typename... Args>
static bool CreateObject(JSContext* cx, JS::MutableHandleValue objectValue, Args const&... args)
static bool CreateObject(const Request& rq, JS::MutableHandleValue objectValue, Args const&... args)
{
JSAutoRequest rq(cx);
JS::RootedObject obj(cx);
JS::RootedObject obj(rq.cx);
if (!CreateObject_(cx, &obj, args...))
if (!CreateObject_(rq, &obj, args...))
return false;
objectValue.setObject(*obj);
@ -138,7 +156,7 @@ public:
/**
* Sets the given value to a new JS object or Null Value in case of out-of-memory.
*/
static void CreateArray(JSContext* cx, JS::MutableHandleValue objectValue, size_t length = 0);
static void CreateArray(const Request& rq, JS::MutableHandleValue objectValue, size_t length = 0);
JS::Value GetGlobalObject() const;
@ -283,7 +301,7 @@ public:
/**
* Convert a JS::Value to a C++ type. (This might trigger GC.)
*/
template<typename T> static bool FromJSVal(JSContext* cx, const JS::HandleValue val, T& ret);
template<typename T> static bool FromJSVal(const Request& rq, const JS::HandleValue val, T& ret);
/**
* Convert a C++ type to a JS::Value. (This might trigger GC. The return
@ -292,12 +310,12 @@ public:
* The reason is a memory corruption problem that appears to be caused by a bug in Visual Studio.
* Details here: http://www.wildfiregames.com/forum/index.php?showtopic=17289&p=285921
*/
template<typename T> static void ToJSVal(JSContext* cx, JS::MutableHandleValue ret, T const& val);
template<typename T> static void ToJSVal(const Request& rq, JS::MutableHandleValue ret, T const& val);
/**
* Convert a named property of an object to a C++ type.
*/
template<typename T> static bool FromJSProperty(JSContext* cx, const JS::HandleValue val, const char* name, T& ret, bool strict = false);
template<typename T> static bool FromJSProperty(const Request& rq, const JS::HandleValue val, const char* name, T& ret, bool strict = false);
/**
* MathRandom (this function) calls the random number generator assigned to this ScriptInterface instance and
@ -331,12 +349,11 @@ public:
* Retrieve the private data field of a JSObject that is an instance of the given JSClass.
*/
template <typename T>
static T* GetPrivate(JSContext* cx, JS::HandleObject thisobj, JSClass* jsClass)
static T* GetPrivate(const Request& rq, JS::HandleObject thisobj, JSClass* jsClass)
{
JSAutoRequest rq(cx);
T* value = static_cast<T*>(JS_GetInstancePrivate(cx, thisobj, jsClass, nullptr));
if (value == nullptr && !JS_IsExceptionPending(cx))
JS_ReportError(cx, "Private data of the given object is null!");
T* value = static_cast<T*>(JS_GetInstancePrivate(rq.cx, thisobj, jsClass, nullptr));
if (value == nullptr && !JS_IsExceptionPending(rq.cx))
JS_ReportError(rq.cx, "Private data of the given object is null!");
return value;
}
@ -345,18 +362,17 @@ public:
* If an error occurs, GetPrivate will report it with the according stack.
*/
template <typename T>
static T* GetPrivate(JSContext* cx, JS::CallArgs& callArgs, JSClass* jsClass)
static T* GetPrivate(const Request& rq, JS::CallArgs& callArgs, JSClass* jsClass)
{
JSAutoRequest rq(cx);
if (!callArgs.thisv().isObject())
{
JS_ReportError(cx, "Cannot retrieve private JS class data because from a non-object value!");
JS_ReportError(rq.cx, "Cannot retrieve private JS class data because from a non-object value!");
return nullptr;
}
JS::RootedObject thisObj(cx, &callArgs.thisv().toObject());
T* value = static_cast<T*>(JS_GetInstancePrivate(cx, thisObj, jsClass, &callArgs));
if (value == nullptr && !JS_IsExceptionPending(cx))
JS_ReportError(cx, "Private data of the given object is null!");
JS::RootedObject thisObj(rq.cx, &callArgs.thisv().toObject());
T* value = static_cast<T*>(JS_GetInstancePrivate(rq.cx, thisObj, jsClass, &callArgs));
if (value == nullptr && !JS_IsExceptionPending(rq.cx))
JS_ReportError(rq.cx, "Private data of the given object is null!");
return value;
}
@ -369,7 +385,7 @@ public:
* because "conversions" from JS::HandleValue to JS::MutableHandleValue are unusual and should not happen "by accident".
*/
template <typename T>
static void AssignOrToJSVal(JSContext* cx, JS::MutableHandleValue handle, const T& a);
static void AssignOrToJSVal(const Request& rq, JS::MutableHandleValue handle, const T& a);
/**
* The same as AssignOrToJSVal, but also allows JS::Value for T.
@ -379,9 +395,9 @@ public:
* "unrooted" version of AssignOrToJSVal.
*/
template <typename T>
static void AssignOrToJSValUnrooted(JSContext* cx, JS::MutableHandleValue handle, const T& a)
static void AssignOrToJSValUnrooted(const Request& rq, JS::MutableHandleValue handle, const T& a)
{
AssignOrToJSVal(cx, handle, a);
AssignOrToJSVal(rq, handle, a);
}
/**
@ -390,23 +406,19 @@ public:
* other types.
*/
template <typename T>
static T AssignOrFromJSVal(JSContext* cx, const JS::HandleValue& val, bool& ret);
static T AssignOrFromJSVal(const Request& rq, const JS::HandleValue& val, bool& ret);
private:
/**
* Careful, the CreateObject_ helpers avoid creation of the JSAutoRequest!
*/
static bool CreateObject_(JSContext* cx, JS::MutableHandleObject obj);
static bool CreateObject_(const Request& rq, JS::MutableHandleObject obj);
template<typename T, typename... Args>
static bool CreateObject_(JSContext* cx, JS::MutableHandleObject obj, const char* propertyName, const T& propertyValue, Args const&... args)
static bool CreateObject_(const Request& rq, JS::MutableHandleObject obj, const char* propertyName, const T& propertyValue, Args const&... args)
{
// JSAutoRequest is the responsibility of the caller
JS::RootedValue val(cx);
AssignOrToJSVal(cx, &val, propertyValue);
JS::RootedValue val(rq.cx);
AssignOrToJSVal(rq, &val, propertyValue);
return CreateObject_(cx, obj, args...) && JS_DefineProperty(cx, obj, propertyName, val, JSPROP_ENUMERATE);
return CreateObject_(rq, obj, args...) && JS_DefineProperty(rq.cx, obj, propertyName, val, JSPROP_ENUMERATE);
}
bool CallFunction_(JS::HandleValue val, const char* name, JS::HandleValueArray argv, JS::MutableHandleValue ret) const;
@ -418,7 +430,7 @@ private:
bool SetPropertyInt_(JS::HandleValue obj, int name, JS::HandleValue value, bool constant, bool enumerate) const;
bool GetProperty_(JS::HandleValue obj, const char* name, JS::MutableHandleValue out) const;
bool GetPropertyInt_(JS::HandleValue obj, int name, JS::MutableHandleValue value) const;
static bool IsExceptionPending(JSContext* cx);
static bool IsExceptionPending(const Request& rq);
struct CustomType
{
@ -472,51 +484,51 @@ public:
#include "NativeWrapperDefns.h"
template<typename T>
inline void ScriptInterface::AssignOrToJSVal(JSContext* cx, JS::MutableHandleValue handle, const T& a)
inline void ScriptInterface::AssignOrToJSVal(const Request& rq, JS::MutableHandleValue handle, const T& a)
{
ToJSVal(cx, handle, a);
ToJSVal(rq, handle, a);
}
template<>
inline void ScriptInterface::AssignOrToJSVal<JS::PersistentRootedValue>(JSContext* UNUSED(cx), JS::MutableHandleValue handle, const JS::PersistentRootedValue& a)
inline void ScriptInterface::AssignOrToJSVal<JS::PersistentRootedValue>(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::PersistentRootedValue& a)
{
handle.set(a);
}
template<>
inline void ScriptInterface::AssignOrToJSVal<JS::Heap<JS::Value> >(JSContext* UNUSED(cx), JS::MutableHandleValue handle, const JS::Heap<JS::Value>& a)
inline void ScriptInterface::AssignOrToJSVal<JS::Heap<JS::Value> >(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::Heap<JS::Value>& a)
{
handle.set(a);
}
template<>
inline void ScriptInterface::AssignOrToJSVal<JS::RootedValue>(JSContext* UNUSED(cx), JS::MutableHandleValue handle, const JS::RootedValue& a)
inline void ScriptInterface::AssignOrToJSVal<JS::RootedValue>(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::RootedValue& a)
{
handle.set(a);
}
template <>
inline void ScriptInterface::AssignOrToJSVal<JS::HandleValue>(JSContext* UNUSED(cx), JS::MutableHandleValue handle, const JS::HandleValue& a)
inline void ScriptInterface::AssignOrToJSVal<JS::HandleValue>(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::HandleValue& a)
{
handle.set(a);
}
template <>
inline void ScriptInterface::AssignOrToJSValUnrooted<JS::Value>(JSContext* UNUSED(cx), JS::MutableHandleValue handle, const JS::Value& a)
inline void ScriptInterface::AssignOrToJSValUnrooted<JS::Value>(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::Value& a)
{
handle.set(a);
}
template<typename T>
inline T ScriptInterface::AssignOrFromJSVal(JSContext* cx, const JS::HandleValue& val, bool& ret)
inline T ScriptInterface::AssignOrFromJSVal(const Request& rq, const JS::HandleValue& val, bool& ret)
{
T retVal;
ret = FromJSVal(cx, val, retVal);
ret = FromJSVal(rq, val, retVal);
return retVal;
}
template<>
inline JS::HandleValue ScriptInterface::AssignOrFromJSVal<JS::HandleValue>(JSContext* UNUSED(cx), const JS::HandleValue& val, bool& ret)
inline JS::HandleValue ScriptInterface::AssignOrFromJSVal<JS::HandleValue>(const Request& UNUSED(rq), const JS::HandleValue& val, bool& ret)
{
ret = true;
return val;
@ -525,58 +537,57 @@ inline JS::HandleValue ScriptInterface::AssignOrFromJSVal<JS::HandleValue>(JSCon
template<typename T>
bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace, bool constant, bool enumerate)
{
JSAutoRequest rq(GetContext());
JS::RootedValue val(GetContext());
AssignOrToJSVal(GetContext(), &val, value);
Request rq(this);
JS::RootedValue val(rq.cx);
AssignOrToJSVal(rq, &val, value);
return SetGlobal_(name, val, replace, constant, enumerate);
}
template<typename T>
bool ScriptInterface::SetProperty(JS::HandleValue obj, const char* name, const T& value, bool constant, bool enumerate) const
{
JSAutoRequest rq(GetContext());
JS::RootedValue val(GetContext());
AssignOrToJSVal(GetContext(), &val, value);
Request rq(this);
JS::RootedValue val(rq.cx);
AssignOrToJSVal(rq, &val, value);
return SetProperty_(obj, name, val, constant, enumerate);
}
template<typename T>
bool ScriptInterface::SetProperty(JS::HandleValue obj, const wchar_t* name, const T& value, bool constant, bool enumerate) const
{
JSAutoRequest rq(GetContext());
JS::RootedValue val(GetContext());
AssignOrToJSVal(GetContext(), &val, value);
Request rq(this);
JS::RootedValue val(rq.cx);
AssignOrToJSVal(rq, &val, value);
return SetProperty_(obj, name, val, constant, enumerate);
}
template<typename T>
bool ScriptInterface::SetPropertyInt(JS::HandleValue obj, int name, const T& value, bool constant, bool enumerate) const
{
JSAutoRequest rq(GetContext());
JS::RootedValue val(GetContext());
AssignOrToJSVal(GetContext(), &val, value);
Request rq(this);
JS::RootedValue val(rq.cx);
AssignOrToJSVal(rq, &val, value);
return SetPropertyInt_(obj, name, val, constant, enumerate);
}
template<typename T>
bool ScriptInterface::GetProperty(JS::HandleValue obj, const char* name, T& out) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue val(cx);
Request rq(this);
JS::RootedValue val(rq.cx);
if (!GetProperty_(obj, name, &val))
return false;
return FromJSVal(cx, val, out);
return FromJSVal(rq, val, out);
}
template<typename T>
bool ScriptInterface::GetPropertyInt(JS::HandleValue obj, int name, T& out) const
{
JSAutoRequest rq(GetContext());
JS::RootedValue val(GetContext());
Request rq(this);
JS::RootedValue val(rq.cx);
if (!GetPropertyInt_(obj, name, &val))
return false;
return FromJSVal(GetContext(), val, out);
return FromJSVal(rq, val, out);
}
template<typename CHAR>
@ -590,11 +601,11 @@ bool ScriptInterface::Eval(const CHAR* code, JS::MutableHandleValue ret) const
template<typename T, typename CHAR>
bool ScriptInterface::Eval(const CHAR* code, T& ret) const
{
JSAutoRequest rq(GetContext());
JS::RootedValue rval(GetContext());
Request rq(this);
JS::RootedValue rval(rq.cx);
if (!Eval_(code, &rval))
return false;
return FromJSVal(GetContext(), rval, ret);
return FromJSVal(rq, rval, ret);
}
#endif // INCLUDED_SCRIPTINTERFACE

View File

@ -35,16 +35,15 @@ class TestScriptConversions : public CxxTest::TestSuite
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
TS_ASSERT(script.LoadGlobalScripts());
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
JS::RootedValue v1(cx);
ScriptInterface::ToJSVal(cx, &v1, value);
JS::RootedValue v1(rq.cx);
ScriptInterface::ToJSVal(rq, &v1, value);
// 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(cx, script.GetGlobalObject());
JS::RootedValue global(rq.cx, script.GetGlobalObject());
TS_ASSERT(script.CallFunction(global, "uneval", source, v1));
TS_ASSERT_STR_EQUALS(source, expected);
@ -55,21 +54,20 @@ class TestScriptConversions : public CxxTest::TestSuite
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
TS_ASSERT(script.LoadGlobalScripts());
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
JS::RootedValue v1(cx);
ScriptInterface::ToJSVal(cx, &v1, value);
JS::RootedValue v1(rq.cx);
ScriptInterface::ToJSVal(rq, &v1, value);
std::string source;
JS::RootedValue global(cx, script.GetGlobalObject());
JS::RootedValue global(rq.cx, script.GetGlobalObject());
TS_ASSERT(script.CallFunction(global, "uneval", source, v1));
if (expected)
TS_ASSERT_STR_EQUALS(source, expected);
T v2 = T();
TS_ASSERT(ScriptInterface::FromJSVal(cx, v1, v2));
TS_ASSERT(ScriptInterface::FromJSVal(rq, v1, v2));
TS_ASSERT_EQUALS(value, v2);
}
@ -78,22 +76,21 @@ class TestScriptConversions : public CxxTest::TestSuite
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
TS_ASSERT(script.LoadGlobalScripts());
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
JS::RootedValue v1(cx);
ScriptInterface::ToJSVal(cx, &v1, v);
JS::RootedValue u1(cx);
ScriptInterface::ToJSVal(cx, &u1, u);
JS::RootedValue v1(rq.cx);
ScriptInterface::ToJSVal(rq, &v1, v);
JS::RootedValue u1(rq.cx);
ScriptInterface::ToJSVal(rq, &u1, u);
T r;
JS::RootedValue r1(cx);
JS::RootedValue r1(rq.cx);
TS_ASSERT(script.CallFunction(u1, func.c_str(), r, v1));
ScriptInterface::ToJSVal(cx, &r1, r);
ScriptInterface::ToJSVal(rq, &r1, r);
std::string source;
JS::RootedValue global(cx, script.GetGlobalObject());
JS::RootedValue global(rq.cx, script.GetGlobalObject());
TS_ASSERT(script.CallFunction(global, "uneval", source, r1));
TS_ASSERT_STR_EQUALS(source, expected);
@ -172,26 +169,25 @@ public:
void test_integers()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
// using new uninitialized variables each time to be sure the test doesn't succeeed if ToJSVal doesn't touch the value at all.
JS::RootedValue val0(cx), val1(cx), val2(cx), val3(cx), val4(cx), val5(cx), val6(cx), val7(cx), val8(cx);
ScriptInterface::ToJSVal<i32>(cx, &val0, 0);
ScriptInterface::ToJSVal<i32>(cx, &val1, JSVAL_INT_MAX - 1);
ScriptInterface::ToJSVal<i32>(cx, &val2, JSVAL_INT_MAX);
ScriptInterface::ToJSVal<i32>(cx, &val3, JSVAL_INT_MIN + 1);
ScriptInterface::ToJSVal<i32>(cx, &val4, -(i64)2147483648u); // JSVAL_INT_MIN
JS::RootedValue val0(rq.cx), val1(rq.cx), val2(rq.cx), val3(rq.cx), val4(rq.cx), val5(rq.cx), val6(rq.cx), val7(rq.cx), val8(rq.cx);
ScriptInterface::ToJSVal<i32>(rq, &val0, 0);
ScriptInterface::ToJSVal<i32>(rq, &val1, JSVAL_INT_MAX - 1);
ScriptInterface::ToJSVal<i32>(rq, &val2, JSVAL_INT_MAX);
ScriptInterface::ToJSVal<i32>(rq, &val3, JSVAL_INT_MIN + 1);
ScriptInterface::ToJSVal<i32>(rq, &val4, -(i64)2147483648u); // JSVAL_INT_MIN
TS_ASSERT(val0.isInt32());
TS_ASSERT(val1.isInt32());
TS_ASSERT(val2.isInt32());
TS_ASSERT(val3.isInt32());
TS_ASSERT(val4.isInt32());
ScriptInterface::ToJSVal<u32>(cx, &val5, 0);
ScriptInterface::ToJSVal<u32>(cx, &val6, 2147483646u); // JSVAL_INT_MAX-1
ScriptInterface::ToJSVal<u32>(cx, &val7, 2147483647u); // JSVAL_INT_MAX
ScriptInterface::ToJSVal<u32>(cx, &val8, 2147483648u); // JSVAL_INT_MAX+1
ScriptInterface::ToJSVal<u32>(rq, &val5, 0);
ScriptInterface::ToJSVal<u32>(rq, &val6, 2147483646u); // JSVAL_INT_MAX-1
ScriptInterface::ToJSVal<u32>(rq, &val7, 2147483647u); // JSVAL_INT_MAX
ScriptInterface::ToJSVal<u32>(rq, &val8, 2147483648u); // JSVAL_INT_MAX+1
TS_ASSERT(val5.isInt32());
TS_ASSERT(val6.isInt32());
TS_ASSERT(val7.isInt32());
@ -205,13 +201,12 @@ public:
convert_to<float>(std::numeric_limits<float>::quiet_NaN(), "NaN"); // can't use roundtrip since nan != nan
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
float f = 0;
JS::RootedValue testNANVal(cx);
ScriptInterface::ToJSVal(cx, &testNANVal, NAN);
TS_ASSERT(ScriptInterface::FromJSVal(cx, testNANVal, f));
JS::RootedValue testNANVal(rq.cx);
ScriptInterface::ToJSVal(rq, &testNANVal, NAN);
TS_ASSERT(ScriptInterface::FromJSVal(rq, testNANVal, f));
TS_ASSERT(isnan(f));
}
@ -257,22 +252,21 @@ public:
// Fancier conversion: we store UTF8 and get UTF16 and vice-versa
ScriptInterface script("Test", "Test", g_ScriptRuntime);
TS_ASSERT(script.LoadGlobalScripts());
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
std::string in_utf8("éè!§$-aezi134900°°©©¢¢ÇÇ‘{¶«¡Ç’[å»ÛÁØ");
std::wstring in_utf16(L"éè!§$-aezi134900°°©©¢¢ÇÇ‘{¶«¡Ç’[å»ÛÁØ");
JS::RootedValue v1(cx);
ScriptInterface::ToJSVal(cx, &v1, in_utf8);
JS::RootedValue v1(rq.cx);
ScriptInterface::ToJSVal(rq, &v1, in_utf8);
std::wstring test_out_utf16;
TS_ASSERT(ScriptInterface::FromJSVal(cx, v1, test_out_utf16));
TS_ASSERT(ScriptInterface::FromJSVal(rq, v1, test_out_utf16));
TS_ASSERT_EQUALS(test_out_utf16, in_utf16);
JS::RootedValue v2(cx);
ScriptInterface::ToJSVal(cx, &v2, in_utf16);
JS::RootedValue v2(rq.cx);
ScriptInterface::ToJSVal(rq, &v2, in_utf16);
std::string test_out_utf8;
TS_ASSERT(ScriptInterface::FromJSVal(cx, v2, test_out_utf8));
TS_ASSERT(ScriptInterface::FromJSVal(rq, v2, test_out_utf8));
TS_ASSERT_EQUALS(test_out_utf8, in_utf8);
}
};

View File

@ -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
@ -65,16 +65,14 @@ public:
ScriptInterface script1("Test", "Test", g_ScriptRuntime);
ScriptInterface script2("Test", "Test", g_ScriptRuntime);
JSContext* cx1 = script1.GetContext();
JSAutoRequest rq1(cx1);
JS::RootedValue obj1(cx1);
ScriptInterface::Request rq1(script1);
JS::RootedValue obj1(rq1.cx);
TS_ASSERT(script1.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", &obj1));
{
JSContext* cx2 = script2.GetContext();
JSAutoRequest rq2(cx2);
ScriptInterface::Request rq2(script2);
JS::RootedValue obj2(cx2, script2.CloneValueFromOtherContext(script1, obj1));
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherContext(script1, obj1));
std::string source;
TS_ASSERT(script2.CallFunction(obj2, "toSource", source));
@ -88,17 +86,15 @@ public:
ScriptInterface script1("Test", "Test", g_ScriptRuntime);
ScriptInterface script2("Test", "Test", g_ScriptRuntime);
JSContext* cx1 = script1.GetContext();
JSAutoRequest rq1(cx1);
ScriptInterface::Request rq1(script1);
JS::RootedValue obj1(cx1);
JS::RootedValue obj1(rq1.cx);
TS_ASSERT(script1.Eval("var s = '?'; var v = ({get x() { return 123 }, 'y': {'w':{get z() { delete v.y; delete v.n; v = null; s += s; return 4 }}}, 'n': 100}); v", &obj1));
{
JSContext* cx2 = script2.GetContext();
JSAutoRequest rq2(cx2);
ScriptInterface::Request rq2(script2);
JS::RootedValue obj2(cx2, script2.CloneValueFromOtherContext(script1, obj1));
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherContext(script1, obj1));
std::string source;
TS_ASSERT(script2.CallFunction(obj2, "toSource", source));
@ -111,21 +107,19 @@ public:
ScriptInterface script1("Test", "Test", g_ScriptRuntime);
ScriptInterface script2("Test", "Test", g_ScriptRuntime);
JSContext* cx1 = script1.GetContext();
JSAutoRequest rq1(cx1);
ScriptInterface::Request rq1(script1);
JS::RootedValue obj1(cx1);
JS::RootedValue obj1(rq1.cx);
TS_ASSERT(script1.Eval("var x = []; x[0] = x; ({'a': x, 'b': x})", &obj1));
{
JSContext* cx2 = script2.GetContext();
JSAutoRequest rq(cx2);
JS::RootedValue obj2(cx2, script2.CloneValueFromOtherContext(script1, obj1));
ScriptInterface::Request rq2(script2);
JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherContext(script1, obj1));
// Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0]
JS::RootedValue prop_a(cx2);
JS::RootedValue prop_b(cx2);
JS::RootedValue prop_x1(cx2);
JS::RootedValue prop_a(rq2.cx);
JS::RootedValue prop_b(rq2.cx);
JS::RootedValue prop_x1(rq2.cx);
TS_ASSERT(script2.GetProperty(obj2, "a", &prop_a));
TS_ASSERT(script2.GetProperty(obj2, "b", &prop_b));
TS_ASSERT(prop_a.isObject());
@ -144,11 +138,10 @@ public:
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
JS::RootedValue val(cx);
JS::RootedValue out(cx);
JS::RootedValue val(rq.cx);
JS::RootedValue out(rq.cx);
TS_ASSERT(script.Eval("({ "
"'0':0,"
"inc:function() { this[0]++; return this[0]; }, "
@ -157,7 +150,7 @@ public:
"})"
, &val));
JS::RootedValue nbrVal(cx, JS::NumberValue(3));
JS::RootedValue nbrVal(rq.cx, JS::NumberValue(3));
int nbr = 0;
// CallFunctionVoid JS::RootedValue& parameter overload
@ -166,7 +159,7 @@ public:
// CallFunction JS::RootedValue* out parameter overload
script.CallFunction(val, "inc", &out);
ScriptInterface::FromJSVal(cx, out, nbr);
ScriptInterface::FromJSVal(rq, out, nbr);
TS_ASSERT_EQUALS(4, nbr);
// CallFunction const JS::RootedValue& parameter overload
@ -176,13 +169,13 @@ public:
// GetProperty JS::RootedValue* overload
nbr = 0;
script.GetProperty(val, "0", &out);
ScriptInterface::FromJSVal(cx, out, nbr);
ScriptInterface::FromJSVal(rq, out, nbr);
TS_ASSERT_EQUALS(nbr, 7);
// GetPropertyInt JS::RootedValue* overload
nbr = 0;
script.GetPropertyInt(val, 0, &out);
ScriptInterface::FromJSVal(cx, out, nbr);
ScriptInterface::FromJSVal(rq, out, nbr);
TS_ASSERT_EQUALS(nbr, 7);
handle_templates_test(script, val, &out, nbrVal);
@ -190,6 +183,8 @@ public:
void handle_templates_test(const ScriptInterface& script, JS::HandleValue val, JS::MutableHandleValue out, JS::HandleValue nbrVal)
{
ScriptInterface::Request rq(script);
int nbr = 0;
// CallFunctionVoid JS::HandleValue parameter overload
@ -198,7 +193,7 @@ public:
// CallFunction JS::MutableHandleValue out parameter overload
script.CallFunction(val, "inc", out);
ScriptInterface::FromJSVal(script.GetContext(), out, nbr);
ScriptInterface::FromJSVal(rq, out, nbr);
TS_ASSERT_EQUALS(4, nbr);
// CallFunction const JS::HandleValue& parameter overload
@ -208,13 +203,13 @@ public:
// GetProperty JS::MutableHandleValue overload
nbr = 0;
script.GetProperty(val, "0", out);
ScriptInterface::FromJSVal(script.GetContext(), out, nbr);
ScriptInterface::FromJSVal(rq, out, nbr);
TS_ASSERT_EQUALS(nbr, 7);
// GetPropertyInt JS::MutableHandleValue overload
nbr = 0;
script.GetPropertyInt(val, 0, out);
ScriptInterface::FromJSVal(script.GetContext(), out, nbr);
ScriptInterface::FromJSVal(rq, out, nbr);
TS_ASSERT_EQUALS(nbr, 7);
}
@ -241,11 +236,10 @@ public:
void test_json()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
std::string input = "({'x':1,'z':[2,'3\\u263A\\ud800'],\"y\":true})";
JS::RootedValue val(cx);
JS::RootedValue val(rq.cx);
TS_ASSERT(script.Eval(input.c_str(), &val));
std::string stringified = script.StringifyJSON(&val);
@ -260,8 +254,7 @@ public:
void test_function_override()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
TS_ASSERT(script.Eval(
"function f() { return 1; }"
@ -270,11 +263,11 @@ public:
"})(f);"
));
JS::RootedValue out(cx);
JS::RootedValue out(rq.cx);
TS_ASSERT(script.Eval("f()", &out));
int outNbr = 0;
ScriptInterface::FromJSVal(cx, out, outNbr);
ScriptInterface::FromJSVal(rq, out, outNbr);
TS_ASSERT_EQUALS(2, outNbr);
}
};

View File

@ -167,18 +167,15 @@ public:
static std::vector<SimulationCommand> CloneCommandsFromOtherContext(const ScriptInterface& oldScript, const ScriptInterface& newScript,
const std::vector<SimulationCommand>& commands)
{
JSContext* cxOld = oldScript.GetContext();
JSAutoRequest rqOld(cxOld);
std::vector<SimulationCommand> newCommands;
newCommands.reserve(commands.size());
ScriptInterface::Request rqNew(newScript);
for (const SimulationCommand& command : commands)
{
JSContext* cxNew = newScript.GetContext();
JSAutoRequest rqNew(cxNew);
JS::RootedValue tmpCommand(cxNew, newScript.CloneValueFromOtherContext(oldScript, command.data));
JS::RootedValue tmpCommand(rqNew.cx, newScript.CloneValueFromOtherContext(oldScript, command.data));
newScript.FreezeObject(tmpCommand, true);
SimulationCommand cmd(command.player, cxNew, tmpCommand);
SimulationCommand cmd(command.player, rqNew.cx, tmpCommand);
newCommands.emplace_back(std::move(cmd));
}
return newCommands;
@ -424,9 +421,8 @@ void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
// Load the trigger scripts after we have loaded the simulation.
{
JSContext* cx2 = m_SecondaryComponentManager->GetScriptInterface().GetContext();
JSAutoRequest rq2(cx2);
JS::RootedValue mapSettingsCloned(cx2,
ScriptInterface::Request rq2(m_SecondaryComponentManager->GetScriptInterface());
JS::RootedValue mapSettingsCloned(rq2.cx,
m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherContext(
scriptInterface, m_MapSettings));
ENSURE(LoadTriggerScripts(*m_SecondaryComponentManager, mapSettingsCloned, m_SecondaryLoadedScripts));
@ -737,20 +733,18 @@ ScriptInterface& CSimulation2::GetScriptInterface() const
void CSimulation2::PreInitGame()
{
JSContext* cx = GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject());
ScriptInterface::Request rq(GetScriptInterface());
JS::RootedValue global(rq.cx, GetScriptInterface().GetGlobalObject());
GetScriptInterface().CallFunctionVoid(global, "PreInitGame");
}
void CSimulation2::InitGame()
{
JSContext* cx = GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject());
ScriptInterface::Request rq(GetScriptInterface());
JS::RootedValue global(rq.cx, GetScriptInterface().GetGlobalObject());
JS::RootedValue settings(cx);
JS::RootedValue tmpInitAttributes(cx, GetInitAttributes());
JS::RootedValue settings(rq.cx);
JS::RootedValue tmpInitAttributes(rq.cx, GetInitAttributes());
GetScriptInterface().GetProperty(tmpInitAttributes, "settings", &settings);
GetScriptInterface().CallFunctionVoid(global, "InitGame", settings);
@ -845,18 +839,16 @@ void CSimulation2::GetMapSettings(JS::MutableHandleValue ret)
void CSimulation2::LoadPlayerSettings(bool newPlayers)
{
JSContext* cx = GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject());
ScriptInterface::Request rq(GetScriptInterface());
JS::RootedValue global(rq.cx, GetScriptInterface().GetGlobalObject());
GetScriptInterface().CallFunctionVoid(global, "LoadPlayerSettings", m->m_MapSettings, newPlayers);
}
void CSimulation2::LoadMapSettings()
{
JSContext* cx = GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(GetScriptInterface());
JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject());
JS::RootedValue global(rq.cx, GetScriptInterface().GetGlobalObject());
// Initialize here instead of in Update()
GetScriptInterface().CallFunctionVoid(global, "LoadMapSettings", m->m_MapSettings);
@ -990,14 +982,13 @@ std::string CSimulation2::GetMapSizes()
std::string CSimulation2::GetAIData()
{
const ScriptInterface& scriptInterface = GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue aiData(cx, ICmpAIManager::GetAIs(scriptInterface));
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue aiData(rq.cx, ICmpAIManager::GetAIs(scriptInterface));
// Build single JSON string with array of AI data
JS::RootedValue ais(cx);
JS::RootedValue ais(rq.cx);
if (!ScriptInterface::CreateObject(cx, &ais, "AIData", aiData))
if (!ScriptInterface::CreateObject(rq, &ais, "AIData", aiData))
return std::string();
return scriptInterface.StringifyJSON(&ais);

View File

@ -96,11 +96,10 @@ private:
if (!m_Worker.LoadScripts(m_AIName))
return false;
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
OsPath path = L"simulation/ai/" + m_AIName + L"/data.json";
JS::RootedValue metadata(cx);
JS::RootedValue metadata(rq.cx);
m_Worker.LoadMetadata(path, &metadata);
if (metadata.isUndefined())
{
@ -111,9 +110,9 @@ private:
// Get the constructor name from the metadata
std::string moduleName;
std::string constructor;
JS::RootedValue objectWithConstructor(cx); // object that should contain the constructor function
JS::RootedValue global(cx, m_ScriptInterface->GetGlobalObject());
JS::RootedValue ctor(cx);
JS::RootedValue objectWithConstructor(rq.cx); // object that should contain the constructor function
JS::RootedValue global(rq.cx, m_ScriptInterface->GetGlobalObject());
JS::RootedValue ctor(rq.cx);
if (!m_ScriptInterface->HasProperty(metadata, "moduleName"))
{
LOGERROR("Failed to create AI player: %s: missing 'moduleName'", path.string8());
@ -145,9 +144,9 @@ private:
m_ScriptInterface->GetProperty(metadata, "useShared", m_UseSharedComponent);
// Set up the data to pass as the constructor argument
JS::RootedValue settings(cx);
JS::RootedValue settings(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&settings,
"player", m_Player,
"difficulty", m_Difficulty,
@ -159,7 +158,7 @@ private:
m_ScriptInterface->SetProperty(settings, "templates", m_Worker.m_EntityTemplates, false);
}
JS::AutoValueVector argv(cx);
JS::AutoValueVector argv(rq.cx);
argv.append(settings.get());
m_ScriptInterface->CallConstructor(ctor, argv, &m_Obj);
@ -313,18 +312,17 @@ public:
{
ENSURE(pCxPrivate->pCBData);
CAIWorker* self = static_cast<CAIWorker*> (pCxPrivate->pCBData);
JSContext* cx(self->m_ScriptInterface->GetContext());
JSAutoRequest rq(cx);
ScriptInterface::Request rq(self->m_ScriptInterface);
CFixedVector2D pos, goalPos;
std::vector<CFixedVector2D> waypoints;
JS::RootedValue retVal(cx);
JS::RootedValue retVal(rq.cx);
self->m_ScriptInterface->FromJSVal<CFixedVector2D>(cx, position, pos);
self->m_ScriptInterface->FromJSVal<CFixedVector2D>(cx, goal, goalPos);
self->m_ScriptInterface->FromJSVal<CFixedVector2D>(rq, position, pos);
self->m_ScriptInterface->FromJSVal<CFixedVector2D>(rq, goal, goalPos);
self->ComputePath(pos, goalPos, passClass, waypoints);
self->m_ScriptInterface->ToJSVal<std::vector<CFixedVector2D> >(cx, &retVal, waypoints);
self->m_ScriptInterface->ToJSVal<std::vector<CFixedVector2D> >(rq, &retVal, waypoints);
return retVal;
}
@ -404,8 +402,7 @@ public:
bool TryLoadSharedComponent()
{
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
// we don't need to load it.
if (!m_HasSharedComponent)
@ -424,9 +421,9 @@ public:
// Constructor name is SharedScript, it's in the module API3
// TODO: Hardcoding this is bad, we need a smarter way.
JS::RootedValue AIModule(cx);
JS::RootedValue global(cx, m_ScriptInterface->GetGlobalObject());
JS::RootedValue ctor(cx);
JS::RootedValue AIModule(rq.cx);
JS::RootedValue global(rq.cx, m_ScriptInterface->GetGlobalObject());
JS::RootedValue ctor(rq.cx);
if (!m_ScriptInterface->GetProperty(global, "API3", &AIModule) || AIModule.isUndefined())
{
LOGERROR("Failed to create shared AI component: %s: can't find module '%s'", path.string8(), "API3");
@ -441,26 +438,26 @@ public:
}
// Set up the data to pass as the constructor argument
JS::RootedValue playersID(cx);
ScriptInterface::CreateObject(cx, &playersID);
JS::RootedValue playersID(rq.cx);
ScriptInterface::CreateObject(rq, &playersID);
for (size_t i = 0; i < m_Players.size(); ++i)
{
JS::RootedValue val(cx);
m_ScriptInterface->ToJSVal(cx, &val, m_Players[i]->m_Player);
JS::RootedValue val(rq.cx);
m_ScriptInterface->ToJSVal(rq, &val, m_Players[i]->m_Player);
m_ScriptInterface->SetPropertyInt(playersID, i, val, true);
}
ENSURE(m_HasLoadedEntityTemplates);
JS::RootedValue settings(cx);
JS::RootedValue settings(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&settings,
"players", playersID,
"templates", m_EntityTemplates);
JS::AutoValueVector argv(cx);
JS::AutoValueVector argv(rq.cx);
argv.append(settings);
m_ScriptInterface->CallConstructor(ctor, argv, &m_SharedAIObj);
@ -494,13 +491,12 @@ public:
// this will be run last by InitGame.js, passing the full game representation.
// For now it will run for the shared Component.
// This is NOT run during deserialization.
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
JS::RootedValue state(cx);
JS::RootedValue state(rq.cx);
m_ScriptInterface->ReadStructuredClone(gameState, &state);
ScriptInterface::ToJSVal(cx, &m_PassabilityMapVal, passabilityMap);
ScriptInterface::ToJSVal(cx, &m_TerritoryMapVal, territoryMap);
ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, passabilityMap);
ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, territoryMap);
m_PassabilityMap = passabilityMap;
m_NonPathfindingPassClasses = nonPathfindingPassClassMasks;
@ -549,21 +545,19 @@ public:
m_HierarchicalPathfinder.Update(&m_PassabilityMap, dirtinessGrid);
}
JSContext* cx = m_ScriptInterface->GetContext();
ScriptInterface::Request rq(m_ScriptInterface);
if (dimensionChange || justDeserialized)
ScriptInterface::ToJSVal(cx, &m_PassabilityMapVal, m_PassabilityMap);
ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, m_PassabilityMap);
else
{
// Avoid a useless memory reallocation followed by a garbage collection.
JSAutoRequest rq(cx);
JS::RootedObject mapObj(cx, &m_PassabilityMapVal.toObject());
JS::RootedValue mapData(cx);
ENSURE(JS_GetProperty(cx, mapObj, "data", &mapData));
JS::RootedObject dataObj(cx, &mapData.toObject());
JS::RootedObject mapObj(rq.cx, &m_PassabilityMapVal.toObject());
JS::RootedValue mapData(rq.cx);
ENSURE(JS_GetProperty(rq.cx, mapObj, "data", &mapData));
JS::RootedObject dataObj(rq.cx, &mapData.toObject());
u32 length = 0;
ENSURE(JS_GetArrayLength(cx, dataObj, &length));
ENSURE(JS_GetArrayLength(rq.cx, dataObj, &length));
u32 nbytes = (u32)(length * sizeof(NavcellData));
bool sharedMemory;
@ -579,21 +573,19 @@ public:
m_TerritoryMap = territoryMap;
JSContext* cx = m_ScriptInterface->GetContext();
ScriptInterface::Request rq(m_ScriptInterface);
if (dimensionChange)
ScriptInterface::ToJSVal(cx, &m_TerritoryMapVal, m_TerritoryMap);
ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, m_TerritoryMap);
else
{
// Avoid a useless memory reallocation followed by a garbage collection.
JSAutoRequest rq(cx);
JS::RootedObject mapObj(cx, &m_TerritoryMapVal.toObject());
JS::RootedValue mapData(cx);
ENSURE(JS_GetProperty(cx, mapObj, "data", &mapData));
JS::RootedObject dataObj(cx, &mapData.toObject());
JS::RootedObject mapObj(rq.cx, &m_TerritoryMapVal.toObject());
JS::RootedValue mapData(rq.cx);
ENSURE(JS_GetProperty(rq.cx, mapObj, "data", &mapData));
JS::RootedObject dataObj(rq.cx, &mapData.toObject());
u32 length = 0;
ENSURE(JS_GetArrayLength(cx, dataObj, &length));
ENSURE(JS_GetArrayLength(rq.cx, dataObj, &length));
u32 nbytes = (u32)(length * sizeof(u8));
bool sharedMemory;
@ -631,17 +623,16 @@ public:
void LoadEntityTemplates(const std::vector<std::pair<std::string, const CParamNode*> >& templates)
{
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
m_HasLoadedEntityTemplates = true;
ScriptInterface::CreateObject(cx, &m_EntityTemplates);
ScriptInterface::CreateObject(rq, &m_EntityTemplates);
JS::RootedValue val(cx);
JS::RootedValue val(rq.cx);
for (size_t i = 0; i < templates.size(); ++i)
{
templates[i].second->ToJSVal(cx, false, &val);
templates[i].second->ToJSVal(rq, false, &val);
m_ScriptInterface->SetProperty(m_EntityTemplates, templates[i].first.c_str(), val, true);
}
}
@ -668,8 +659,7 @@ public:
if (m_Players.empty())
return;
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
std::stringstream rngStream;
rngStream << m_RNG;
@ -680,7 +670,7 @@ public:
serializer.Bool("useSharedScript", m_HasSharedComponent);
if (m_HasSharedComponent)
{
JS::RootedValue sharedData(cx);
JS::RootedValue sharedData(rq.cx);
if (!m_ScriptInterface->CallFunction(m_SharedAIObj, "Serialize", &sharedData))
LOGERROR("AI shared script Serialize call failed");
serializer.ScriptVal("sharedData", &sharedData);
@ -695,7 +685,7 @@ public:
serializer.NumberU32_Unbounded("num commands", (u32)m_Players[i]->m_Commands.size());
for (size_t j = 0; j < m_Players[i]->m_Commands.size(); ++j)
{
JS::RootedValue val(cx);
JS::RootedValue val(rq.cx);
m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j], &val);
serializer.ScriptVal("command", &val);
}
@ -703,7 +693,7 @@ public:
bool hasCustomSerialize = m_ScriptInterface->HasProperty(m_Players[i]->m_Obj, "Serialize");
if (hasCustomSerialize)
{
JS::RootedValue scriptData(cx);
JS::RootedValue scriptData(rq.cx);
if (!m_ScriptInterface->CallFunction(m_Players[i]->m_Obj, "Serialize", &scriptData))
LOGERROR("AI script Serialize call failed");
serializer.ScriptVal("data", &scriptData);
@ -731,8 +721,7 @@ public:
if (numAis == 0)
return;
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
ENSURE(m_CommandsComputed); // deserializing while we're still actively computing would be bad
@ -750,7 +739,7 @@ public:
if (m_HasSharedComponent)
{
TryLoadSharedComponent();
JS::RootedValue sharedData(cx);
JS::RootedValue sharedData(rq.cx);
deserializer.ScriptVal("sharedData", &sharedData);
if (!m_ScriptInterface->CallFunctionVoid(m_SharedAIObj, "Deserialize", sharedData))
LOGERROR("AI shared script Deserialize call failed");
@ -774,7 +763,7 @@ public:
m_Players.back()->m_Commands.reserve(numCommands);
for (size_t j = 0; j < numCommands; ++j)
{
JS::RootedValue val(cx);
JS::RootedValue val(rq.cx);
deserializer.ScriptVal("command", &val);
m_Players.back()->m_Commands.push_back(m_ScriptInterface->WriteStructuredClone(val));
}
@ -782,7 +771,7 @@ public:
bool hasCustomDeserialize = m_ScriptInterface->HasProperty(m_Players.back()->m_Obj, "Deserialize");
if (hasCustomDeserialize)
{
JS::RootedValue scriptData(cx);
JS::RootedValue scriptData(rq.cx);
deserializer.ScriptVal("data", &scriptData);
if (m_Players[i]->m_UseSharedComponent)
{
@ -844,9 +833,8 @@ private:
void PerformComputation()
{
// Deserialize the game state, to pass to the AI's HandleMessage
JSContext* cx = m_ScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue state(cx);
ScriptInterface::Request rq(m_ScriptInterface);
JS::RootedValue state(rq.cx);
{
PROFILE3("AI compute read state");
m_ScriptInterface->ReadStructuredClone(m_GameState, &state);
@ -998,15 +986,14 @@ public:
virtual void RunGamestateInit()
{
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
CmpPtr<ICmpAIInterface> cmpAIInterface(GetSystemEntity());
ENSURE(cmpAIInterface);
// Get the game state from AIInterface
// We flush events from the initialization so we get a clean state now.
JS::RootedValue state(cx);
JS::RootedValue state(rq.cx);
cmpAIInterface->GetFullRepresentation(&state, true);
// Get the passability data
@ -1037,8 +1024,7 @@ public:
PROFILE("AI setup");
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
if (m_Worker.getPlayerSize() == 0)
return;
@ -1047,7 +1033,7 @@ public:
ENSURE(cmpAIInterface);
// Get the game state from AIInterface
JS::RootedValue state(cx);
JS::RootedValue state(rq.cx);
if (m_JustDeserialized)
cmpAIInterface->GetFullRepresentation(&state, false);
else
@ -1102,9 +1088,8 @@ public:
return;
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue clonedCommandVal(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue clonedCommandVal(rq.cx);
for (size_t i = 0; i < commands.size(); ++i)
{
@ -1154,11 +1139,10 @@ private:
return;
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue classesVal(cx);
ScriptInterface::CreateObject(cx, &classesVal);
JS::RootedValue classesVal(rq.cx);
ScriptInterface::CreateObject(rq, &classesVal);
std::map<std::string, pass_class_t> classes;
cmpPathfinder->GetPassabilityClasses(classes);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017 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
@ -51,8 +51,7 @@ public:
virtual void Serialize(ISerializer& serialize)
{
JSContext* cx = GetSimContext().GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(GetSimContext().GetScriptInterface());
serialize.NumberU32_Unbounded("num commands", (u32)m_LocalQueue.size());
for (size_t i = 0; i < m_LocalQueue.size(); ++i)
@ -64,36 +63,32 @@ public:
virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize)
{
JSContext* cx = GetSimContext().GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(GetSimContext().GetScriptInterface());
u32 numCmds;
deserialize.NumberU32_Unbounded("num commands", numCmds);
for (size_t i = 0; i < numCmds; ++i)
{
i32 player;
JS::RootedValue data(cx);
JS::RootedValue data(rq.cx);
deserialize.NumberI32_Unbounded("player", player);
deserialize.ScriptVal("data", &data);
m_LocalQueue.emplace_back(SimulationCommand(player, cx, data));
m_LocalQueue.emplace_back(SimulationCommand(player, rq.cx, data));
}
}
virtual void PushLocalCommand(player_id_t player, JS::HandleValue cmd)
{
JSContext* cx = GetSimContext().GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
m_LocalQueue.emplace_back(SimulationCommand(player, cx, cmd));
ScriptInterface::Request rq(GetSimContext().GetScriptInterface());
m_LocalQueue.emplace_back(SimulationCommand(player, rq.cx, cmd));
}
virtual void PostNetworkCommand(JS::HandleValue cmd1)
{
JSContext* cx = GetSimContext().GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(GetSimContext().GetScriptInterface());
// TODO: This is a workaround because we need to pass a MutableHandle to StringifyJSON.
JS::RootedValue cmd(cx, cmd1.get());
JS::RootedValue cmd(rq.cx, cmd1.get());
PROFILE2_EVENT("post net command");
PROFILE2_ATTR("command: %s", GetSimContext().GetScriptInterface().StringifyJSON(&cmd, false).c_str());
@ -106,10 +101,9 @@ public:
virtual void FlushTurn(const std::vector<SimulationCommand>& commands)
{
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue global(cx, scriptInterface.GetGlobalObject());
JS::RootedValue global(rq.cx, scriptInterface.GetGlobalObject());
std::vector<SimulationCommand> localCommands;
m_LocalQueue.swap(localCommands);

View File

@ -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
@ -41,9 +41,8 @@ public:
m_ScriptInterface(scriptInterface),
m_AIs(scriptInterface.GetJSRuntime())
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
m_AIs = JS_NewArrayObject(cx, 0);
ScriptInterface::Request rq(m_ScriptInterface);
m_AIs = JS_NewArrayObject(rq.cx, 0);
}
void Run()
@ -54,8 +53,7 @@ public:
static Status Callback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
{
GetAIsHelper* self = (GetAIsHelper*)cbData;
JSContext* cx = self->m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(self->m_ScriptInterface);
// Extract the 3rd component of the path (i.e. the directory after simulation/ai/)
fs::wpath components = pathname.string();
@ -63,16 +61,16 @@ public:
std::advance(it, 2);
std::wstring dirname = GetWstringFromWpath(*it);
JS::RootedValue ai(cx);
ScriptInterface::CreateObject(cx, &ai);
JS::RootedValue ai(rq.cx);
ScriptInterface::CreateObject(rq, &ai);
JS::RootedValue data(cx);
JS::RootedValue data(rq.cx);
self->m_ScriptInterface.ReadJSONFile(pathname, &data);
self->m_ScriptInterface.SetProperty(ai, "id", dirname, true);
self->m_ScriptInterface.SetProperty(ai, "data", data, true);
u32 length;
JS_GetArrayLength(cx, self->m_AIs, &length);
JS_SetElement(cx, self->m_AIs, length, ai);
JS_GetArrayLength(rq.cx, self->m_AIs, &length);
JS_SetElement(rq.cx, self->m_AIs, length, ai);
return INFO::OK;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017 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
@ -30,39 +30,38 @@ JS::Value ICmpFootprint::GetShape_wrapper() const
entity_pos_t size0, size1, height;
GetShape(shape, size0, size1, height);
JSContext* cx = GetSimContext().GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(GetSimContext().GetScriptInterface());
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx));
if (!obj)
return JS::UndefinedValue();
if (shape == CIRCLE)
{
JS::RootedValue ptype(cx);
JS::RootedValue pradius(cx);
JS::RootedValue pheight(cx);
ScriptInterface::ToJSVal<std::string>(cx, &ptype, "circle");
ScriptInterface::ToJSVal(cx, &pradius, size0);
ScriptInterface::ToJSVal(cx, &pheight, height);
JS_SetProperty(cx, obj, "type", ptype);
JS_SetProperty(cx, obj, "radius", pradius);
JS_SetProperty(cx, obj, "height", pheight);
JS::RootedValue ptype(rq.cx);
JS::RootedValue pradius(rq.cx);
JS::RootedValue pheight(rq.cx);
ScriptInterface::ToJSVal<std::string>(rq, &ptype, "circle");
ScriptInterface::ToJSVal(rq, &pradius, size0);
ScriptInterface::ToJSVal(rq, &pheight, height);
JS_SetProperty(rq.cx, obj, "type", ptype);
JS_SetProperty(rq.cx, obj, "radius", pradius);
JS_SetProperty(rq.cx, obj, "height", pheight);
}
else
{
JS::RootedValue ptype(cx);
JS::RootedValue pwidth(cx);
JS::RootedValue pdepth(cx);
JS::RootedValue pheight(cx);
ScriptInterface::ToJSVal<std::string>(cx, &ptype, "square");
ScriptInterface::ToJSVal(cx, &pwidth, size0);
ScriptInterface::ToJSVal(cx, &pdepth, size1);
ScriptInterface::ToJSVal(cx, &pheight, height);
JS_SetProperty(cx, obj, "type", ptype);
JS_SetProperty(cx, obj, "width", pwidth);
JS_SetProperty(cx, obj, "depth", pdepth);
JS_SetProperty(cx, obj, "height", pheight);
JS::RootedValue ptype(rq.cx);
JS::RootedValue pwidth(rq.cx);
JS::RootedValue pdepth(rq.cx);
JS::RootedValue pheight(rq.cx);
ScriptInterface::ToJSVal<std::string>(rq, &ptype, "square");
ScriptInterface::ToJSVal(rq, &pwidth, size0);
ScriptInterface::ToJSVal(rq, &pdepth, size1);
ScriptInterface::ToJSVal(rq, &pheight, height);
JS_SetProperty(rq.cx, obj, "type", ptype);
JS_SetProperty(rq.cx, obj, "width", pwidth);
JS_SetProperty(rq.cx, obj, "depth", pdepth);
JS_SetProperty(rq.cx, obj, "height", pheight);
}
return JS::ObjectValue(*obj);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017 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
@ -35,8 +35,6 @@ public:
void test_basic()
{
ComponentTestHelper test(g_ScriptRuntime);
JSContext* cx = test.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ICmpCinemaManager* cmp = test.Add<ICmpCinemaManager>(CID_CinemaManager, "", SYSTEM_ENTITY);

View File

@ -35,8 +35,7 @@ public:
void test_basic()
{
ComponentTestHelper test(g_ScriptRuntime);
JSContext* cx = test.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(test.GetScriptInterface());
std::vector<SimulationCommand> empty;
@ -44,7 +43,7 @@ public:
TS_ASSERT(test.GetScriptInterface().Eval("var cmds = []; function ProcessCommand(player, cmd) { cmds.push([player, cmd]); }"));
JS::RootedValue cmd(cx);
JS::RootedValue cmd(rq.cx);
TS_ASSERT(test.GetScriptInterface().Eval("([1,2,3])", &cmd));
cmp->PushLocalCommand(1, cmd);

View File

@ -31,12 +31,11 @@
#include "simulation2/system/IComponent.h"
#include "simulation2/system/ParamNode.h"
#define FAIL(msg) STMT(JS_ReportError(cx, msg); return false)
#define FAIL_VOID(msg) STMT(JS_ReportError(cx, msg); return)
#define FAIL(msg) STMT(JS_ReportError(rq.cx, msg); return false)
#define FAIL_VOID(msg) STMT(JS_ReportError(rq.cx, msg); return)
template<> void ScriptInterface::ToJSVal<IComponent*>(JSContext* cx, JS::MutableHandleValue ret, IComponent* const& val)
template<> void ScriptInterface::ToJSVal<IComponent*>(const Request& rq, JS::MutableHandleValue ret, IComponent* const& val)
{
JSAutoRequest rq(cx);
if (val == NULL)
{
ret.setNull();
@ -44,7 +43,7 @@ template<> void ScriptInterface::ToJSVal<IComponent*>(JSContext* cx, JS::Mutable
}
// If this is a scripted component, just return the JS object directly
JS::RootedValue instance(cx, val->GetJSInstance());
JS::RootedValue instance(rq.cx, val->GetJSInstance());
if (!instance.isNull())
{
ret.set(instance);
@ -53,8 +52,8 @@ template<> void ScriptInterface::ToJSVal<IComponent*>(JSContext* cx, JS::Mutable
// Otherwise we need to construct a wrapper object
// (TODO: cache wrapper objects?)
JS::RootedObject obj(cx);
if (!val->NewJSObject(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface, &obj))
JS::RootedObject obj(rq.cx);
if (!val->NewJSObject(*ScriptInterface::GetScriptInterfaceAndCBData(rq.cx)->pScriptInterface, &obj))
{
// Report as an error, since scripts really shouldn't try to use unscriptable interfaces
LOGERROR("IComponent does not have a scriptable interface");
@ -66,57 +65,54 @@ template<> void ScriptInterface::ToJSVal<IComponent*>(JSContext* cx, JS::Mutable
ret.setObject(*obj);
}
template<> void ScriptInterface::ToJSVal<CParamNode>(JSContext* cx, JS::MutableHandleValue ret, CParamNode const& val)
template<> void ScriptInterface::ToJSVal<CParamNode>(const Request& rq, JS::MutableHandleValue ret, CParamNode const& val)
{
JSAutoRequest rq(cx);
val.ToJSVal(cx, true, ret);
val.ToJSVal(rq, true, ret);
// Prevent modifications to the object, so that it's safe to share between
// components and to reconstruct on deserialization
if (ret.isObject())
{
JS::RootedObject obj(cx, &ret.toObject());
JS_DeepFreezeObject(cx, obj);
JS::RootedObject obj(rq.cx, &ret.toObject());
JS_DeepFreezeObject(rq.cx, obj);
}
}
template<> void ScriptInterface::ToJSVal<const CParamNode*>(JSContext* cx, JS::MutableHandleValue ret, const CParamNode* const& val)
template<> void ScriptInterface::ToJSVal<const CParamNode*>(const Request& rq, JS::MutableHandleValue ret, const CParamNode* const& val)
{
if (val)
ToJSVal(cx, ret, *val);
ToJSVal(rq, ret, *val);
else
ret.setUndefined();
}
template<> bool ScriptInterface::FromJSVal<CColor>(JSContext* cx, JS::HandleValue v, CColor& out)
template<> bool ScriptInterface::FromJSVal<CColor>(const Request& rq, JS::HandleValue v, CColor& out)
{
JSAutoRequest rq(cx);
if (!v.isObject())
FAIL("CColor has to be an object");
JS::RootedObject obj(cx, &v.toObject());
JS::RootedObject obj(rq.cx, &v.toObject());
JS::RootedValue r(cx);
JS::RootedValue g(cx);
JS::RootedValue b(cx);
JS::RootedValue a(cx);
if (!JS_GetProperty(cx, obj, "r", &r) || !FromJSVal(cx, r, out.r))
JS::RootedValue r(rq.cx);
JS::RootedValue g(rq.cx);
JS::RootedValue b(rq.cx);
JS::RootedValue a(rq.cx);
if (!JS_GetProperty(rq.cx, obj, "r", &r) || !FromJSVal(rq, r, out.r))
FAIL("Failed to get property CColor.r");
if (!JS_GetProperty(cx, obj, "g", &g) || !FromJSVal(cx, g, out.g))
if (!JS_GetProperty(rq.cx, obj, "g", &g) || !FromJSVal(rq, g, out.g))
FAIL("Failed to get property CColor.g");
if (!JS_GetProperty(cx, obj, "b", &b) || !FromJSVal(cx, b, out.b))
if (!JS_GetProperty(rq.cx, obj, "b", &b) || !FromJSVal(rq, b, out.b))
FAIL("Failed to get property CColor.b");
if (!JS_GetProperty(cx, obj, "a", &a) || !FromJSVal(cx, a, out.a))
if (!JS_GetProperty(rq.cx, obj, "a", &a) || !FromJSVal(rq, a, out.a))
FAIL("Failed to get property CColor.a");
return true;
}
template<> void ScriptInterface::ToJSVal<CColor>(JSContext* cx, JS::MutableHandleValue ret, CColor const& val)
template<> void ScriptInterface::ToJSVal<CColor>(const Request& rq, JS::MutableHandleValue ret, CColor const& val)
{
CreateObject(
cx,
rq,
ret,
"r", val.r,
"g", val.g,
@ -124,11 +120,10 @@ template<> void ScriptInterface::ToJSVal<CColor>(JSContext* cx, JS::MutableHandl
"a", val.a);
}
template<> bool ScriptInterface::FromJSVal<fixed>(JSContext* cx, JS::HandleValue v, fixed& out)
template<> bool ScriptInterface::FromJSVal<fixed>(const Request& rq, JS::HandleValue v, fixed& out)
{
JSAutoRequest rq(cx);
double ret;
if (!JS::ToNumber(cx, v, &ret))
if (!JS::ToNumber(rq.cx, v, &ret))
return false;
out = fixed::FromDouble(ret);
// double can precisely represent the full range of fixed, so this is a non-lossy conversion
@ -136,93 +131,86 @@ template<> bool ScriptInterface::FromJSVal<fixed>(JSContext* cx, JS::HandleValue
return true;
}
template<> void ScriptInterface::ToJSVal<fixed>(JSContext* UNUSED(cx), JS::MutableHandleValue ret, const fixed& val)
template<> void ScriptInterface::ToJSVal<fixed>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const fixed& val)
{
ret.set(JS::NumberValue(val.ToDouble()));
}
template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(JSContext* cx, JS::HandleValue v, CFixedVector3D& out)
template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(const Request& rq, JS::HandleValue v, CFixedVector3D& out)
{
if (!v.isObject())
return false; // TODO: report type error
JSAutoRequest rq(cx);
JS::RootedObject obj(cx, &v.toObject());
JS::RootedValue p(cx);
JS::RootedObject obj(rq.cx, &v.toObject());
JS::RootedValue p(rq.cx);
if (!JS_GetProperty(cx, obj, "x", &p)) return false; // TODO: report type errors
if (!FromJSVal(cx, p, out.X)) return false;
if (!JS_GetProperty(rq.cx, obj, "x", &p)) return false; // TODO: report type errors
if (!FromJSVal(rq, p, out.X)) return false;
if (!JS_GetProperty(cx, obj, "y", &p)) return false;
if (!FromJSVal(cx, p, out.Y)) return false;
if (!JS_GetProperty(rq.cx, obj, "y", &p)) return false;
if (!FromJSVal(rq, p, out.Y)) return false;
if (!JS_GetProperty(cx, obj, "z", &p)) return false;
if (!FromJSVal(cx, p, out.Z)) return false;
if (!JS_GetProperty(rq.cx, obj, "z", &p)) return false;
if (!FromJSVal(rq, p, out.Z)) return false;
return true;
}
template<> void ScriptInterface::ToJSVal<CFixedVector3D>(JSContext* cx, JS::MutableHandleValue ret, const CFixedVector3D& val)
template<> void ScriptInterface::ToJSVal<CFixedVector3D>(const Request& rq, JS::MutableHandleValue ret, const CFixedVector3D& val)
{
JSAutoRequest rq(cx);
ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(cx);
JS::RootedObject global(cx, &pCxPrivate->pScriptInterface->GetGlobalObject().toObject());
JS::RootedValue valueVector3D(cx);
if (!JS_GetProperty(cx, global, "Vector3D", &valueVector3D))
ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(rq.cx);
JS::RootedObject global(rq.cx, &pCxPrivate->pScriptInterface->GetGlobalObject().toObject());
JS::RootedValue valueVector3D(rq.cx);
if (!JS_GetProperty(rq.cx, global, "Vector3D", &valueVector3D))
FAIL_VOID("Failed to get Vector3D constructor");
JS::AutoValueArray<3> args(cx);
JS::AutoValueArray<3> args(rq.cx);
args[0].setNumber(val.X.ToDouble());
args[1].setNumber(val.Y.ToDouble());
args[2].setNumber(val.Z.ToDouble());
if (!JS::Construct(cx, valueVector3D, args, ret))
if (!JS::Construct(rq.cx, valueVector3D, args, ret))
FAIL_VOID("Failed to construct Vector3D object");
}
template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(JSContext* cx, JS::HandleValue v, CFixedVector2D& out)
template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(const Request& rq, JS::HandleValue v, CFixedVector2D& out)
{
JSAutoRequest rq(cx);
if (!v.isObject())
return false; // TODO: report type error
JS::RootedObject obj(cx, &v.toObject());
JS::RootedObject obj(rq.cx, &v.toObject());
JS::RootedValue p(cx);
JS::RootedValue p(rq.cx);
if (!JS_GetProperty(cx, obj, "x", &p)) return false; // TODO: report type errors
if (!FromJSVal(cx, p, out.X)) return false;
if (!JS_GetProperty(rq.cx, obj, "x", &p)) return false; // TODO: report type errors
if (!FromJSVal(rq, p, out.X)) return false;
if (!JS_GetProperty(cx, obj, "y", &p)) return false;
if (!FromJSVal(cx, p, out.Y)) return false;
if (!JS_GetProperty(rq.cx, obj, "y", &p)) return false;
if (!FromJSVal(rq, p, out.Y)) return false;
return true;
}
template<> void ScriptInterface::ToJSVal<CFixedVector2D>(JSContext* cx, JS::MutableHandleValue ret, const CFixedVector2D& val)
template<> void ScriptInterface::ToJSVal<CFixedVector2D>(const Request& rq, JS::MutableHandleValue ret, const CFixedVector2D& val)
{
JSAutoRequest rq(cx);
ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(cx);
JS::RootedObject global(cx, &pCxPrivate->pScriptInterface->GetGlobalObject().toObject());
JS::RootedValue valueVector2D(cx);
if (!JS_GetProperty(cx, global, "Vector2D", &valueVector2D))
ScriptInterface::CxPrivate* pCxPrivate = ScriptInterface::GetScriptInterfaceAndCBData(rq.cx);
JS::RootedObject global(rq.cx, &pCxPrivate->pScriptInterface->GetGlobalObject().toObject());
JS::RootedValue valueVector2D(rq.cx);
if (!JS_GetProperty(rq.cx, global, "Vector2D", &valueVector2D))
FAIL_VOID("Failed to get Vector2D constructor");
JS::AutoValueArray<2> args(cx);
JS::AutoValueArray<2> args(rq.cx);
args[0].setNumber(val.X.ToDouble());
args[1].setNumber(val.Y.ToDouble());
if (!JS::Construct(cx, valueVector2D, args, ret))
if (!JS::Construct(rq.cx, valueVector2D, args, ret))
FAIL_VOID("Failed to construct Vector2D object");
}
template<> void ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, JS::MutableHandleValue ret, const Grid<u8>& val)
template<> void ScriptInterface::ToJSVal<Grid<u8> >(const Request& rq, JS::MutableHandleValue ret, const Grid<u8>& val)
{
JSAutoRequest rq(cx);
u32 length = (u32)(val.m_W * val.m_H);
u32 nbytes = (u32)(length * sizeof(u8));
JS::RootedObject objArr(cx, JS_NewUint8Array(cx, length));
JS::RootedObject objArr(rq.cx, JS_NewUint8Array(rq.cx, length));
// Copy the array data and then remove the no-GC check to allow further changes to the JS data
{
JS::AutoCheckCannotGC nogc;
@ -230,21 +218,20 @@ template<> void ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, JS::MutableHa
memcpy((void*)JS_GetUint8ArrayData(objArr, &sharedMemory, nogc), val.m_Data, nbytes);
}
JS::RootedValue data(cx, JS::ObjectValue(*objArr));
JS::RootedValue data(rq.cx, JS::ObjectValue(*objArr));
CreateObject(
cx,
rq,
ret,
"width", val.m_W,
"height", val.m_H,
"data", data);
}
template<> void ScriptInterface::ToJSVal<Grid<u16> >(JSContext* cx, JS::MutableHandleValue ret, const Grid<u16>& val)
template<> void ScriptInterface::ToJSVal<Grid<u16> >(const Request& rq, JS::MutableHandleValue ret, const Grid<u16>& val)
{
JSAutoRequest rq(cx);
u32 length = (u32)(val.m_W * val.m_H);
u32 nbytes = (u32)(length * sizeof(u16));
JS::RootedObject objArr(cx, JS_NewUint16Array(cx, length));
JS::RootedObject objArr(rq.cx, JS_NewUint16Array(rq.cx, length));
// Copy the array data and then remove the no-GC check to allow further changes to the JS data
{
JS::AutoCheckCannotGC nogc;
@ -252,43 +239,41 @@ template<> void ScriptInterface::ToJSVal<Grid<u16> >(JSContext* cx, JS::MutableH
memcpy((void*)JS_GetUint16ArrayData(objArr, &sharedMemory, nogc), val.m_Data, nbytes);
}
JS::RootedValue data(cx, JS::ObjectValue(*objArr));
JS::RootedValue data(rq.cx, JS::ObjectValue(*objArr));
CreateObject(
cx,
rq,
ret,
"width", val.m_W,
"height", val.m_H,
"data", data);
}
template<> bool ScriptInterface::FromJSVal<TNSpline>(JSContext* cx, JS::HandleValue v, TNSpline& out)
template<> bool ScriptInterface::FromJSVal<TNSpline>(const Request& rq, JS::HandleValue v, TNSpline& out)
{
JSAutoRequest rq(cx);
if (!v.isObject())
FAIL("Argument must be an object");
JS::RootedObject obj(cx, &v.toObject());
JS::RootedObject obj(rq.cx, &v.toObject());
bool isArray;
if (!JS_IsArrayObject(cx, obj, &isArray) || !isArray)
if (!JS_IsArrayObject(rq.cx, obj, &isArray) || !isArray)
FAIL("Argument must be an array");
u32 numberOfNodes = 0;
if (!JS_GetArrayLength(cx, obj, &numberOfNodes))
if (!JS_GetArrayLength(rq.cx, obj, &numberOfNodes))
FAIL("Failed to get array length");
for (u32 i = 0; i < numberOfNodes; ++i)
{
JS::RootedValue node(cx);
if (!JS_GetElement(cx, obj, i, &node))
JS::RootedValue node(rq.cx);
if (!JS_GetElement(rq.cx, obj, i, &node))
FAIL("Failed to read array element");
fixed deltaTime;
if (!FromJSProperty(cx, node, "deltaTime", deltaTime))
if (!FromJSProperty(rq, node, "deltaTime", deltaTime))
FAIL("Failed to read Spline.deltaTime property");
CFixedVector3D position;
if (!FromJSProperty(cx, node, "position", position))
if (!FromJSProperty(rq, node, "position", position))
FAIL("Failed to read Spline.position property");
out.AddNode(position, CFixedVector3D(), deltaTime);
@ -300,38 +285,36 @@ template<> bool ScriptInterface::FromJSVal<TNSpline>(JSContext* cx, JS::HandleVa
return true;
}
template<> bool ScriptInterface::FromJSVal<CCinemaPath>(JSContext* cx, JS::HandleValue v, CCinemaPath& out)
template<> bool ScriptInterface::FromJSVal<CCinemaPath>(const Request& rq, JS::HandleValue v, CCinemaPath& out)
{
JSAutoRequest rq(cx);
if (!v.isObject())
FAIL("Argument must be an object");
JS::RootedObject obj(cx, &v.toObject());
JS::RootedObject obj(rq.cx, &v.toObject());
CCinemaData pathData;
TNSpline positionSpline, targetSpline;
if (!FromJSProperty(cx, v, "name", pathData.m_Name))
if (!FromJSProperty(rq, v, "name", pathData.m_Name))
FAIL("Failed to get CCinemaPath.name property");
if (!FromJSProperty(cx, v, "orientation", pathData.m_Orientation))
if (!FromJSProperty(rq, v, "orientation", pathData.m_Orientation))
FAIL("Failed to get CCinemaPath.orientation property");
if (!FromJSProperty(cx, v, "positionNodes", positionSpline))
if (!FromJSProperty(rq, v, "positionNodes", positionSpline))
FAIL("Failed to get CCinemaPath.positionNodes property");
if (pathData.m_Orientation == L"target" && !FromJSProperty(cx, v, "targetNodes", targetSpline))
if (pathData.m_Orientation == L"target" && !FromJSProperty(rq, v, "targetNodes", targetSpline))
FAIL("Failed to get CCinemaPath.targetNodes property");
// Other properties are not necessary to be defined
if (!FromJSProperty(cx, v, "timescale", pathData.m_Timescale))
if (!FromJSProperty(rq, v, "timescale", pathData.m_Timescale))
pathData.m_Timescale = fixed::FromInt(1);
if (!FromJSProperty(cx, v, "mode", pathData.m_Mode))
if (!FromJSProperty(rq, v, "mode", pathData.m_Mode))
pathData.m_Mode = L"ease_inout";
if (!FromJSProperty(cx, v, "style", pathData.m_Style))
if (!FromJSProperty(rq, v, "style", pathData.m_Style))
pathData.m_Style = L"default";
out = CCinemaPath(pathData, positionSpline, targetSpline);

View File

@ -50,10 +50,9 @@ JS::Value JSI_Simulation::GuiInterfaceCall(ScriptInterface::CxPrivate* pCxPrivat
if (!cmpGuiInterface)
return JS::UndefinedValue();
JSContext* cxSim = sim->GetScriptInterface().GetContext();
JSAutoRequest rqSim(cxSim);
JS::RootedValue arg(cxSim, sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), data));
JS::RootedValue ret(cxSim);
ScriptInterface::Request rqSim(sim->GetScriptInterface());
JS::RootedValue arg(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), data));
JS::RootedValue ret(rqSim.cx);
cmpGuiInterface->ScriptCall(g_Game->GetViewedPlayerID(), name, arg, &ret);
return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(sim->GetScriptInterface(), ret);
@ -71,9 +70,8 @@ void JSI_Simulation::PostNetworkCommand(ScriptInterface::CxPrivate* pCxPrivate,
if (!cmpCommandQueue)
return;
JSContext* cxSim = sim->GetScriptInterface().GetContext();
JSAutoRequest rqSim(cxSim);
JS::RootedValue cmd2(cxSim, sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), cmd));
ScriptInterface::Request rqSim(sim->GetScriptInterface());
JS::RootedValue cmd2(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherContext(*(pCxPrivate->pScriptInterface), cmd));
cmpCommandQueue->PostNetworkCommand(cmd2);
}
@ -126,10 +124,9 @@ JS::Value JSI_Simulation::GetEdgesOfStaticObstructionsOnScreenNearTo(ScriptInter
CSimulation2* sim = g_Game->GetSimulation2();
ENSURE(sim);
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue edgeList(cx);
ScriptInterface::CreateArray(cx, &edgeList);
ScriptInterface::Request rq(pCxPrivate);
JS::RootedValue edgeList(rq.cx);
ScriptInterface::CreateArray(rq, &edgeList);
int edgeListIndex = 0;
float distanceThreshold = 10.0f;
@ -163,7 +160,7 @@ JS::Value JSI_Simulation::GetEdgesOfStaticObstructionsOnScreenNearTo(ScriptInter
for (size_t i = 0; i < corners.size(); ++i)
{
JS::RootedValue edge(cx);
JS::RootedValue edge(rq.cx);
const CFixedVector2D& corner = corners[i];
const CFixedVector2D& nextCorner = corners[(i + 1) % corners.size()];
@ -175,7 +172,7 @@ JS::Value JSI_Simulation::GetEdgesOfStaticObstructionsOnScreenNearTo(ScriptInter
CFixedVector2D normal = -(nextCorner - corner).Perpendicular();
normal.Normalize();
ScriptInterface::CreateObject(
cx,
rq,
&edge,
"begin", corner,
"end", nextCorner,

View File

@ -21,34 +21,32 @@
#include "simulation2/MessageTypes.h"
#define TOJSVAL_SETUP() \
JSContext* cx = scriptInterface.GetContext(); \
JSAutoRequest rq(cx); \
JS::RootedObject obj(cx, JS_NewPlainObject(cx)); \
ScriptInterface::Request rq(scriptInterface); \
JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx)); \
if (!obj) \
return JS::UndefinedValue();
#define SET_MSG_PROPERTY(name) \
do { \
JS::RootedValue prop(cx);\
ScriptInterface::ToJSVal(cx, &prop, this->name); \
if (! JS_SetProperty(cx, obj, #name, prop)) \
JS::RootedValue prop(rq.cx);\
ScriptInterface::ToJSVal(rq, &prop, this->name); \
if (! JS_SetProperty(rq.cx, obj, #name, prop)) \
return JS::UndefinedValue(); \
} while (0);
#define FROMJSVAL_SETUP() \
JSContext* cx = scriptInterface.GetContext(); \
JSAutoRequest rq(cx); \
ScriptInterface::Request rq(scriptInterface); \
if (val.isPrimitive()) \
return NULL; \
JS::RootedObject obj(cx, &val.toObject()); \
JS::RootedValue prop(cx);
JS::RootedObject obj(rq.cx, &val.toObject()); \
JS::RootedValue prop(rq.cx);
#define GET_MSG_PROPERTY(type, name) \
type name; \
{ \
if (! JS_GetProperty(cx, obj, #name, &prop)) \
if (! JS_GetProperty(rq.cx, obj, #name, &prop)) \
return NULL; \
if (! ScriptInterface::FromJSVal(cx, prop, name)) \
if (! ScriptInterface::FromJSVal(rq, prop, name)) \
return NULL; \
}
@ -273,9 +271,9 @@ const std::array<const char*, CMessageMotionUpdate::UpdateType::LENGTH> CMessage
JS::Value CMessageMotionUpdate::ToJSVal(const ScriptInterface& scriptInterface) const
{
TOJSVAL_SETUP();
JS::RootedValue prop(cx);
JS::RootedValue prop(rq.cx);
if (!JS_SetProperty(cx, obj, UpdateTypeStr[updateType], JS::TrueHandleValue))
if (!JS_SetProperty(rq.cx, obj, UpdateTypeStr[updateType], JS::TrueHandleValue))
return JS::UndefinedValue();
return JS::ObjectValue(*obj);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2017 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
@ -26,8 +26,7 @@ CComponentTypeScript::CComponentTypeScript(const ScriptInterface& scriptInterfac
m_ScriptInterface(scriptInterface), m_Instance(scriptInterface.GetJSRuntime(), instance)
{
// Cache the property detection for efficiency
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
m_HasCustomSerialize = m_ScriptInterface.HasProperty(m_Instance, "Serialize");
m_HasCustomDeserialize = m_ScriptInterface.HasProperty(m_Instance, "Deserialize");
@ -35,7 +34,7 @@ CComponentTypeScript::CComponentTypeScript(const ScriptInterface& scriptInterfac
m_HasNullSerialize = false;
if (m_HasCustomSerialize)
{
JS::RootedValue val(cx);
JS::RootedValue val(rq.cx);
if (m_ScriptInterface.GetProperty(m_Instance, "Serialize", &val) && val.isNull())
m_HasNullSerialize = true;
}
@ -55,12 +54,11 @@ void CComponentTypeScript::Deinit()
void CComponentTypeScript::HandleMessage(const CMessage& msg, bool global)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
const char* name = global ? msg.GetScriptGlobalHandlerName() : msg.GetScriptHandlerName();
JS::RootedValue msgVal(cx, msg.ToJSValCached(m_ScriptInterface));
JS::RootedValue msgVal(rq.cx, msg.ToJSValCached(m_ScriptInterface));
if (!m_ScriptInterface.CallFunctionVoid(m_Instance, name, msgVal))
LOGERROR("Script message handler %s failed", name);
@ -72,14 +70,13 @@ void CComponentTypeScript::Serialize(ISerializer& serialize)
if (m_HasNullSerialize)
return;
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
// Support a custom "Serialize" function, which returns a new object that will be
// serialized instead of the component itself
if (m_HasCustomSerialize)
{
JS::RootedValue val(cx);
JS::RootedValue val(rq.cx);
if (!m_ScriptInterface.CallFunction(m_Instance, "Serialize", &val))
LOGERROR("Script Serialize call failed");
serialize.ScriptVal("object", &val);
@ -92,8 +89,7 @@ void CComponentTypeScript::Serialize(ISerializer& serialize)
void CComponentTypeScript::Deserialize(const CParamNode& paramNode, IDeserializer& deserialize, entity_id_t ent)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
m_ScriptInterface.SetProperty(m_Instance, "entity", (int)ent, true, false);
m_ScriptInterface.SetProperty(m_Instance, "template", paramNode, true, false);
@ -102,7 +98,7 @@ void CComponentTypeScript::Deserialize(const CParamNode& paramNode, IDeserialize
// instead of automatically adding the deserialized properties onto the object
if (m_HasCustomDeserialize)
{
JS::RootedValue val(cx);
JS::RootedValue val(rq.cx);
// If Serialize = null, we'll still call Deserialize but with undefined argument
if (!m_HasNullSerialize)

View File

@ -57,18 +57,16 @@ static u8 GetArrayType(js::Scalar::Type arrayType)
CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(const ScriptInterface& scriptInterface, ISerializer& serializer) :
m_ScriptInterface(scriptInterface), m_Serializer(serializer), m_ScriptBackrefsNext(0)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
m_ScriptBackrefSymbol.init(cx, JS::NewSymbol(cx, nullptr));
m_ScriptBackrefSymbol.init(rq.cx, JS::NewSymbol(rq.cx, nullptr));
}
void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
switch (JS_TypeOfValue(cx, val))
switch (JS_TypeOfValue(rq.cx, val))
{
case JSTYPE_VOID:
{
@ -88,7 +86,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
break;
}
JS::RootedObject obj(cx, &val.toObject());
JS::RootedObject obj(rq.cx, &val.toObject());
// If we've already serialized this object, just output a reference to it
i32 tag = GetScriptBackrefTag(obj);
@ -101,7 +99,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
// Arrays are special cases of Object
bool isArray;
if (JS_IsArrayObject(cx, obj, &isArray) && isArray)
if (JS_IsArrayObject(rq.cx, obj, &isArray) && isArray)
{
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_ARRAY);
// TODO: probably should have a more efficient storage format
@ -109,7 +107,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
// Arrays like [1, 2, ] have an 'undefined' at the end which is part of the
// length but seemingly isn't enumerated, so store the length explicitly
uint length = 0;
if (!JS_GetArrayLength(cx, obj, &length))
if (!JS_GetArrayLength(rq.cx, obj, &length))
throw PSERROR_Serialize_ScriptError("JS_GetArrayLength failed");
m_Serializer.NumberU32_Unbounded("array length", length);
}
@ -124,7 +122,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
bool sharedMemory;
// Now handle its array buffer
// this may be a backref, since ArrayBuffers can be shared by multiple views
JS::RootedValue bufferVal(cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(cx, obj, &sharedMemory)));
JS::RootedValue bufferVal(rq.cx, JS::ObjectValue(*JS_GetArrayBufferViewBuffer(rq.cx, obj, &sharedMemory)));
HandleScriptVal(bufferVal);
break;
}
@ -163,7 +161,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_NUMBER);
// Get primitive value
double d;
if (!JS::ToNumber(cx, val, &d))
if (!JS::ToNumber(rq.cx, val, &d))
throw PSERROR_Serialize_ScriptError("JS::ToNumber failed");
m_Serializer.NumberDouble_Unbounded("value", d);
break;
@ -173,7 +171,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
// Standard String object
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_STRING);
// Get primitive value
JS::RootedString str(cx, JS::ToString(cx, val));
JS::RootedString str(rq.cx, JS::ToString(rq.cx, val));
if (!str)
throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");
ScriptString("value", str);
@ -193,17 +191,17 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
else if (protokey == JSProto_Map)
{
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_MAP);
m_Serializer.NumberU32_Unbounded("map size", JS::MapSize(cx, obj));
m_Serializer.NumberU32_Unbounded("map size", JS::MapSize(rq.cx, obj));
JS::RootedValue keyValueIterator(cx);
if (!JS::MapEntries(cx, obj, &keyValueIterator))
JS::RootedValue keyValueIterator(rq.cx);
if (!JS::MapEntries(rq.cx, obj, &keyValueIterator))
throw PSERROR_Serialize_ScriptError("JS::MapEntries failed");
JS::ForOfIterator it(cx);
JS::ForOfIterator it(rq.cx);
if (!it.init(keyValueIterator))
throw PSERROR_Serialize_ScriptError("JS::ForOfIterator::init failed");
JS::RootedValue keyValuePair(cx);
JS::RootedValue keyValuePair(rq.cx);
bool done;
while (true)
{
@ -213,11 +211,11 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
if (done)
break;
JS::RootedObject keyValuePairObj(cx, &keyValuePair.toObject());
JS::RootedValue key(cx);
JS::RootedValue value(cx);
ENSURE(JS_GetElement(cx, keyValuePairObj, 0, &key));
ENSURE(JS_GetElement(cx, keyValuePairObj, 1, &value));
JS::RootedObject keyValuePairObj(rq.cx, &keyValuePair.toObject());
JS::RootedValue key(rq.cx);
JS::RootedValue value(rq.cx);
ENSURE(JS_GetElement(rq.cx, keyValuePairObj, 0, &key));
ENSURE(JS_GetElement(rq.cx, keyValuePairObj, 1, &value));
HandleScriptVal(key);
HandleScriptVal(value);
@ -236,12 +234,12 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT_SET);
m_Serializer.NumberU32_Unbounded("set size", setSize);
JS::RootedValue valueIterator(cx);
JS::RootedValue valueIterator(rq.cx);
m_ScriptInterface.CallFunction(val, "values", &valueIterator);
for (u32 i=0; i<setSize; ++i)
{
JS::RootedValue currentIterator(cx);
JS::RootedValue value(cx);
JS::RootedValue currentIterator(rq.cx);
JS::RootedValue value(rq.cx);
ENSURE(m_ScriptInterface.CallFunction(valueIterator, "next", &currentIterator));
m_ScriptInterface.GetProperty(currentIterator, "value", &value);
@ -260,36 +258,36 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
}
// Find all properties (ordered by insertion time)
JS::Rooted<JS::IdVector> ida(cx, JS::IdVector(cx));
if (!JS_Enumerate(cx, obj, &ida))
JS::Rooted<JS::IdVector> ida(rq.cx, JS::IdVector(rq.cx));
if (!JS_Enumerate(rq.cx, obj, &ida))
throw PSERROR_Serialize_ScriptError("JS_Enumerate failed");
m_Serializer.NumberU32_Unbounded("num props", (u32)ida.length());
for (size_t i = 0; i < ida.length(); ++i)
{
JS::RootedId id(cx, ida[i]);
JS::RootedId id(rq.cx, ida[i]);
JS::RootedValue idval(cx);
JS::RootedValue propval(cx);
JS::RootedValue idval(rq.cx);
JS::RootedValue propval(rq.cx);
// Forbid getters, which might delete values and mess things up.
JS::Rooted<JSPropertyDescriptor> desc(cx);
if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
JS::Rooted<JSPropertyDescriptor> desc(rq.cx);
if (!JS_GetPropertyDescriptorById(rq.cx, obj, id, &desc))
throw PSERROR_Serialize_ScriptError("JS_GetPropertyDescriptorById failed");
if (desc.hasGetterObject())
throw PSERROR_Serialize_ScriptError("Cannot serialize property getters");
// Get the property name as a string
if (!JS_IdToValue(cx, id, &idval))
if (!JS_IdToValue(rq.cx, id, &idval))
throw PSERROR_Serialize_ScriptError("JS_IdToValue failed");
JS::RootedString idstr(cx, JS::ToString(cx, idval));
JS::RootedString idstr(rq.cx, JS::ToString(rq.cx, idval));
if (!idstr)
throw PSERROR_Serialize_ScriptError("JS_ValueToString failed");
ScriptString("prop name", idstr);
if (!JS_GetPropertyById(cx, obj, id, &propval))
if (!JS_GetPropertyById(rq.cx, obj, id, &propval))
throw PSERROR_Serialize_ScriptError("JS_GetPropertyById failed");
HandleScriptVal(propval);
@ -301,17 +299,17 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
{
// We can't serialise functions, but we can at least name the offender (hopefully)
std::wstring funcname(L"(unnamed)");
JS::RootedFunction func(cx, JS_ValueToFunction(cx, val));
JS::RootedFunction func(rq.cx, JS_ValueToFunction(rq.cx, val));
if (func)
{
JS::RootedString string(cx, JS_GetFunctionId(func));
JS::RootedString string(rq.cx, JS_GetFunctionId(func));
if (string)
{
if (JS_StringHasLatin1Chars(string))
{
size_t length;
JS::AutoCheckCannotGC nogc;
const JS::Latin1Char* ch = JS_GetLatin1StringCharsAndLength(cx, nogc, string, &length);
const JS::Latin1Char* ch = JS_GetLatin1StringCharsAndLength(rq.cx, nogc, string, &length);
if (ch && length > 0)
funcname.assign(ch, ch + length);
}
@ -319,7 +317,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
{
size_t length;
JS::AutoCheckCannotGC nogc;
const char16_t* ch = JS_GetTwoByteStringCharsAndLength(cx, nogc, string, &length);
const char16_t* ch = JS_GetTwoByteStringCharsAndLength(rq.cx, nogc, string, &length);
if (ch && length > 0)
funcname.assign(ch, ch + length);
}
@ -332,7 +330,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
case JSTYPE_STRING:
{
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_STRING);
JS::RootedString stringVal(cx, val.toString());
JS::RootedString stringVal(rq.cx, val.toString());
ScriptString("string", stringVal);
break;
}
@ -377,8 +375,7 @@ void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
void CBinarySerializerScriptImpl::ScriptString(const char* name, JS::HandleString string)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
#if BYTE_ORDER != LITTLE_ENDIAN
#error TODO: probably need to convert JS strings to little-endian
@ -391,7 +388,7 @@ void CBinarySerializerScriptImpl::ScriptString(const char* name, JS::HandleStrin
m_Serializer.Bool("isLatin1", isLatin1);
if (isLatin1)
{
const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, string, &length);
const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(rq.cx, nogc, string, &length);
if (!chars)
throw PSERROR_Serialize_ScriptError("JS_GetLatin1StringCharsAndLength failed");
m_Serializer.NumberU32_Unbounded("string length", (u32)length);
@ -399,7 +396,7 @@ void CBinarySerializerScriptImpl::ScriptString(const char* name, JS::HandleStrin
}
else
{
const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, string, &length);
const char16_t* chars = JS_GetTwoByteStringCharsAndLength(rq.cx, nogc, string, &length);
if (!chars)
throw PSERROR_Serialize_ScriptError("JS_GetTwoByteStringCharsAndLength failed");
@ -418,27 +415,26 @@ i32 CBinarySerializerScriptImpl::GetScriptBackrefTag(JS::HandleObject obj)
// Tags are stored on the object. To avoid overwriting any existing property,
// they are saved as a uniquely-named, non-enumerable property (the serializer's unique symbol).
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
JS::RootedValue symbolValue(cx, JS::SymbolValue(m_ScriptBackrefSymbol));
JS::RootedId symbolId(cx);
ENSURE(JS_ValueToId(cx, symbolValue, &symbolId));
JS::RootedValue symbolValue(rq.cx, JS::SymbolValue(m_ScriptBackrefSymbol));
JS::RootedId symbolId(rq.cx);
ENSURE(JS_ValueToId(rq.cx, symbolValue, &symbolId));
JS::RootedValue tagValue(cx);
JS::RootedValue tagValue(rq.cx);
// If it was already there, return the tag
bool tagFound;
ENSURE(JS_HasPropertyById(cx, obj, symbolId, &tagFound));
ENSURE(JS_HasPropertyById(rq.cx, obj, symbolId, &tagFound));
if (tagFound)
{
ENSURE(JS_GetPropertyById(cx, obj, symbolId, &tagValue));
ENSURE(JS_GetPropertyById(rq.cx, obj, symbolId, &tagValue));
ENSURE(tagValue.isInt32());
return tagValue.toInt32();
}
tagValue = JS::Int32Value(m_ScriptBackrefsNext);
JS_SetPropertyById(cx, obj, symbolId, tagValue);
JS_SetPropertyById(rq.cx, obj, symbolId, tagValue);
++m_ScriptBackrefsNext;
// Return a non-tag number so callers know they need to serialize the object

View File

@ -112,8 +112,7 @@ void CStdDeserializer::GetScriptBackref(size_t tag, JS::MutableHandleObject ret)
JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject appendParent)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
uint8_t type;
NumberU8_Unbounded("type", type);
@ -128,7 +127,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
case SCRIPT_TYPE_ARRAY:
case SCRIPT_TYPE_OBJECT:
{
JS::RootedObject obj(cx);
JS::RootedObject obj(rq.cx);
if (appendParent)
{
obj.set(appendParent);
@ -137,11 +136,11 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
{
u32 length;
NumberU32_Unbounded("array length", length);
obj.set(JS_NewArrayObject(cx, length));
obj.set(JS_NewArrayObject(rq.cx, length));
}
else // SCRIPT_TYPE_OBJECT
{
obj.set(JS_NewPlainObject(cx));
obj.set(JS_NewPlainObject(rq.cx));
}
if (!obj)
@ -159,20 +158,20 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
{
std::vector<JS::Latin1Char> propname;
ReadStringLatin1("prop name", propname);
JS::RootedValue propval(cx, ReadScriptVal("prop value", nullptr));
JS::RootedValue propval(rq.cx, ReadScriptVal("prop value", nullptr));
utf16string prp(propname.begin(), propname.end());;
// TODO: Should ask upstream about getting a variant of JS_SetProperty with a length param.
if (!JS_SetUCProperty(cx, obj, (const char16_t*)prp.data(), prp.length(), propval))
if (!JS_SetUCProperty(rq.cx, obj, (const char16_t*)prp.data(), prp.length(), propval))
throw PSERROR_Deserialize_ScriptError();
}
else
{
utf16string propname;
ReadStringUTF16("prop name", propname);
JS::RootedValue propval(cx, ReadScriptVal("prop value", nullptr));
JS::RootedValue propval(rq.cx, ReadScriptVal("prop value", nullptr));
if (!JS_SetUCProperty(cx, obj, (const char16_t*)propname.data(), propname.length(), propval))
if (!JS_SetUCProperty(rq.cx, obj, (const char16_t*)propname.data(), propname.length(), propval))
throw PSERROR_Deserialize_ScriptError();
}
}
@ -181,7 +180,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
}
case SCRIPT_TYPE_STRING:
{
JS::RootedString str(cx);
JS::RootedString str(rq.cx);
ScriptString("string", &str);
return JS::StringValue(str);
}
@ -195,7 +194,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
{
double value;
NumberDouble_Unbounded("value", value);
JS::RootedValue rval(cx, JS::NumberValue(value));
JS::RootedValue rval(rq.cx, JS::NumberValue(value));
if (rval.isNull())
throw PSERROR_Deserialize_ScriptError("JS_NewNumberValue failed");
return rval;
@ -210,7 +209,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
{
i32 tag;
NumberI32("tag", tag, 0, JSVAL_INT_MAX);
JS::RootedObject obj(cx);
JS::RootedObject obj(rq.cx);
GetScriptBackref(tag, &obj);
if (!obj)
throw PSERROR_Deserialize_ScriptError("Invalid backref tag");
@ -220,13 +219,13 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
{
double value;
NumberDouble_Unbounded("value", value);
JS::RootedValue val(cx, JS::NumberValue(value));
JS::RootedValue val(rq.cx, JS::NumberValue(value));
JS::RootedObject ctorobj(cx);
if (!JS_GetClassObject(cx, JSProto_Number, &ctorobj))
JS::RootedObject ctorobj(rq.cx);
if (!JS_GetClassObject(rq.cx, JSProto_Number, &ctorobj))
throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
JS::RootedObject obj(cx, JS_New(cx, ctorobj, JS::HandleValueArray(val)));
JS::RootedObject obj(rq.cx, JS_New(rq.cx, ctorobj, JS::HandleValueArray(val)));
if (!obj)
throw PSERROR_Deserialize_ScriptError("JS_New failed");
AddScriptBackref(obj);
@ -234,17 +233,17 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
}
case SCRIPT_TYPE_OBJECT_STRING:
{
JS::RootedString str(cx);
JS::RootedString str(rq.cx);
ScriptString("value", &str);
if (!str)
throw PSERROR_Deserialize_ScriptError();
JS::RootedValue val(cx, JS::StringValue(str));
JS::RootedValue val(rq.cx, JS::StringValue(str));
JS::RootedObject ctorobj(cx);
if (!JS_GetClassObject(cx, JSProto_String, &ctorobj))
JS::RootedObject ctorobj(rq.cx);
if (!JS_GetClassObject(rq.cx, JSProto_String, &ctorobj))
throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
JS::RootedObject obj(cx, JS_New(cx, ctorobj, JS::HandleValueArray(val)));
JS::RootedObject obj(rq.cx, JS_New(rq.cx, ctorobj, JS::HandleValueArray(val)));
if (!obj)
throw PSERROR_Deserialize_ScriptError("JS_New failed");
AddScriptBackref(obj);
@ -254,13 +253,13 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
{
bool value;
Bool("value", value);
JS::RootedValue val(cx, JS::BooleanValue(value));
JS::RootedValue val(rq.cx, JS::BooleanValue(value));
JS::RootedObject ctorobj(cx);
if (!JS_GetClassObject(cx, JSProto_Boolean, &ctorobj))
JS::RootedObject ctorobj(rq.cx);
if (!JS_GetClassObject(rq.cx, JSProto_Boolean, &ctorobj))
throw PSERROR_Deserialize_ScriptError("JS_GetClassObject failed");
JS::RootedObject obj(cx, JS_New(cx, ctorobj, JS::HandleValueArray(val)));
JS::RootedObject obj(rq.cx, JS_New(rq.cx, ctorobj, JS::HandleValueArray(val)));
if (!obj)
throw PSERROR_Deserialize_ScriptError("JS_New failed");
AddScriptBackref(obj);
@ -275,47 +274,47 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
NumberU32_Unbounded("length", length);
// To match the serializer order, we reserve the typed array's backref tag here
JS::RootedObject arrayObj(cx);
JS::RootedObject arrayObj(rq.cx);
AddScriptBackref(arrayObj);
// Get buffer object
JS::RootedValue bufferVal(cx, ReadScriptVal("buffer", nullptr));
JS::RootedValue bufferVal(rq.cx, ReadScriptVal("buffer", nullptr));
if (!bufferVal.isObject())
throw PSERROR_Deserialize_ScriptError();
JS::RootedObject bufferObj(cx, &bufferVal.toObject());
JS::RootedObject bufferObj(rq.cx, &bufferVal.toObject());
if (!JS_IsArrayBufferObject(bufferObj))
throw PSERROR_Deserialize_ScriptError("js_IsArrayBuffer failed");
switch(arrayType)
{
case SCRIPT_TYPED_ARRAY_INT8:
arrayObj = JS_NewInt8ArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewInt8ArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
case SCRIPT_TYPED_ARRAY_UINT8:
arrayObj = JS_NewUint8ArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewUint8ArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
case SCRIPT_TYPED_ARRAY_INT16:
arrayObj = JS_NewInt16ArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewInt16ArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
case SCRIPT_TYPED_ARRAY_UINT16:
arrayObj = JS_NewUint16ArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewUint16ArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
case SCRIPT_TYPED_ARRAY_INT32:
arrayObj = JS_NewInt32ArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewInt32ArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
case SCRIPT_TYPED_ARRAY_UINT32:
arrayObj = JS_NewUint32ArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewUint32ArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
case SCRIPT_TYPED_ARRAY_FLOAT32:
arrayObj = JS_NewFloat32ArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewFloat32ArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
case SCRIPT_TYPED_ARRAY_FLOAT64:
arrayObj = JS_NewFloat64ArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewFloat64ArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
case SCRIPT_TYPED_ARRAY_UINT8_CLAMPED:
arrayObj = JS_NewUint8ClampedArrayWithBuffer(cx, bufferObj, byteOffset, length);
arrayObj = JS_NewUint8ClampedArrayWithBuffer(rq.cx, bufferObj, byteOffset, length);
break;
default:
throw PSERROR_Deserialize_ScriptError("Failed to deserialize unrecognized typed array view");
@ -336,14 +335,14 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
void* contents = malloc(length);
ENSURE(contents);
RawBytes("buffer data", (u8*)contents, length);
JS::RootedObject bufferObj(cx, JS_NewArrayBufferWithContents(cx, length, contents));
JS::RootedObject bufferObj(rq.cx, JS_NewArrayBufferWithContents(rq.cx, length, contents));
AddScriptBackref(bufferObj);
return JS::ObjectValue(*bufferObj);
}
case SCRIPT_TYPE_OBJECT_MAP:
{
JS::RootedObject obj(cx, JS::NewMapObject(cx));
JS::RootedObject obj(rq.cx, JS::NewMapObject(rq.cx));
AddScriptBackref(obj);
u32 mapSize;
@ -351,19 +350,19 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
for (u32 i=0; i<mapSize; ++i)
{
JS::RootedValue key(cx, ReadScriptVal("map key", nullptr));
JS::RootedValue value(cx, ReadScriptVal("map value", nullptr));
JS::MapSet(cx, obj, key, value);
JS::RootedValue key(rq.cx, ReadScriptVal("map key", nullptr));
JS::RootedValue value(rq.cx, ReadScriptVal("map value", nullptr));
JS::MapSet(rq.cx, obj, key, value);
}
return JS::ObjectValue(*obj);
}
case SCRIPT_TYPE_OBJECT_SET:
{
JS::RootedValue setVal(cx);
JS::RootedValue setVal(rq.cx);
m_ScriptInterface.Eval("(new Set())", &setVal);
JS::RootedObject setObj(cx, &setVal.toObject());
JS::RootedObject setObj(rq.cx, &setVal.toObject());
AddScriptBackref(setObj);
u32 setSize;
@ -371,7 +370,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleOb
for (u32 i=0; i<setSize; ++i)
{
JS::RootedValue value(cx, ReadScriptVal("set value", nullptr));
JS::RootedValue value(rq.cx, ReadScriptVal("set value", nullptr));
m_ScriptInterface.CallFunctionVoid(setVal, "add", value);
}
@ -406,8 +405,7 @@ void CStdDeserializer::ScriptString(const char* name, JS::MutableHandleString ou
#error TODO: probably need to convert JS strings from little-endian
#endif
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
bool isLatin1;
Bool("isLatin1", isLatin1);
@ -416,7 +414,7 @@ void CStdDeserializer::ScriptString(const char* name, JS::MutableHandleString ou
std::vector<JS::Latin1Char> str;
ReadStringLatin1(name, str);
out.set(JS_NewStringCopyN(cx, (const char*)str.data(), str.size()));
out.set(JS_NewStringCopyN(rq.cx, (const char*)str.data(), str.size()));
if (!out)
throw PSERROR_Deserialize_ScriptError("JS_NewStringCopyN failed");
}
@ -425,7 +423,7 @@ void CStdDeserializer::ScriptString(const char* name, JS::MutableHandleString ou
utf16string str;
ReadStringUTF16(name, str);
out.set(JS_NewUCStringCopyN(cx, (const char16_t*)str.data(), str.length()));
out.set(JS_NewUCStringCopyN(rq.cx, (const char16_t*)str.data(), str.length()));
if (!out)
throw PSERROR_Deserialize_ScriptError("JS_NewUCStringCopyN failed");
}
@ -438,12 +436,11 @@ void CStdDeserializer::ScriptVal(const char* name, JS::MutableHandleValue out)
void CStdDeserializer::ScriptObjectAppend(const char* name, JS::HandleValue objVal)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
if (!objVal.isObject())
throw PSERROR_Deserialize_ScriptError();
JS::RootedObject obj(cx, &objVal.toObject());
JS::RootedObject obj(rq.cx, &objVal.toObject());
ReadScriptVal(name, obj);
}

View File

@ -152,8 +152,7 @@ bool CComponentManager::LoadScript(const VfsPath& filename, bool hotload)
void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CxPrivate* pCxPrivate, int iid, const std::string& cname, JS::HandleValue ctor, bool reRegister, bool systemComponent)
{
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData);
JSContext* cx = componentManager->m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(componentManager->m_ScriptInterface);
// Find the C++ component that wraps the interface
int cidWrapper = componentManager->GetScriptWrapper(iid);
@ -231,7 +230,7 @@ void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CxP
mustReloadComponents = true;
}
JS::RootedValue protoVal(cx);
JS::RootedValue protoVal(rq.cx);
if (!componentManager->m_ScriptInterface.GetProperty(ctor, "prototype", &protoVal))
{
componentManager->m_ScriptInterface.ReportError("Failed to get property 'prototype'");
@ -255,7 +254,7 @@ void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CxP
ctWrapper.dealloc,
cname,
schema,
std::unique_ptr<JS::PersistentRootedValue>(new JS::PersistentRootedValue(cx, ctor))
std::unique_ptr<JS::PersistentRootedValue>(new JS::PersistentRootedValue(rq.cx, ctor))
};
componentManager->m_ComponentTypesById[cid] = std::move(ct);
@ -309,7 +308,7 @@ void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CxP
std::map<entity_id_t, IComponent*>::const_iterator eit = comps.begin();
for (; eit != comps.end(); ++eit)
{
JS::RootedValue instance(cx, eit->second->GetJSInstance());
JS::RootedValue instance(rq.cx, eit->second->GetJSInstance());
if (!instance.isNull())
componentManager->m_ScriptInterface.SetPrototype(instance, protoVal);
}
@ -730,8 +729,7 @@ void CComponentManager::AddSystemComponents(bool skipScriptedComponents, bool sk
IComponent* CComponentManager::ConstructComponent(CEntityHandle ent, ComponentTypeId cid)
{
JSContext* cx = m_ScriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_ScriptInterface);
std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(cid);
if (it == m_ComponentTypesById.end())
@ -754,7 +752,7 @@ IComponent* CComponentManager::ConstructComponent(CEntityHandle ent, ComponentTy
std::map<entity_id_t, IComponent*>& emap2 = m_ComponentsByTypeId[cid];
// If this is a scripted component, construct the appropriate JS object first
JS::RootedValue obj(cx);
JS::RootedValue obj(rq.cx);
if (ct.type == CT_Script)
{
m_ScriptInterface.CallConstructor(*ct.ctor, JS::HandleValueArray::empty(), &obj);

View File

@ -358,7 +358,7 @@ void CParamNode::ToXML(std::wostream& strm) const
}
}
void CParamNode::ToJSVal(JSContext* cx, bool cacheValue, JS::MutableHandleValue ret) const
void CParamNode::ToJSVal(const ScriptInterface::Request& rq, bool cacheValue, JS::MutableHandleValue ret) const
{
if (cacheValue && m_ScriptVal != NULL)
{
@ -366,15 +366,14 @@ void CParamNode::ToJSVal(JSContext* cx, bool cacheValue, JS::MutableHandleValue
return;
}
ConstructJSVal(cx, ret);
ConstructJSVal(rq, ret);
if (cacheValue)
m_ScriptVal.reset(new JS::PersistentRootedValue(cx, ret));
m_ScriptVal.reset(new JS::PersistentRootedValue(rq.cx, ret));
}
void CParamNode::ConstructJSVal(JSContext* cx, JS::MutableHandleValue ret) const
void CParamNode::ConstructJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue ret) const
{
JSAutoRequest rq(cx);
if (m_Childs.empty())
{
// Empty node - map to undefined
@ -386,7 +385,7 @@ void CParamNode::ConstructJSVal(JSContext* cx, JS::MutableHandleValue ret) const
// Just a string
utf16string text(m_Value.begin(), m_Value.end());
JS::RootedString str(cx, JS_AtomizeAndPinUCStringN(cx, reinterpret_cast<const char16_t*>(text.data()), text.length()));
JS::RootedString str(rq.cx, JS_AtomizeAndPinUCStringN(rq.cx, reinterpret_cast<const char16_t*>(text.data()), text.length()));
if (str)
{
ret.setString(str);
@ -399,18 +398,18 @@ void CParamNode::ConstructJSVal(JSContext* cx, JS::MutableHandleValue ret) const
// Got child nodes - convert this node into a hash-table-style object:
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx));
if (!obj)
{
ret.setUndefined();
return; // TODO: report error
}
JS::RootedValue childVal(cx);
JS::RootedValue childVal(rq.cx);
for (std::map<std::string, CParamNode>::const_iterator it = m_Childs.begin(); it != m_Childs.end(); ++it)
{
it->second.ConstructJSVal(cx, &childVal);
if (!JS_SetProperty(cx, obj, it->first.c_str(), childVal))
it->second.ConstructJSVal(rq, &childVal);
if (!JS_SetProperty(rq.cx, obj, it->first.c_str(), childVal))
{
ret.setUndefined();
return; // TODO: report error
@ -421,15 +420,15 @@ void CParamNode::ConstructJSVal(JSContext* cx, JS::MutableHandleValue ret) const
if (!m_Value.empty())
{
utf16string text(m_Value.begin(), m_Value.end());
JS::RootedString str(cx, JS_AtomizeAndPinUCStringN(cx, reinterpret_cast<const char16_t*>(text.data()), text.length()));
JS::RootedString str(rq.cx, JS_AtomizeAndPinUCStringN(rq.cx, reinterpret_cast<const char16_t*>(text.data()), text.length()));
if (!str)
{
ret.setUndefined();
return; // TODO: report error
}
JS::RootedValue childVal(cx, JS::StringValue(str));
if (!JS_SetProperty(cx, obj, "_string", childVal))
JS::RootedValue childVal(rq.cx, JS::StringValue(str));
if (!JS_SetProperty(rq.cx, obj, "_string", childVal))
{
ret.setUndefined();
return; // TODO: report error

View File

@ -22,7 +22,7 @@
#include "maths/Fixed.h"
#include "ps/CStrIntern.h"
#include "ps/Errors.h"
#include "scriptinterface/ScriptTypes.h"
#include "scriptinterface/ScriptInterface.h"
#include <map>
#include <set>
@ -248,7 +248,7 @@ public:
* The cache will be reset if *this* node is modified (e.g. by LoadXML),
* but *not* if any child nodes are modified (so don't do that).
*/
void ToJSVal(JSContext* cx, bool cacheValue, JS::MutableHandleValue ret) const;
void ToJSVal(const ScriptInterface::Request& rq, bool cacheValue, JS::MutableHandleValue ret) const;
/**
* Returns the names/nodes of the children of this node, ordered by name
@ -275,7 +275,7 @@ private:
void ResetScriptVal();
void ConstructJSVal(JSContext* cx, JS::MutableHandleValue ret) const;
void ConstructJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue ret) const;
std::wstring m_Value;
ChildrenMap m_Childs;

View File

@ -87,19 +87,18 @@ void CReplayTurnManager::NotifyFinishedUpdate(u32 turn)
LOGERROR("Replay out of sync on turn %d", turn);
const ScriptInterface& scriptInterface = m_Simulation2.GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::AutoValueVector paramData(cx);
JS::AutoValueVector paramData(rq.cx);
paramData.append(JS::NumberValue(turn));
JS::RootedValue hashVal(cx);
scriptInterface.ToJSVal(cx, &hashVal, hash);
JS::RootedValue hashVal(rq.cx);
scriptInterface.ToJSVal(rq, &hashVal, hash);
paramData.append(hashVal);
JS::RootedValue expectedHashVal(cx);
scriptInterface.ToJSVal(cx, &expectedHashVal, expectedHash);
JS::RootedValue expectedHashVal(rq.cx);
scriptInterface.ToJSVal(rq, &expectedHashVal, expectedHash);
paramData.append(expectedHashVal);
g_GUI->SendEventToAll(EventNameReplayOutOfSync, paramData);
@ -111,13 +110,12 @@ void CReplayTurnManager::DoTurn(u32 turn)
m_TurnLength = m_ReplayTurnLengths[turn];
JSContext* cx = m_Simulation2.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_Simulation2.GetScriptInterface());
// Simulate commands for that turn
for (const std::pair<player_id_t, std::string>& p : m_ReplayCommands[turn])
{
JS::RootedValue command(cx);
JS::RootedValue command(rq.cx);
m_Simulation2.GetScriptInterface().ParseJSON(p.second, &command);
AddCommand(m_ClientId, p.first, command, m_CurrentTurn + 1);
}

View File

@ -46,7 +46,7 @@ CTurnManager::CTurnManager(CSimulation2& simulation, u32 defaultTurnLength, int
: m_Simulation2(simulation), m_CurrentTurn(0), m_ReadyTurn(1), m_TurnLength(defaultTurnLength),
m_PlayerId(-1), m_ClientId(clientId), m_DeltaSimTime(0), m_HasSyncError(false), m_Replay(replay),
m_FinalTurn(std::numeric_limits<u32>::max()), m_TimeWarpNumTurns(0),
m_QuickSaveMetadata(m_Simulation2.GetScriptInterface().GetContext())
m_QuickSaveMetadata(m_Simulation2.GetScriptInterface().GetJSRuntime())
{
// When we are on turn n, we schedule new commands for n+2.
// We know that all other clients have finished scheduling commands for n (else we couldn't have got here).
@ -240,10 +240,8 @@ void CTurnManager::AddCommand(int client, int player, JS::HandleValue data, u32
m_Simulation2.GetScriptInterface().FreezeObject(data, true);
JSContext* cx = m_Simulation2.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
m_QueuedCommands[turn - (m_CurrentTurn+1)][client].emplace_back(player, cx, data);
ScriptInterface::Request rq(m_Simulation2.GetScriptInterface());
m_QueuedCommands[turn - (m_CurrentTurn+1)][client].emplace_back(player, rq.cx, data);
}
void CTurnManager::FinishedAllCommands(u32 turn, u32 turnLength)
@ -306,10 +304,9 @@ void CTurnManager::QuickSave(JS::HandleValue GUIMetadata)
m_QuickSaveState = stream.str();
JSContext* cx = m_Simulation2.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_Simulation2.GetScriptInterface());
if (JS_StructuredClone(cx, GUIMetadata, &m_QuickSaveMetadata, nullptr, nullptr))
if (JS_StructuredClone(rq.cx, GUIMetadata, &m_QuickSaveMetadata, nullptr, nullptr))
{
// Freeze state to ensure that consectuvie loads don't modify the state
m_Simulation2.GetScriptInterface().FreezeObject(m_QuickSaveMetadata, true);
@ -346,18 +343,17 @@ void CTurnManager::QuickLoad()
if (!g_GUI)
return;
JSContext* cx = m_Simulation2.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(m_Simulation2.GetScriptInterface());
// Provide a copy, so that GUI components don't have to clone to get mutable objects
JS::RootedValue quickSaveMetadataClone(cx);
if (!JS_StructuredClone(cx, m_QuickSaveMetadata, &quickSaveMetadataClone, nullptr, nullptr))
JS::RootedValue quickSaveMetadataClone(rq.cx);
if (!JS_StructuredClone(rq.cx, m_QuickSaveMetadata, &quickSaveMetadataClone, nullptr, nullptr))
{
LOGERROR("Failed to clone quicksave state!");
return;
}
JS::AutoValueArray<1> paramData(cx);
JS::AutoValueArray<1> paramData(rq.cx);
paramData[0].set(quickSaveMetadataClone);
g_GUI->SendEventToAll(EventNameSavegameLoaded, paramData);

View File

@ -99,26 +99,25 @@ public:
TS_ASSERT(tempMan != NULL);
tempMan->DisableValidation();
JSContext* cx = man.GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(man.GetScriptInterface());
// This is testing some bugs in the template JS object caching
const CParamNode* inherit1 = tempMan->LoadTemplate(ent2, "inherit1");
JS::RootedValue val(cx);
ScriptInterface::ToJSVal(cx, &val, inherit1);
JS::RootedValue val(rq.cx);
ScriptInterface::ToJSVal(rq, &val, inherit1);
TS_ASSERT_STR_EQUALS(man.GetScriptInterface().ToString(&val), "({Test1A:{'@a':\"a1\", '@b':\"b1\", '@c':\"c1\", d:\"d1\", e:\"e1\", f:\"f1\"}})");
const CParamNode* inherit2 = tempMan->LoadTemplate(ent2, "inherit2");
ScriptInterface::ToJSVal(cx, &val, inherit2);
ScriptInterface::ToJSVal(rq, &val, inherit2);
TS_ASSERT_STR_EQUALS(man.GetScriptInterface().ToString(&val), "({'@parent':\"inherit1\", Test1A:{'@a':\"a2\", '@b':\"b1\", '@c':\"c1\", d:\"d2\", e:\"e1\", f:\"f1\", g:\"g2\"}})");
const CParamNode* actor = tempMan->LoadTemplate(ent2, "actor|example1");
ScriptInterface::ToJSVal(cx, &val, &actor->GetChild("VisualActor"));
ScriptInterface::ToJSVal(rq, &val, &actor->GetChild("VisualActor"));
TS_ASSERT_STR_EQUALS(man.GetScriptInterface().ToString(&val), "({Actor:\"example1\", ActorOnly:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})");
const CParamNode* foundation = tempMan->LoadTemplate(ent2, "foundation|actor|example1");
ScriptInterface::ToJSVal(cx, &val, &foundation->GetChild("VisualActor"));
ScriptInterface::ToJSVal(rq, &val, &foundation->GetChild("VisualActor"));
TS_ASSERT_STR_EQUALS(man.GetScriptInterface().ToString(&val), "({Actor:\"example1\", ActorOnly:(void 0), Foundation:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})");
#define GET_FIRST_ELEMENT(n, templateName) \
@ -127,7 +126,7 @@ public:
{ \
if (it->first[0] == '@') \
continue; \
ScriptInterface::ToJSVal(cx, &val, it->second); \
ScriptInterface::ToJSVal(rq, &val, it->second); \
break; \
}

View File

@ -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
@ -292,10 +292,9 @@ public:
void helper_script_roundtrip(const char* msg, const char* input, const char* expected, size_t expstreamlen = 0, const char* expstream = NULL, const char* debug = NULL)
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
JS::RootedValue obj(cx);
JS::RootedValue obj(rq.cx);
TSM_ASSERT(msg, script.Eval(input, &obj));
if (debug)
@ -318,7 +317,7 @@ public:
CStdDeserializer deserialize(script, stream);
JS::RootedValue newobj(cx);
JS::RootedValue newobj(rq.cx);
deserialize.ScriptVal("script", &newobj);
// NOTE: Don't use good() here - it fails due to a bug in older libc++ versions
TSM_ASSERT(msg, !stream.bad() && !stream.fail());
@ -755,10 +754,9 @@ public:
void test_script_exceptions()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
JS::RootedValue obj(cx);
JS::RootedValue obj(rq.cx);
std::stringstream stream;
CStdSerializer serialize(script, stream);
@ -790,10 +788,9 @@ public:
const char* input = "var x = {}; for (var i=0;i<256;++i) x[i]=Math.pow(i, 2); x";
ScriptInterface script("Test", "Test", g_ScriptRuntime);
JSContext* cx = script.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(script);
JS::RootedValue obj(cx);
JS::RootedValue obj(rq.cx);
TS_ASSERT(script.Eval(input, &obj));
for (size_t i = 0; i < 256; ++i)
@ -805,7 +802,7 @@ public:
CStdDeserializer deserialize(script, stream);
JS::RootedValue newobj(cx);
JS::RootedValue newobj(rq.cx);
deserialize.ScriptVal("script", &newobj);
// NOTE: Don't use good() here - it fails due to a bug in older libc++ versions
TS_ASSERT(!stream.bad() && !stream.fail());

View File

@ -99,16 +99,15 @@ QUERYHANDLER(GenerateMap)
// Random map
const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
JS::RootedValue settings(cx);
JS::RootedValue settings(rq.cx);
scriptInterface.ParseJSON(*msg->settings, &settings);
scriptInterface.SetProperty(settings, "mapType", "random");
JS::RootedValue attrs(cx);
JS::RootedValue attrs(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&attrs,
"mapType", "random",
"script", *msg->filename,
@ -128,30 +127,29 @@ QUERYHANDLER(GenerateMap)
InitGame();
const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
// Set up 8-element array of empty objects to satisfy init
JS::RootedValue playerData(cx);
ScriptInterface::CreateArray(cx, &playerData);
JS::RootedValue playerData(rq.cx);
ScriptInterface::CreateArray(rq, &playerData);
for (int i = 0; i < 8; ++i)
{
JS::RootedValue player(cx);
ScriptInterface::CreateObject(cx, &player);
JS::RootedValue player(rq.cx);
ScriptInterface::CreateObject(rq, &player);
scriptInterface.SetPropertyInt(playerData, i, player);
}
JS::RootedValue settings(cx);
JS::RootedValue settings(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&settings,
"mapType", "scenario",
"PlayerData", playerData);
JS::RootedValue attrs(cx);
JS::RootedValue attrs(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&attrs,
"mapType", "scenario",
"map", "maps/scenarios/_default",
@ -168,17 +166,16 @@ MESSAGEHANDLER(LoadMap)
InitGame();
const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
ScriptInterface::Request rq(scriptInterface);
// Scenario
CStrW map = *msg->filename;
CStrW mapBase = map.BeforeLast(L".pmp"); // strip the file extension, if any
JS::RootedValue attrs(cx);
JS::RootedValue attrs(rq.cx);
ScriptInterface::CreateObject(
cx,
rq,
&attrs,
"mapType", "scenario",
"map", mapBase);