Index: ps/trunk/binaries/data/mods/_test.sim/simulation/components/error.js =================================================================== --- ps/trunk/binaries/data/mods/_test.sim/simulation/components/error.js +++ ps/trunk/binaries/data/mods/_test.sim/simulation/components/error.js @@ -1,11 +1,6 @@ function TestScript1A() {} -try { - Engine.RegisterComponentType(12345, "TestScript1A", TestScript1A); - Engine.TS_FAIL("Missed exception"); -} catch (e) { -// print("Caught exception: " + e + "\n"); -} +TS_ASSERT_EXCEPTION(() => { Engine.RegisterComponentType(12345, "TestScript1A", TestScript1A); }); var n = Engine.QueryInterface(12345, IID_Test1); if (n !== null) Index: ps/trunk/source/graphics/MapGenerator.cpp =================================================================== --- ps/trunk/source/graphics/MapGenerator.cpp +++ ps/trunk/source/graphics/MapGenerator.cpp @@ -115,7 +115,7 @@ bool CMapGeneratorWorker::Run() { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); // Parse settings JS::RootedValue settingsVal(rq.cx); @@ -325,7 +325,7 @@ } CMapGeneratorWorker* self = static_cast(pCmptPrivate->pCBData); - ScriptInterface::Request rq(self->m_ScriptInterface); + ScriptRequest rq(self->m_ScriptInterface); JS::RootedValue returnValue(rq.cx); ToJSVal_vector(rq, &returnValue, heightmap); return returnValue; @@ -335,13 +335,11 @@ JS::Value CMapGeneratorWorker::LoadMapTerrain(ScriptInterface::CmptPrivate* pCmptPrivate, const VfsPath& filename) { CMapGeneratorWorker* self = static_cast(pCmptPrivate->pCBData); - ScriptInterface::Request rq(self->m_ScriptInterface); + ScriptRequest rq(self->m_ScriptInterface); if (!VfsFileExists(filename)) { - self->m_ScriptInterface->ReportError( - ("Terrain file \"" + filename.string8() + "\" does not exist!").c_str()); - + ScriptException::Raise(rq, "Terrain file \"%s\" does not exist!", filename.string8().c_str()); return JS::UndefinedValue(); } @@ -350,9 +348,7 @@ if (unpacker.GetVersion() < CMapIO::FILE_READ_VERSION) { - self->m_ScriptInterface->ReportError( - ("Could not load terrain file \"" + filename.string8() + "\" too old version!").c_str()); - + ScriptException::Raise(rq, "Could not load terrain file \"%s\" too old version!", filename.string8().c_str()); return JS::UndefinedValue(); } Index: ps/trunk/source/graphics/MapReader.cpp =================================================================== --- ps/trunk/source/graphics/MapReader.cpp +++ ps/trunk/source/graphics/MapReader.cpp @@ -371,7 +371,7 @@ void CMapSummaryReader::GetMapSettings(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); ScriptInterface::CreateObject(rq, ret); @@ -1266,7 +1266,7 @@ int CMapReader::GenerateMap() { - ScriptInterface::Request rq(pSimulation2->GetScriptInterface()); + ScriptRequest rq(pSimulation2->GetScriptInterface()); if (!m_MapGen) { @@ -1328,7 +1328,7 @@ int CMapReader::ParseTerrain() { TIMER(L"ParseTerrain"); - ScriptInterface::Request rq(pSimulation2->GetScriptInterface()); + ScriptRequest rq(pSimulation2->GetScriptInterface()); // parse terrain from map data // an error here should stop the loading process @@ -1403,7 +1403,7 @@ int CMapReader::ParseEntities() { TIMER(L"ParseEntities"); - ScriptInterface::Request rq(pSimulation2->GetScriptInterface()); + ScriptRequest rq(pSimulation2->GetScriptInterface()); // parse entities from map data std::vector entities; @@ -1467,7 +1467,7 @@ int CMapReader::ParseEnvironment() { // parse environment settings from map data - ScriptInterface::Request rq(pSimulation2->GetScriptInterface()); + ScriptRequest rq(pSimulation2->GetScriptInterface()); #define GET_ENVIRONMENT_PROPERTY(val, prop, out)\ if (!pSimulation2->GetScriptInterface().GetProperty(val, #prop, out))\ @@ -1566,7 +1566,7 @@ int CMapReader::ParseCamera() { - ScriptInterface::Request rq(pSimulation2->GetScriptInterface()); + ScriptRequest rq(pSimulation2->GetScriptInterface()); // parse camera settings from map data // defaults if we don't find player starting camera Index: ps/trunk/source/graphics/scripting/JSInterface_GameView.cpp =================================================================== --- ps/trunk/source/graphics/scripting/JSInterface_GameView.cpp +++ ps/trunk/source/graphics/scripting/JSInterface_GameView.cpp @@ -70,7 +70,7 @@ JS::Value JSI_GameView::GetCameraPivot(ScriptInterface::CmptPrivate* pCmptPrivate) { - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); CVector3D pivot(-1, -1, -1); if (g_Game && g_Game->GetView()) pivot = g_Game->GetView()->GetCameraPivot(); Index: ps/trunk/source/gui/CGUI.cpp =================================================================== --- ps/trunk/source/gui/CGUI.cpp +++ ps/trunk/source/gui/CGUI.cpp @@ -37,6 +37,7 @@ #include "ps/Pyrogenesis.h" #include "ps/XML/Xeromyces.h" #include "renderer/Renderer.h" +#include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptInterface.h" #include @@ -97,10 +98,11 @@ { ret = IN_HANDLED; - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); JS::RootedObject globalObj(rq.cx, rq.glob); JS::RootedValue result(rq.cx); - JS_CallFunctionValue(rq.cx, globalObj, m_GlobalHotkeys[hotkey][eventName], JS::HandleValueArray::empty(), &result); + if (!JS_CallFunctionValue(rq.cx, globalObj, m_GlobalHotkeys[hotkey][eventName], JS::HandleValueArray::empty(), &result)) + ScriptException::CatchPending(rq); } std::map >::iterator it = m_HotkeyObjects.find(hotkey); @@ -418,24 +420,24 @@ void CGUI::SetGlobalHotkey(const CStr& hotkeyTag, const CStr& eventName, JS::HandleValue function) { - ScriptInterface::Request rq(*m_ScriptInterface); + ScriptRequest rq(*m_ScriptInterface); if (hotkeyTag.empty()) { - JS_ReportError(rq.cx, "Cannot assign a function to an empty hotkey identifier!"); + ScriptException::Raise(rq, "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(rq.cx, "Cannot assign a function to an unsupported event!"); + ScriptException::Raise(rq, "Cannot assign a function to an unsupported event!"); return; } if (!function.isObject() || !JS_ObjectIsFunction(rq.cx, &function.toObject())) { - JS_ReportError(rq.cx, "Cannot assign non-function value to global hotkey '%s'", hotkeyTag.c_str()); + ScriptException::Raise(rq, "Cannot assign non-function value to global hotkey '%s'", hotkeyTag.c_str()); return; } Index: ps/trunk/source/gui/CGUISetting.h =================================================================== --- ps/trunk/source/gui/CGUISetting.h +++ ps/trunk/source/gui/CGUISetting.h @@ -41,12 +41,12 @@ /** * Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data. */ - virtual bool FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue Value, const bool SendMessage) = 0; + virtual bool FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) = 0; /** * Converts the setting data to a JS::Value using ScriptInterface::ToJSVal. */ - virtual void ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue Value) = 0; + virtual void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value) = 0; }; template @@ -65,12 +65,12 @@ /** * Parses the given JS::Value using ScriptInterface::FromJSVal and assigns it to the setting data. */ - bool FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue Value, const bool SendMessage) override; + bool FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) override; /** * Converts the setting data to a JS::Value using ScriptInterface::ToJSVal. */ - void ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue Value) override; + void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value) override; /** * These members are public because they are either unmodifiable or free to be modified. Index: ps/trunk/source/gui/CGUISetting.cpp =================================================================== --- ps/trunk/source/gui/CGUISetting.cpp +++ ps/trunk/source/gui/CGUISetting.cpp @@ -41,7 +41,7 @@ }; template<> -bool CGUISetting::FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue Value, const bool SendMessage) +bool CGUISetting::FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) { CGUIColor settingValue; if (Value.isString()) @@ -52,7 +52,7 @@ if (!settingValue.ParseString(m_pObject.GetGUI(), name)) { - JS_ReportError(rq.cx, "Invalid color '%s'", name.c_str()); + LOGERROR("Invalid color '%s'", name.c_str()); return false; } } @@ -64,7 +64,7 @@ }; template -bool CGUISetting::FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue Value, const bool SendMessage) +bool CGUISetting::FromJSVal(const ScriptRequest& rq, JS::HandleValue Value, const bool SendMessage) { T settingValue; if (!ScriptInterface::FromJSVal(rq, Value, settingValue)) @@ -75,7 +75,7 @@ }; template -void CGUISetting::ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue Value) +void CGUISetting::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue Value) { ScriptInterface::ToJSVal(rq, Value, m_pSetting); }; Index: ps/trunk/source/gui/GUIManager.cpp =================================================================== --- ps/trunk/source/gui/GUIManager.cpp +++ ps/trunk/source/gui/GUIManager.cpp @@ -133,7 +133,7 @@ if (gui) { shared_ptr scriptInterface = gui->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue global(rq.cx, rq.globalValue()); JS::RootedValue hotloadDataVal(rq.cx); @@ -199,7 +199,7 @@ gui->LoadedXmlFiles(); shared_ptr scriptInterface = gui->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue initDataVal(rq.cx); JS::RootedValue hotloadDataVal(rq.cx); @@ -224,7 +224,7 @@ return; } - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); if (!JS_ObjectIsFunction(rq.cx, &callbackFunc.toObject())) { @@ -241,7 +241,7 @@ return; shared_ptr scriptInterface = gui->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedObject globalObj(rq.cx, rq.glob); @@ -259,7 +259,8 @@ JS::RootedValue result(rq.cx); - JS_CallFunctionValue(rq.cx, globalObj, funcVal, paramData, &result); + if(!JS_CallFunctionValue(rq.cx, globalObj, funcVal, paramData, &result)) + ScriptException::CatchPending(rq); } Status CGUIManager::ReloadChangedFile(const VfsPath& path) @@ -297,7 +298,7 @@ { PROFILE("handleInputBeforeGui"); - ScriptInterface::Request rq(*top()->GetScriptInterface()); + ScriptRequest rq(*top()->GetScriptInterface()); JS::RootedValue global(rq.cx, rq.globalValue()); if (top()->GetScriptInterface()->CallFunction(global, "handleInputBeforeGui", handled, *ev, top()->FindObjectUnderMouse())) @@ -314,7 +315,7 @@ { // We can't take the following lines out of this scope because top() may be another gui page than it was when calling handleInputBeforeGui! - ScriptInterface::Request rq(*top()->GetScriptInterface()); + ScriptRequest rq(*top()->GetScriptInterface()); JS::RootedValue global(rq.cx, rq.globalValue()); PROFILE("handleInputAfterGui"); Index: ps/trunk/source/gui/ObjectBases/IGUIObject.cpp =================================================================== --- ps/trunk/source/gui/ObjectBases/IGUIObject.cpp +++ ps/trunk/source/gui/ObjectBases/IGUIObject.cpp @@ -25,6 +25,7 @@ #include "ps/CLogger.h" #include "ps/GameSetup/Config.h" #include "ps/Profile.h" +#include "scriptinterface/ScriptContext.h" #include "scriptinterface/ScriptInterface.h" #include "soundmanager/ISoundManager.h" @@ -299,7 +300,7 @@ void IGUIObject::RegisterScriptHandler(const CStr& eventName, const CStr& Code, CGUI& pGUI) { - ScriptInterface::Request rq(pGUI.GetScriptInterface()); + ScriptRequest rq(pGUI.GetScriptInterface()); const int paramCount = 1; const char* paramNames[paramCount] = { "mouse" }; @@ -387,7 +388,7 @@ SGUIMessage msg(type); HandleMessage(msg); - ScriptInterface::Request rq(m_pGUI.GetScriptInterface()); + ScriptRequest rq(m_pGUI.GetScriptInterface()); // Set up the 'mouse' parameter JS::RootedValue mouse(rq.cx); @@ -417,7 +418,7 @@ if (m_ScriptHandlers.find(eventName) == m_ScriptHandlers.end()) return false; - ScriptInterface::Request rq(m_pGUI.GetScriptInterface()); + ScriptRequest rq(m_pGUI.GetScriptInterface()); JS::AutoValueVector paramData(rq.cx); return ScriptEventWithReturn(eventName, paramData); } @@ -433,7 +434,7 @@ if (it == m_ScriptHandlers.end()) return false; - ScriptInterface::Request rq(m_pGUI.GetScriptInterface()); + ScriptRequest rq(m_pGUI.GetScriptInterface()); JS::RootedObject obj(rq.cx, GetJSObject()); JS::RootedValue handlerVal(rq.cx, JS::ObjectValue(*it->second)); JS::RootedValue result(rq.cx); @@ -441,6 +442,7 @@ if (!JS_CallFunctionValue(rq.cx, obj, handlerVal, paramData, &result)) { LOGERROR("Errors executing script event \"%s\"", eventName.c_str()); + ScriptException::CatchPending(rq); return false; } return JS::ToBoolean(result); @@ -448,7 +450,7 @@ void IGUIObject::CreateJSObject() { - ScriptInterface::Request rq(m_pGUI.GetScriptInterface()); + ScriptRequest rq(m_pGUI.GetScriptInterface()); m_JSObject.init(rq.cx, m_pGUI.GetScriptInterface()->CreateCustomObject("GUIObject")); JS_SetPrivate(m_JSObject.get(), this); Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp +++ ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp @@ -238,7 +238,7 @@ bool CMiniMap::FireWorldClickEvent(int button, int UNUSED(clicks)) { - ScriptInterface::Request rq(g_GUI->GetActiveGUI()->GetScriptInterface()); + ScriptRequest rq(g_GUI->GetActiveGUI()->GetScriptInterface()); float x, z; GetMouseWorldCoordinates(x, z); Index: ps/trunk/source/gui/ObjectTypes/CText.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/CText.cpp +++ ps/trunk/source/gui/ObjectTypes/CText.cpp @@ -254,7 +254,7 @@ void CText::RegisterScriptFunctions() { - ScriptInterface::Request rq(m_pGUI.GetScriptInterface()); + ScriptRequest rq(m_pGUI.GetScriptInterface()); JS_DefineFunctions(rq.cx, m_JSObject, CText::JSI_methods); } @@ -268,11 +268,11 @@ { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); CText* thisObj = ScriptInterface::GetPrivate(rq, args, &JSI_IGUIObject::JSI_class); if (!thisObj) { - JS_ReportError(cx, "This is not a CText object!"); + ScriptException::Raise(rq, "This is not a CText object!"); return false; } Index: ps/trunk/source/gui/Scripting/GuiScriptConversions.cpp =================================================================== --- ps/trunk/source/gui/Scripting/GuiScriptConversions.cpp +++ ps/trunk/source/gui/Scripting/GuiScriptConversions.cpp @@ -33,7 +33,7 @@ // 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(const Request& rq, JS::MutableHandleValue ret, SDL_Event_ const& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, SDL_Event_ const& val) { const char* typeName; @@ -120,7 +120,7 @@ ret.setObject(*obj); } -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, IGUIObject* const& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, IGUIObject* const& val) { if (val == nullptr) ret.setNull(); @@ -128,12 +128,12 @@ ret.setObject(*val->GetJSObject()); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CGUIString& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CGUIString& val) { ScriptInterface::ToJSVal(rq, ret, val.GetOriginalString()); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CGUIString& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CGUIString& out) { std::wstring val; if (!FromJSVal(rq, v, val)) @@ -146,7 +146,7 @@ JSVAL_VECTOR(std::vector) JSVAL_VECTOR(CGUIString) -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CGUIColor& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CGUIColor& val) { ToJSVal(rq, ret, val); } @@ -154,65 +154,65 @@ /** * The color depends on the predefined color database stored in the current GUI page. */ -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CGUIColor& out) = delete; +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CGUIColor& out) = delete; -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CSize& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CSize& val) { CreateObject(rq, ret, "width", val.cx, "height", val.cy); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CSize& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CSize& out) { if (!v.isObject()) { - JS_ReportError(rq.cx, "CSize value must be an object!"); + LOGERROR("CSize value must be an object!"); return false; } if (!FromJSProperty(rq, v, "width", out.cx)) { - JS_ReportError(rq.cx, "Failed to get CSize.cx property"); + LOGERROR("Failed to get CSize.cx property"); return false; } if (!FromJSProperty(rq, v, "height", out.cy)) { - JS_ReportError(rq.cx, "Failed to get CSize.cy property"); + LOGERROR("Failed to get CSize.cy property"); return false; } return true; } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CPos& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CPos& val) { CreateObject(rq, ret, "x", val.x, "y", val.y); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CPos& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CPos& out) { if (!v.isObject()) { - JS_ReportError(rq.cx, "CPos value must be an object!"); + LOGERROR("CPos value must be an object!"); return false; } if (!FromJSProperty(rq, v, "x", out.x)) { - JS_ReportError(rq.cx, "Failed to get CPos.x property"); + LOGERROR("Failed to get CPos.x property"); return false; } if (!FromJSProperty(rq, v, "y", out.y)) { - JS_ReportError(rq.cx, "Failed to get CPos.y property"); + LOGERROR("Failed to get CPos.y property"); return false; } return true; } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CRect& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CRect& val) { CreateObject( rq, @@ -223,37 +223,37 @@ "bottom", val.bottom); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CGUISize& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CGUISize& val) { val.ToJSVal(rq, ret); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CGUISize& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CGUISize& out) { return out.FromJSVal(rq, v); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CGUIList& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CGUIList& val) { ToJSVal(rq, ret, val.m_Items); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CGUIList& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CGUIList& out) { return FromJSVal(rq, v, out.m_Items); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CGUISeries& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CGUISeries& val) { ToJSVal(rq, ret, val.m_Series); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CGUISeries& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CGUISeries& out) { return FromJSVal(rq, v, out.m_Series); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const EVAlign& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const EVAlign& val) { std::string word; switch (val) @@ -272,13 +272,13 @@ default: word = "error"; - JS_ReportError(rq.cx, "Invalid EVAlign"); + ScriptException::Raise(rq, "Invalid EVAlign"); break; } ToJSVal(rq, ret, word); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, EVAlign& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, EVAlign& out) { std::string word; FromJSVal(rq, v, word); @@ -292,13 +292,13 @@ else { out = EVAlign_Top; - JS_ReportError(rq.cx, "Invalid alignment (should be 'left', 'right' or 'center')"); + LOGERROR("Invalid alignment (should be 'left', 'right' or 'center')"); return false; } return true; } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const EAlign& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const EAlign& val) { std::string word; switch (val) @@ -314,13 +314,13 @@ break; default: word = "error"; - JS_ReportError(rq.cx, "Invalid alignment (should be 'left', 'right' or 'center')"); + ScriptException::Raise(rq, "Invalid alignment (should be 'left', 'right' or 'center')"); break; } ToJSVal(rq, ret, word); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, EAlign& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, EAlign& out) { std::string word; FromJSVal(rq, v, word); @@ -334,18 +334,18 @@ else { out = EAlign_Left; - JS_ReportError(rq.cx, "Invalid alignment (should be 'left', 'right' or 'center')"); + LOGERROR("Invalid alignment (should be 'left', 'right' or 'center')"); return false; } return true; } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CGUISpriteInstance& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CGUISpriteInstance& val) { ToJSVal(rq, ret, val.GetName()); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CGUISpriteInstance& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CGUISpriteInstance& out) { std::string name; if (!FromJSVal(rq, v, name)) Index: ps/trunk/source/gui/Scripting/JSInterface_GUIManager.cpp =================================================================== --- ps/trunk/source/gui/Scripting/JSInterface_GUIManager.cpp +++ ps/trunk/source/gui/Scripting/JSInterface_GUIManager.cpp @@ -41,8 +41,8 @@ { if (g_GUI->GetPageCount() < 2) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Can't pop GUI pages when less than two pages are opened!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Can't pop GUI pages when less than two pages are opened!"); return; } Index: ps/trunk/source/gui/Scripting/JSInterface_GUISize.cpp =================================================================== --- ps/trunk/source/gui/Scripting/JSInterface_GUISize.cpp +++ ps/trunk/source/gui/Scripting/JSInterface_GUISize.cpp @@ -45,7 +45,7 @@ { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - ScriptInterface::Request rq(*pScriptInterface); + ScriptRequest rq(*pScriptInterface); JS::RootedObject obj(rq.cx, pScriptInterface->CreateCustomObject("GUISize")); @@ -104,7 +104,7 @@ CStr buffer; ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - ScriptInterface::Request rq(*pScriptInterface); + ScriptRequest rq(*pScriptInterface); double val, valr; #define SIDE(side) \ Index: ps/trunk/source/gui/Scripting/JSInterface_IGUIObject.cpp =================================================================== --- ps/trunk/source/gui/Scripting/JSInterface_IGUIObject.cpp +++ ps/trunk/source/gui/Scripting/JSInterface_IGUIObject.cpp @@ -53,7 +53,7 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) { ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - ScriptInterface::Request rq(*pScriptInterface); + ScriptRequest rq(*pScriptInterface); IGUIObject* e = ScriptInterface::GetPrivate(rq, obj, &JSI_IGUIObject::JSI_class); if (!e) @@ -129,7 +129,7 @@ bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result) { - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); IGUIObject* e = ScriptInterface::GetPrivate(rq, obj, &JSI_IGUIObject::JSI_class); if (!e) @@ -180,7 +180,7 @@ bool JSI_IGUIObject::deleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result) { - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); IGUIObject* e = ScriptInterface::GetPrivate(rq, obj, &JSI_IGUIObject::JSI_class); if (!e) @@ -208,7 +208,7 @@ bool JSI_IGUIObject::toString(JSContext* cx, uint argc, JS::Value* vp) { - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); IGUIObject* e = ScriptInterface::GetPrivate(rq, args, &JSI_IGUIObject::JSI_class); @@ -222,7 +222,7 @@ bool JSI_IGUIObject::focus(JSContext* cx, uint argc, JS::Value* vp) { - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); IGUIObject* e = ScriptInterface::GetPrivate(rq, args, &JSI_IGUIObject::JSI_class); @@ -236,7 +236,7 @@ bool JSI_IGUIObject::blur(JSContext* cx, uint argc, JS::Value* vp) { - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); IGUIObject* e = ScriptInterface::GetPrivate(rq, args, &JSI_IGUIObject::JSI_class); @@ -250,7 +250,7 @@ bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp) { - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); IGUIObject* e = ScriptInterface::GetPrivate(rq, args, &JSI_IGUIObject::JSI_class); Index: ps/trunk/source/gui/SettingTypes/CGUISize.h =================================================================== --- ps/trunk/source/gui/SettingTypes/CGUISize.h +++ ps/trunk/source/gui/SettingTypes/CGUISize.h @@ -67,8 +67,8 @@ return pixel == other.pixel && percent == other.percent; } - void ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue ret) const; - bool FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue v); + void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret) const; + bool FromJSVal(const ScriptRequest& rq, JS::HandleValue v); }; #endif // INCLUDED_CGUISIZE Index: ps/trunk/source/gui/SettingTypes/CGUISize.cpp =================================================================== --- ps/trunk/source/gui/SettingTypes/CGUISize.cpp +++ ps/trunk/source/gui/SettingTypes/CGUISize.cpp @@ -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 @@ -140,28 +140,28 @@ return true; } -void CGUISize::ToJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue ret) const +void CGUISize::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret) const { ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(rq.cx)->pScriptInterface; ret.setObjectOrNull(pScriptInterface->CreateCustomObject("GUISize")); if (!ret.isObject()) { - JS_ReportError(rq.cx, "CGUISize value is not an Object"); + ScriptException::Raise(rq, "CGUISize value is not an Object"); return; } JS::RootedObject obj(rq.cx, &ret.toObject()); if (!JS_InstanceOf(rq.cx, obj, &JSI_GUISize::JSI_class, nullptr)) { - JS_ReportError(rq.cx, "CGUISize value is not a CGUISize class instance"); + ScriptException::Raise(rq, "CGUISize value is not a CGUISize class instance"); return; } #define P(x, y, z)\ if (!pScriptInterface->SetProperty(ret, #z, x.y)) \ { \ - JS_ReportError(rq.cx, "Could not SetProperty '%s'", #z); \ + ScriptException::Raise(rq, "Could not SetProperty '%s'", #z); \ return; \ } P(pixel, left, left); @@ -175,7 +175,7 @@ #undef P } -bool CGUISize::FromJSVal(const ScriptInterface::Request& rq, JS::HandleValue v) +bool CGUISize::FromJSVal(const ScriptRequest& rq, JS::HandleValue v) { ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(rq.cx)->pScriptInterface; @@ -184,13 +184,13 @@ CStrW str; if (!ScriptInterface::FromJSVal(rq, v, str)) { - JS_ReportError(rq.cx, "CGUISize could not read JS string"); + LOGERROR("CGUISize could not read JS string"); return false; } if (!FromString(str.ToUTF8())) { - JS_ReportError(rq.cx, "CGUISize could not parse JS string"); + LOGERROR("CGUISize could not parse JS string"); return false; } return true; @@ -198,21 +198,21 @@ if (!v.isObject()) { - JS_ReportError(rq.cx, "CGUISize value is not an String, nor Object"); + LOGERROR("CGUISize value is not an String, nor Object"); return false; } JS::RootedObject obj(rq.cx, &v.toObject()); if (!JS_InstanceOf(rq.cx, obj, &JSI_GUISize::JSI_class, nullptr)) { - JS_ReportError(rq.cx, "CGUISize value is not a CGUISize class instance"); + LOGERROR("CGUISize value is not a CGUISize class instance"); return false; } #define P(x, y, z) \ if (!pScriptInterface->GetProperty(v, #z, x.y))\ {\ - JS_ReportError(rq.cx, "CGUISize could not get object property '%s'", #z);\ + LOGERROR("CGUISize could not get object property '%s'", #z);\ return false;\ } Index: ps/trunk/source/gui/tests/test_GuiManager.h =================================================================== --- ps/trunk/source/gui/tests/test_GuiManager.h +++ ps/trunk/source/gui/tests/test_GuiManager.h @@ -62,7 +62,7 @@ // Load up a test page. const ScriptInterface& scriptInterface = *(g_GUI->GetScriptInterface()); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue val(rq.cx); scriptInterface.CreateObject(rq, &val); @@ -83,7 +83,7 @@ in_dispatch_event(&ev); const ScriptInterface& pageScriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface()); - ScriptInterface::Request prq(pageScriptInterface); + ScriptRequest prq(pageScriptInterface); JS::RootedValue global(prq.cx, prq.globalValue()); // Ensure that our hotkey state was synchronised with the event itself. Index: ps/trunk/source/lobby/XmppClient.cpp =================================================================== --- ps/trunk/source/lobby/XmppClient.cpp +++ ps/trunk/source/lobby/XmppClient.cpp @@ -537,7 +537,7 @@ */ void XmppClient::GUIGetPlayerList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); ScriptInterface::CreateArray(rq, ret); int j = 0; @@ -565,7 +565,7 @@ */ void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); ScriptInterface::CreateArray(rq, ret); int j = 0; @@ -593,7 +593,7 @@ */ void XmppClient::GUIGetBoardList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); ScriptInterface::CreateArray(rq, ret); int j = 0; @@ -619,7 +619,7 @@ */ void XmppClient::GUIGetProfile(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); ScriptInterface::CreateArray(rq, ret); int j = 0; @@ -642,12 +642,12 @@ * Message interfaces * *****************************************************/ -void SetGUIMessageProperty(const ScriptInterface::Request& UNUSED(rq), JS::HandleObject UNUSED(messageObj)) +void SetGUIMessageProperty(const ScriptRequest& UNUSED(rq), JS::HandleObject UNUSED(messageObj)) { } template -void SetGUIMessageProperty(const ScriptInterface::Request& rq, JS::HandleObject messageObj, const std::string& propertyName, const T& propertyValue, Args const&... args) +void SetGUIMessageProperty(const ScriptRequest& rq, JS::HandleObject messageObj, const std::string& propertyName, const T& propertyValue, Args const&... args) { JS::RootedValue scriptPropertyValue(rq.cx); ScriptInterface::AssignOrToJSVal(rq, &scriptPropertyValue, propertyValue); @@ -664,7 +664,7 @@ { if (!m_ScriptInterface) return; - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); JS::RootedValue message(rq.cx); ScriptInterface::CreateObject( rq, @@ -697,7 +697,7 @@ if ((m_isConnected && !m_initialLoadComplete) || m_GuiMessageQueue.empty()) return JS::UndefinedValue(); - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); // Optimize for batch message processing that is more // performance demanding than processing a lone message. @@ -744,7 +744,7 @@ if (m_HistoricGuiMessages.empty()) return JS::UndefinedValue(); - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); JS::RootedValue messages(rq.cx); ScriptInterface::CreateArray(rq, &messages); Index: ps/trunk/source/lobby/scripting/GlooxScriptConversions.cpp =================================================================== --- ps/trunk/source/lobby/scripting/GlooxScriptConversions.cpp +++ ps/trunk/source/lobby/scripting/GlooxScriptConversions.cpp @@ -23,37 +23,37 @@ #include "lobby/XmppClient.h" #include "scriptinterface/ScriptInterface.h" -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const glooxwrapper::string& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const glooxwrapper::string& val) { ToJSVal(rq, ret, wstring_from_utf8(val.to_string())); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const gloox::Presence::PresenceType& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const gloox::Presence::PresenceType& val) { ToJSVal(rq, ret, XmppClient::GetPresenceString(val)); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const gloox::MUCRoomRole& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const gloox::MUCRoomRole& val) { ToJSVal(rq, ret, XmppClient::GetRoleString(val)); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const gloox::StanzaError& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const gloox::StanzaError& val) { ToJSVal(rq, ret, wstring_from_utf8(XmppClient::StanzaErrorToString(val))); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const gloox::ConnectionError& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const gloox::ConnectionError& val) { ToJSVal(rq, ret, wstring_from_utf8(XmppClient::ConnectionErrorToString(val))); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const gloox::RegistrationResult& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const gloox::RegistrationResult& val) { ToJSVal(rq, ret, wstring_from_utf8(XmppClient::RegistrationResultToString(val))); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const gloox::CertStatus& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const gloox::CertStatus& val) { ToJSVal(rq, ret, wstring_from_utf8(XmppClient::CertificateErrorToString(val))); } Index: ps/trunk/source/lobby/scripting/JSInterface_Lobby.cpp =================================================================== --- ps/trunk/source/lobby/scripting/JSInterface_Lobby.cpp +++ ps/trunk/source/lobby/scripting/JSInterface_Lobby.cpp @@ -87,8 +87,8 @@ { if (g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call StartXmppClient with an already initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call StartXmppClient with an already initialized XmppClient!"); return; } @@ -108,8 +108,8 @@ { if (g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call StartRegisterXmppClient with an already initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call StartRegisterXmppClient with an already initialized XmppClient!"); return; } @@ -128,8 +128,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call StopXmppClient without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call StopXmppClient without an initialized XmppClient!"); return; } @@ -141,8 +141,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call ConnectXmppClient without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call ConnectXmppClient without an initialized XmppClient!"); return; } @@ -153,8 +153,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call DisconnectXmppClient without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call DisconnectXmppClient without an initialized XmppClient!"); return; } @@ -165,8 +165,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call IsXmppClientConnected without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call IsXmppClientConnected without an initialized XmppClient!"); return false; } @@ -177,8 +177,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call SendGetBoardList without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call SendGetBoardList without an initialized XmppClient!"); return; } @@ -189,8 +189,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call SendGetProfile without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call SendGetProfile without an initialized XmppClient!"); return; } @@ -201,8 +201,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call SendGameReport without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call SendGameReport without an initialized XmppClient!"); return; } @@ -213,8 +213,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call SendRegisterGame without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call SendRegisterGame without an initialized XmppClient!"); return; } @@ -232,8 +232,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call SendUnregisterGame without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call SendUnregisterGame without an initialized XmppClient!"); return; } @@ -244,8 +244,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call SendChangeStateGame without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call SendChangeStateGame without an initialized XmppClient!"); return; } @@ -254,11 +254,11 @@ JS::Value JSI_Lobby::GetPlayerList(ScriptInterface::CmptPrivate* pCmptPrivate) { - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); if (!g_XmppClient) { - JS_ReportError(rq.cx, "Cannot call GetPlayerList without an initialized XmppClient!"); + ScriptException::Raise(rq, "Cannot call GetPlayerList without an initialized XmppClient!"); return JS::UndefinedValue(); } @@ -270,11 +270,11 @@ JS::Value JSI_Lobby::GetGameList(ScriptInterface::CmptPrivate* pCmptPrivate) { - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); if (!g_XmppClient) { - JS_ReportError(rq.cx, "Cannot call GetGameList without an initialized XmppClient!"); + ScriptException::Raise(rq, "Cannot call GetGameList without an initialized XmppClient!"); return JS::UndefinedValue(); } @@ -286,11 +286,11 @@ JS::Value JSI_Lobby::GetBoardList(ScriptInterface::CmptPrivate* pCmptPrivate) { - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); if (!g_XmppClient) { - JS_ReportError(rq.cx, "Cannot call GetBoardList without an initialized XmppClient!"); + ScriptException::Raise(rq, "Cannot call GetBoardList without an initialized XmppClient!"); return JS::UndefinedValue(); } @@ -302,11 +302,11 @@ JS::Value JSI_Lobby::GetProfile(ScriptInterface::CmptPrivate* pCmptPrivate) { - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); if (!g_XmppClient) { - JS_ReportError(rq.cx, "Cannot call GetProfile without an initialized XmppClient!"); + ScriptException::Raise(rq, "Cannot call GetProfile without an initialized XmppClient!"); return JS::UndefinedValue(); } @@ -320,8 +320,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyGuiPollHasPlayerListUpdate without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyGuiPollHasPlayerListUpdate without an initialized XmppClient!"); return false; } @@ -340,8 +340,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyGuiPollHistoricMessages without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyGuiPollHistoricMessages without an initialized XmppClient!"); return JS::UndefinedValue(); } @@ -352,8 +352,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbySendMessage without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbySendMessage without an initialized XmppClient!"); return; } @@ -364,8 +364,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbySetPlayerPresence without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbySetPlayerPresence without an initialized XmppClient!"); return; } @@ -376,8 +376,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbySetNick without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbySetNick without an initialized XmppClient!"); return; } @@ -388,8 +388,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyGetNick without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyGetNick without an initialized XmppClient!"); return std::wstring(); } @@ -402,8 +402,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyKick without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyKick without an initialized XmppClient!"); return; } @@ -414,8 +414,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyBan without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyBan without an initialized XmppClient!"); return; } @@ -426,8 +426,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyGetPlayerPresence without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyGetPlayerPresence without an initialized XmppClient!"); return ""; } @@ -438,8 +438,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyGetPlayerRole without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyGetPlayerRole without an initialized XmppClient!"); return ""; } @@ -450,8 +450,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyGetPlayerRating without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyGetPlayerRating without an initialized XmppClient!"); return std::wstring(); } @@ -509,8 +509,8 @@ { if (!g_XmppClient) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Cannot call LobbyGetRoomSubject without an initialized XmppClient!"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Cannot call LobbyGetRoomSubject without an initialized XmppClient!"); return std::wstring(); } Index: ps/trunk/source/main.cpp =================================================================== --- ps/trunk/source/main.cpp +++ ps/trunk/source/main.cpp @@ -213,7 +213,7 @@ // dispatch all pending events to the various receivers. static void PumpEvents() { - ScriptInterface::Request rq(g_GUI->GetScriptInterface()); + ScriptRequest rq(g_GUI->GetScriptInterface()); PROFILE3("dispatch events"); Index: ps/trunk/source/network/NetClient.h =================================================================== --- ps/trunk/source/network/NetClient.h +++ ps/trunk/source/network/NetClient.h @@ -156,7 +156,7 @@ template void PushGuiMessage(Args const&... args) { - ScriptInterface::Request rq(GetScriptInterface()); + ScriptRequest rq(GetScriptInterface()); JS::RootedValue message(rq.cx); ScriptInterface::CreateObject(rq, &message, args...); Index: ps/trunk/source/network/NetClient.cpp =================================================================== --- ps/trunk/source/network/NetClient.cpp +++ ps/trunk/source/network/NetClient.cpp @@ -251,7 +251,7 @@ std::string CNetClient::TestReadGuiMessages() { - ScriptInterface::Request rq(GetScriptInterface()); + ScriptRequest rq(GetScriptInterface()); std::string r; JS::RootedValue msg(rq.cx); @@ -272,7 +272,7 @@ void CNetClient::PostPlayerAssignmentsToScript() { - ScriptInterface::Request rq(GetScriptInterface()); + ScriptRequest rq(GetScriptInterface()); JS::RootedValue newAssignments(rq.cx); ScriptInterface::CreateObject(rq, &newAssignments); Index: ps/trunk/source/network/NetServer.cpp =================================================================== --- ps/trunk/source/network/NetServer.cpp +++ ps/trunk/source/network/NetServer.cpp @@ -418,7 +418,7 @@ m_ScriptInterface->GetContext()->MaybeIncrementalGC(0.5f); - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); std::vector newStartGame; std::vector newGameAttributes; @@ -1136,7 +1136,7 @@ // unless cheating is enabled bool cheatsEnabled = false; const ScriptInterface& scriptInterface = server.GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue settings(rq.cx); scriptInterface.GetProperty(server.m_GameAttributes, "settings", &settings); if (scriptInterface.HasProperty(settings, "CheatsEnabled")) Index: ps/trunk/source/network/StunClient.cpp =================================================================== --- ps/trunk/source/network/StunClient.cpp +++ ps/trunk/source/network/StunClient.cpp @@ -390,7 +390,7 @@ addr.host = ntohl(m_IP); enet_address_get_host_ip(&addr, ipStr, ARRAY_SIZE(ipStr)); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue stunEndpoint(rq.cx); ScriptInterface::CreateObject(rq, &stunEndpoint, "ip", ipStr, "port", m_Port); Index: ps/trunk/source/network/scripting/JSInterface_Network.cpp =================================================================== --- ps/trunk/source/network/scripting/JSInterface_Network.cpp +++ ps/trunk/source/network/scripting/JSInterface_Network.cpp @@ -61,7 +61,8 @@ g_NetServer = new CNetServer(static_cast(g_XmppClient)); if (!g_NetServer->SetupConnection(serverPort)) { - pCmptPrivate->pScriptInterface->ReportError("Failed to start server"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Failed to start server"); SAFE_DELETE(g_NetServer); return; } @@ -73,7 +74,8 @@ if (!g_NetClient->SetupConnection("127.0.0.1", serverPort, nullptr)) { - pCmptPrivate->pScriptInterface->ReportError("Failed to connect to server"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Failed to connect to server"); SAFE_DELETE(g_NetClient); SAFE_DELETE(g_Game); } @@ -100,14 +102,16 @@ if (!enetClient) { - pCmptPrivate->pScriptInterface->ReportError("Could not find an unused port for the enet STUN client"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Could not find an unused port for the enet STUN client"); return; } StunClient::StunEndpoint stunEndpoint; if (!StunClient::FindStunEndpointJoin(*enetClient, stunEndpoint)) { - pCmptPrivate->pScriptInterface->ReportError("Could not find the STUN endpoint"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Could not find the STUN endpoint"); return; } @@ -126,7 +130,8 @@ if (!g_NetClient->SetupConnection(serverAddress, serverPort, enetClient)) { - pCmptPrivate->pScriptInterface->ReportError("Failed to connect to server"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Failed to connect to server"); SAFE_DELETE(g_NetClient); SAFE_DELETE(g_Game); } @@ -155,7 +160,7 @@ return JS::UndefinedValue(); // Convert from net client context to GUI script context - ScriptInterface::Request rqNet(g_NetClient->GetScriptInterface()); + ScriptRequest rqNet(g_NetClient->GetScriptInterface()); JS::RootedValue pollNet(rqNet.cx); g_NetClient->GuiPoll(&pollNet); return pCmptPrivate->pScriptInterface->CloneValueFromOtherCompartment(g_NetClient->GetScriptInterface(), pollNet); @@ -166,7 +171,7 @@ ENSURE(g_NetClient); // TODO: This is a workaround because we need to pass a MutableHandle to a JSAPI functions somewhere (with no obvious reason). - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); JS::RootedValue attribs(rq.cx, attribs1); g_NetClient->SendGameSetupMessage(&attribs, *(pCmptPrivate->pScriptInterface)); Index: ps/trunk/source/network/tests/test_Net.h =================================================================== --- ps/trunk/source/network/tests/test_Net.h +++ ps/trunk/source/network/tests/test_Net.h @@ -137,7 +137,7 @@ // and prints a load of debug output so you can see if anything funny's going on ScriptInterface scriptInterface("Engine", "Test", g_ScriptContext); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); TestStdoutLogger logger; @@ -216,7 +216,7 @@ void test_rejoin_DISABLED() { ScriptInterface scriptInterface("Engine", "Test", g_ScriptContext); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); TestStdoutLogger logger; Index: ps/trunk/source/network/tests/test_NetMessage.h =================================================================== --- ps/trunk/source/network/tests/test_NetMessage.h +++ ps/trunk/source/network/tests/test_NetMessage.h @@ -27,7 +27,7 @@ void test_sim() { ScriptInterface script("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); JS::RootedValue val(rq.cx); ScriptInterface::CreateArray(rq, &val); Index: ps/trunk/source/ps/CConsole.cpp =================================================================== --- ps/trunk/source/ps/CConsole.cpp +++ ps/trunk/source/ps/CConsole.cpp @@ -555,7 +555,7 @@ // Process it as JavaScript shared_ptr pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface(); - ScriptInterface::Request rq(*pScriptInterface); + ScriptRequest rq(*pScriptInterface); JS::RootedValue rval(rq.cx); pScriptInterface->Eval(szLine, &rval); Index: ps/trunk/source/ps/Game.cpp =================================================================== --- ps/trunk/source/ps/Game.cpp +++ ps/trunk/source/ps/Game.cpp @@ -191,7 +191,7 @@ std::getline(*m_ReplayStream, line); const ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue attribs(rq.cx); scriptInterface.ParseJSON(line, &attribs); @@ -208,7 +208,7 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& savedState) { const ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); m_InitialSavedState = savedState; m_IsSavedGame = !savedState.empty(); @@ -323,7 +323,7 @@ if (g_GUI && g_GUI->GetPageCount()) { shared_ptr scriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue global(rq.cx, rq.globalValue()); if (scriptInterface->HasProperty(global, "reallyStartGame")) Index: ps/trunk/source/ps/GameSetup/GameSetup.cpp =================================================================== --- ps/trunk/source/ps/GameSetup/GameSetup.cpp +++ ps/trunk/source/ps/GameSetup/GameSetup.cpp @@ -184,7 +184,7 @@ void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task) { const ScriptInterface& scriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface()); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::AutoValueVector paramData(rq.cx); @@ -516,7 +516,7 @@ { // The GUI has not been initialized yet, so use the simulation scriptinterface for this variable ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue playerAssignments(rq.cx); ScriptInterface::CreateObject(rq, &playerAssignments); @@ -1059,7 +1059,7 @@ const bool setup_gui = ((flags & INIT_NO_GUI) == 0); // We only want to display the splash screen at startup shared_ptr scriptInterface = g_GUI->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue data(rq.cx); if (g_GUI) { @@ -1218,7 +1218,7 @@ g_Game = new CGame(!args.Has("autostart-disable-replay")); ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue attrs(rq.cx); JS::RootedValue settings(rq.cx); @@ -1602,7 +1602,7 @@ g_Game->StartVisualReplay(replayFile); ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue attrs(rq.cx, g_Game->GetSimulation2()->GetInitAttributes()); InitPsAutostart(false, attrs); @@ -1613,7 +1613,7 @@ void CancelLoad(const CStrW& message) { shared_ptr pScriptInterface = g_GUI->GetActiveGUI()->GetScriptInterface(); - ScriptInterface::Request rq(pScriptInterface); + ScriptRequest rq(pScriptInterface); JS::RootedValue global(rq.cx, rq.globalValue()); Index: ps/trunk/source/ps/GameSetup/HWDetect.cpp =================================================================== --- ps/trunk/source/ps/GameSetup/HWDetect.cpp +++ ps/trunk/source/ps/GameSetup/HWDetect.cpp @@ -78,7 +78,7 @@ #if ARCH_X86_X64 void ConvertCaches(const ScriptInterface& scriptInterface, x86_x64::IdxCache idxCache, JS::MutableHandleValue ret) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); ScriptInterface::CreateArray(rq, ret); @@ -106,7 +106,7 @@ void ConvertTLBs(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); ScriptInterface::CreateArray(rq, ret); @@ -143,7 +143,7 @@ ScriptInterface scriptInterface("Engine", "HWDetect", g_ScriptContext); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JSI_Debug::RegisterScriptFunctions(scriptInterface); // Engine.DisplayErrorDialog JSI_ConfigDB::RegisterScriptFunctions(scriptInterface); Index: ps/trunk/source/ps/Mod.cpp =================================================================== --- ps/trunk/source/ps/Mod.cpp +++ ps/trunk/source/ps/Mod.cpp @@ -39,7 +39,7 @@ JS::Value Mod::GetAvailableMods(const ScriptInterface& scriptInterface) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx)); const Paths paths(g_args); @@ -107,7 +107,7 @@ void Mod::CacheEnabledModVersions(const shared_ptr& scriptContext) { ScriptInterface scriptInterface("Engine", "CacheEnabledModVersions", scriptContext); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue availableMods(rq.cx, GetAvailableMods(scriptInterface)); @@ -130,7 +130,7 @@ JS::Value Mod::GetLoadedModsWithVersions(const ScriptInterface& scriptInterface) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue returnValue(rq.cx); scriptInterface.ToJSVal(rq, &returnValue, g_LoadedModVersions); return returnValue; @@ -138,7 +138,7 @@ JS::Value Mod::GetEngineInfo(const ScriptInterface& scriptInterface) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue mods(rq.cx, Mod::GetLoadedModsWithVersions(scriptInterface)); JS::RootedValue metainfo(rq.cx); Index: ps/trunk/source/ps/ModInstaller.cpp =================================================================== --- ps/trunk/source/ps/ModInstaller.cpp +++ ps/trunk/source/ps/ModInstaller.cpp @@ -64,7 +64,7 @@ CStr modName; { ScriptInterface scriptInterface("Engine", "ModInstaller", scriptContext); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue json_val(rq.cx); if (!scriptInterface.ParseJSON(modinfo.GetAsString(), &json_val)) Index: ps/trunk/source/ps/ModIo.cpp =================================================================== --- ps/trunk/source/ps/ModIo.cpp +++ ps/trunk/source/ps/ModIo.cpp @@ -586,7 +586,7 @@ bool ModIo::ParseGameIdResponse(const ScriptInterface& scriptInterface, const std::string& responseData, int& id, std::string& err) { #define CLEANUP() id = -1; - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue gameResponse(rq.cx); @@ -657,7 +657,7 @@ // Make sure we don't end up passing partial results back #define CLEANUP() modData.clear(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue modResponse(rq.cx); Index: ps/trunk/source/ps/ProfileViewer.cpp =================================================================== --- ps/trunk/source/ps/ProfileViewer.cpp +++ ps/trunk/source/ps/ProfileViewer.cpp @@ -502,7 +502,7 @@ void operator() (AbstractProfileTable* table) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); JS::RootedValue t(rq.cx); ScriptInterface::CreateObject( @@ -528,7 +528,7 @@ JS::Value DumpRows(AbstractProfileTable* table) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); JS::RootedValue data(rq.cx); ScriptInterface::CreateObject(rq, &data); Index: ps/trunk/source/ps/Replay.cpp =================================================================== --- ps/trunk/source/ps/Replay.cpp +++ ps/trunk/source/ps/Replay.cpp @@ -64,7 +64,7 @@ void CReplayLogger::StartGame(JS::MutableHandleValue attribs) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); // Add timestamp, since the file-modification-date can change m_ScriptInterface.SetProperty(attribs, "timestamp", (double)std::time(nullptr)); @@ -83,7 +83,7 @@ void CReplayLogger::Turn(u32 n, u32 turnLength, std::vector& commands) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); *m_Stream << "turn " << n << " " << turnLength << "\n"; @@ -112,7 +112,7 @@ } ScriptInterface& scriptInterface = simulation.GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue arg(rq.cx); JS::RootedValue metadata(rq.cx); @@ -162,7 +162,7 @@ void CReplayPlayer::CheckReplayMods(const ScriptInterface& scriptInterface, JS::HandleValue attribs) const { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); std::vector> replayMods; scriptInterface.GetProperty(attribs, "mods", replayMods); @@ -229,7 +229,7 @@ u32 turnLength = 0; { - ScriptInterface::Request rq(g_Game->GetSimulation2()->GetScriptInterface()); + ScriptRequest rq(g_Game->GetSimulation2()->GetScriptInterface()); std::string type; while ((*m_Stream >> type).good()) Index: ps/trunk/source/ps/SavedGame.cpp =================================================================== --- ps/trunk/source/ps/SavedGame.cpp +++ ps/trunk/source/ps/SavedGame.cpp @@ -52,7 +52,7 @@ Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation2& simulation, const shared_ptr& guiMetadataClone) { - ScriptInterface::Request rq(simulation.GetScriptInterface()); + ScriptRequest rq(simulation.GetScriptInterface()); // Determine the filename to save under const VfsPath basenameFormat(L"saves/" + name); @@ -226,7 +226,7 @@ JS::Value SavedGames::GetSavedGames(const ScriptInterface& scriptInterface) { TIMER(L"GetSavedGames"); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue games(rq.cx); ScriptInterface::CreateArray(rq, &games); Index: ps/trunk/source/ps/VisualReplay.cpp =================================================================== --- ps/trunk/source/ps/VisualReplay.cpp +++ ps/trunk/source/ps/VisualReplay.cpp @@ -78,7 +78,7 @@ CStr cacheStr((std::istreambuf_iterator(cacheStream)), std::istreambuf_iterator()); cacheStream.close(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue cachedReplays(rq.cx); if (scriptInterface.ParseJSON(cacheStr, &cachedReplays)) @@ -96,7 +96,7 @@ void VisualReplay::StoreCacheFile(const ScriptInterface& scriptInterface, JS::HandleObject replays) { - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue replaysRooted(rq.cx, JS::ObjectValue(*replays)); std::ofstream cacheStream(OsString(GetTempCacheFilePath()).c_str(), std::ofstream::out | std::ofstream::trunc); @@ -111,7 +111,7 @@ JS::HandleObject VisualReplay::ReloadReplayCache(const ScriptInterface& scriptInterface, bool compareFiles) { TIMER(L"ReloadReplayCache"); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); // Maps the filename onto the index and size typedef std::map> replayCacheMap; @@ -229,7 +229,7 @@ { TIMER(L"GetReplays"); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedObject replays(rq.cx, ReloadReplayCache(scriptInterface, compareFiles)); // Only take entries with data JS::RootedValue replaysWithoutNullEntries(rq.cx); @@ -366,7 +366,7 @@ // Parse header / first line CStr header; std::getline(*replayStream, header); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue attribs(rq.cx); if (!scriptInterface.ParseJSON(header, &attribs)) { @@ -426,7 +426,7 @@ JS::Value VisualReplay::GetReplayAttributes(ScriptInterface::CmptPrivate* pCmptPrivate, const OsPath& directoryName) { // Create empty JS object - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); JS::RootedValue attribs(rq.cx); ScriptInterface::CreateObject(rq, &attribs); @@ -450,7 +450,7 @@ void VisualReplay::AddReplayToCache(const ScriptInterface& scriptInterface, const CStrW& directoryName) { TIMER(L"AddReplayToCache"); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue replayData(rq.cx, LoadReplayData(scriptInterface, OsPath(directoryName))); if (replayData.isNull()) @@ -485,7 +485,7 @@ if (!HasReplayMetadata(directoryName)) return JS::NullValue(); - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); JS::RootedValue metadata(rq.cx); std::ifstream* stream = new std::ifstream(OsString(GetDirectoryPath() / directoryName / L"metadata.json").c_str()); Index: ps/trunk/source/ps/scripting/JSInterface_Game.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_Game.cpp +++ ps/trunk/source/ps/scripting/JSInterface_Game.cpp @@ -48,7 +48,7 @@ // Convert from GUI script context to sim script context CSimulation2* sim = g_Game->GetSimulation2(); - ScriptInterface::Request rqSim(sim->GetScriptInterface()); + ScriptRequest rqSim(sim->GetScriptInterface()); JS::RootedValue gameAttribs(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), attribs)); @@ -100,8 +100,8 @@ { if (!g_Game) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Game is not started"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Game is not started"); return false; } @@ -112,8 +112,8 @@ { if (!g_Game) { - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "Game is not started"); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "Game is not started"); return; } Index: ps/trunk/source/ps/scripting/JSInterface_Main.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_Main.cpp +++ ps/trunk/source/ps/scripting/JSInterface_Main.cpp @@ -73,7 +73,7 @@ JS::Value JSI_Main::LoadMapSettings(ScriptInterface::CmptPrivate* pCmptPrivate, const VfsPath& pathname) { - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); CMapSummaryReader reader; Index: ps/trunk/source/ps/scripting/JSInterface_ModIo.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_ModIo.cpp +++ ps/trunk/source/ps/scripting/JSInterface_ModIo.cpp @@ -86,7 +86,7 @@ } ScriptInterface* scriptInterface = pCmptPrivate->pScriptInterface; - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); const std::vector& availableMods = g_ModIo->GetMods(); @@ -132,7 +132,7 @@ } ScriptInterface* scriptInterface = pCmptPrivate->pScriptInterface; - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); const DownloadProgressData& progress = g_ModIo->GetDownloadProgress(); Index: ps/trunk/source/ps/scripting/JSInterface_SavedGame.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_SavedGame.cpp +++ ps/trunk/source/ps/scripting/JSInterface_SavedGame.cpp @@ -78,7 +78,7 @@ // 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. - ScriptInterface::Request rqGui(pCmptPrivate); + ScriptRequest rqGui(pCmptPrivate->pScriptInterface); ENSURE(!g_NetServer); ENSURE(!g_NetClient); @@ -96,7 +96,7 @@ { CSimulation2* sim = g_Game->GetSimulation2(); - ScriptInterface::Request rqGame(sim->GetScriptInterface()); + ScriptRequest rqGame(sim->GetScriptInterface()); JS::RootedValue gameContextMetadata(rqGame.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), guiContextMetadata)); Index: ps/trunk/source/ps/scripting/JSInterface_VFS.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_VFS.cpp +++ ps/trunk/source/ps/scripting/JSInterface_VFS.cpp @@ -57,7 +57,7 @@ filename_array(scriptInterface->GetJSRuntime()), cur_idx(0) { - ScriptInterface::Request rq(pScriptInterface); + ScriptRequest rq(pScriptInterface); filename_array = JS_NewArrayObject(rq.cx, JS::HandleValueArray::empty()); } }; @@ -66,7 +66,7 @@ static Status BuildDirEntListCB(const VfsPath& pathname, const CFileInfo& UNUSED(fileINfo), uintptr_t cbData) { BuildDirEntListState* s = (BuildDirEntListState*)cbData; - ScriptInterface::Request rq(s->pScriptInterface); + ScriptRequest rq(s->pScriptInterface); JS::RootedObject filenameArrayObj(rq.cx, s->filename_array); JS::RootedValue val(rq.cx); @@ -139,7 +139,7 @@ contents.Replace("\r\n", "\n"); // Decode as UTF-8 - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); JS::RootedValue ret(rq.cx); ScriptInterface::ToJSVal(rq, &ret, contents.FromUTF8()); return ret; @@ -161,7 +161,7 @@ std::stringstream ss(contents); const ScriptInterface& scriptInterface = *pCmptPrivate->pScriptInterface; - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue line_array(rq.cx); ScriptInterface::CreateArray(rq, &line_array); @@ -186,7 +186,7 @@ return JS::NullValue(); const ScriptInterface& scriptInterface = *pCmptPrivate->pScriptInterface; - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue out(rq.cx); scriptInterface.ReadJSONFile(filePath, &out); return out; @@ -195,7 +195,7 @@ void JSI_VFS::WriteJSONFile(ScriptInterface::CmptPrivate* pCmptPrivate, const std::wstring& filePath, JS::HandleValue val1) { const ScriptInterface& scriptInterface = *pCmptPrivate->pScriptInterface; - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); // TODO: This is a workaround because we need to pass a MutableHandle to StringifyJSON. JS::RootedValue val(rq.cx, val1); @@ -223,8 +223,8 @@ allowedPaths += L"\"" + validPaths[i] + L"\""; } - ScriptInterface::Request rq(pCmptPrivate); - JS_ReportError(rq.cx, "This part of the engine may only read from %s!", utf8_from_wstring(allowedPaths).c_str()); + ScriptRequest rq(pCmptPrivate->pScriptInterface); + ScriptException::Raise(rq, "This part of the engine may only read from %s!", utf8_from_wstring(allowedPaths).c_str()); return false; } Index: ps/trunk/source/rlinterface/RLInterface.cpp =================================================================== --- ps/trunk/source/rlinterface/RLInterface.cpp +++ ps/trunk/source/rlinterface/RLInterface.cpp @@ -298,7 +298,7 @@ g_Game = new CGame(m_ScenarioConfig.saveReplay); ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue attrs(rq.cx); scriptInterface.ParseJSON(m_ScenarioConfig.content, &attrs); @@ -343,7 +343,7 @@ CLocalTurnManager* turnMgr = static_cast(g_Game->GetTurnManager()); const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); for (Command command : msg.commands) { JS::RootedValue commandJSON(rq.cx); @@ -376,7 +376,7 @@ std::string RLInterface::GetGameState() { const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); const CSimContext simContext = g_Game->GetSimulation2()->GetSimContext(); CmpPtr cmpAIInterface(simContext.GetSystemEntity()); Index: ps/trunk/source/scriptinterface/NativeWrapperDefns.h =================================================================== --- ps/trunk/source/scriptinterface/NativeWrapperDefns.h +++ ps/trunk/source/scriptinterface/NativeWrapperDefns.h @@ -69,7 +69,7 @@ struct ScriptInterface_NativeWrapper { template - static void call(const ScriptInterface::Request& rq, JS::MutableHandleValue rval, F fptr, Ts... params) + static void call(const ScriptRequest& rq, JS::MutableHandleValue rval, F fptr, Ts... params) { ScriptInterface::AssignOrToJSValUnrooted(rq, rval, fptr(ScriptInterface::GetScriptInterfaceAndCBData(rq.cx), params...)); } @@ -80,7 +80,7 @@ struct ScriptInterface_NativeWrapper { template - static void call(const ScriptInterface::Request& rq, JS::MutableHandleValue UNUSED(rval), F fptr, Ts... params) + static void call(const ScriptRequest& rq, JS::MutableHandleValue UNUSED(rval), F fptr, Ts... params) { fptr(ScriptInterface::GetScriptInterfaceAndCBData(rq.cx), params...); } @@ -92,7 +92,7 @@ struct ScriptInterface_NativeMethodWrapper { template - static void call(const ScriptInterface::Request& rq, JS::MutableHandleValue rval, TC* c, F fptr, Ts... params) + static void call(const ScriptRequest& rq, JS::MutableHandleValue rval, TC* c, F fptr, Ts... params) { ScriptInterface::AssignOrToJSValUnrooted(rq, rval, (c->*fptr)(params...)); } @@ -102,7 +102,7 @@ struct ScriptInterface_NativeMethodWrapper { template - static void call(const ScriptInterface::Request& UNUSED(rq), JS::MutableHandleValue UNUSED(rval), TC* c, F fptr, Ts... params) + static void call(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue UNUSED(rval), TC* c, F fptr, Ts... params) { (c->*fptr)(params...); } @@ -114,12 +114,12 @@ bool ScriptInterface::call(JSContext* cx, uint argc, JS::Value* vp) \ { \ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \ - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ JS::RootedValue rval(rq.cx); \ ScriptInterface_NativeWrapper::template call(rq, &rval, fptr A0_TAIL(z,i)); \ args.rval().set(rval); \ - return !ScriptInterface::IsExceptionPending(rq); \ + return !ScriptException::IsPending(rq); \ } BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS @@ -130,14 +130,14 @@ bool ScriptInterface::callMethod(JSContext* cx, uint argc, JS::Value* vp) \ { \ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \ - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ TC* c = ScriptInterface::GetPrivate(rq, args, CLS); \ if (! c) return false; \ BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ JS::RootedValue rval(rq.cx); \ ScriptInterface_NativeMethodWrapper::template call(rq, &rval, c, fptr A0_TAIL(z,i)); \ args.rval().set(rval); \ - return !ScriptInterface::IsExceptionPending(rq); \ + return !ScriptException::IsPending(rq); \ } BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS @@ -148,27 +148,27 @@ bool ScriptInterface::callMethodConst(JSContext* cx, uint argc, JS::Value* vp) \ { \ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \ - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ TC* c = ScriptInterface::GetPrivate(rq, args, CLS); \ if (! c) return false; \ BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ JS::RootedValue rval(rq.cx); \ ScriptInterface_NativeMethodWrapper::template call(rq, &rval, c, fptr A0_TAIL(z,i)); \ args.rval().set(rval); \ - return !ScriptInterface::IsExceptionPending(rq); \ + return !ScriptException::IsPending(rq); \ } BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS template -static void AssignOrToJSValHelper(const ScriptInterface::Request& rq, JS::AutoValueVector& argv, const T& a, const Ts&... params) +static void AssignOrToJSValHelper(const ScriptRequest& rq, JS::AutoValueVector& argv, const T& a, const Ts&... params) { ScriptInterface::AssignOrToJSVal(rq, argv[i], a); AssignOrToJSValHelper(rq, argv, params...); } template -static void AssignOrToJSValHelper(const ScriptInterface::Request& UNUSED(rq), JS::AutoValueVector& UNUSED(argv)) +static void AssignOrToJSValHelper(const ScriptRequest& UNUSED(rq), JS::AutoValueVector& UNUSED(argv)) { cassert(sizeof...(Ts) == 0); // Nop, for terminating the template recursion. @@ -177,7 +177,7 @@ template bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, R& ret, const Ts&... params) const { - ScriptInterface::Request rq(this); + ScriptRequest rq(this); JS::RootedValue jsRet(rq.cx); JS::AutoValueVector argv(rq.cx); argv.resize(sizeof...(Ts)); @@ -190,7 +190,7 @@ template bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::Rooted* ret, const Ts&... params) const { - ScriptInterface::Request rq(this); + ScriptRequest rq(this); JS::MutableHandle jsRet(ret); JS::AutoValueVector argv(rq.cx); argv.resize(sizeof...(Ts)); @@ -201,7 +201,7 @@ template bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, JS::MutableHandle ret, const Ts&... params) const { - ScriptInterface::Request rq(this); + ScriptRequest rq(this); JS::AutoValueVector argv(rq.cx); argv.resize(sizeof...(Ts)); AssignOrToJSValHelper<0>(rq, argv, params...); @@ -212,7 +212,7 @@ template bool ScriptInterface::CallFunctionVoid(JS::HandleValue val, const char* name, const Ts&... params) const { - ScriptInterface::Request rq(this); + ScriptRequest rq(this); JS::RootedValue jsRet(rq.cx); JS::AutoValueVector argv(rq.cx); argv.resize(sizeof...(Ts)); Index: ps/trunk/source/scriptinterface/ScriptContext.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptContext.h +++ ps/trunk/source/scriptinterface/ScriptContext.h @@ -56,6 +56,7 @@ int contextSize = DEFAULT_CONTEXT_SIZE, int heapGrowthBytesGCTrigger = DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER); + /** * MaybeIncrementalGC tries to determine whether a context-wide garbage collection would free up enough memory to * be worth the amount of time it would take. It does this with our own logic and NOT some predefined JSAPI logic because @@ -82,7 +83,7 @@ * entering any compartment. It should only be used in specific situations, such as * creating a new compartment, or as an unsafe alternative to GetJSRuntime. * If you need the compartmented context of a ScriptInterface, you should create a - * ScriptInterface::Request and use the context from that. + * ScriptRequest and use the context from that. */ JSContext* GetGeneralJSContext() const { return m_cx; } Index: ps/trunk/source/scriptinterface/ScriptContext.cpp =================================================================== --- ps/trunk/source/scriptinterface/ScriptContext.cpp +++ ps/trunk/source/scriptinterface/ScriptContext.cpp @@ -90,51 +90,6 @@ #endif } - -namespace { - -void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report) -{ - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); - - std::stringstream msg; - bool isWarning = JSREPORT_IS_WARNING(report->flags); - msg << (isWarning ? "JavaScript warning: " : "JavaScript error: "); - if (report->filename) - { - msg << report->filename; - msg << " line " << report->lineno << "\n"; - } - - msg << message; - - // If there is an exception, then print its stack trace - JS::RootedValue excn(rq.cx); - if (JS_GetPendingException(rq.cx, &excn) && excn.isObject()) - { - JS::RootedValue stackVal(rq.cx); - JS::RootedObject excnObj(rq.cx, &excn.toObject()); - JS_GetProperty(rq.cx, excnObj, "stack", &stackVal); - - std::string stackText; - ScriptInterface::FromJSVal(rq, stackVal, stackText); - - std::istringstream stream(stackText); - for (std::string line; std::getline(stream, line);) - msg << "\n " << line; - } - - if (isWarning) - LOGWARNING("%s", msg.str().c_str()); - else - LOGERROR("%s", msg.str().c_str()); - - // When running under Valgrind, print more information in the error message - // VALGRIND_PRINTF_BACKTRACE("->"); -} - -} // anonymous namespace - shared_ptr ScriptContext::CreateContext(int contextSize, int heapGrowthBytesGCTrigger) { return shared_ptr(new ScriptContext(contextSize, heapGrowthBytesGCTrigger)); @@ -161,6 +116,7 @@ // We disable it to make it more clear if full GCs happen triggered by this JSAPI internal mechanism. JS_SetGCParameter(m_rt, JSGC_DYNAMIC_HEAP_GROWTH, false); + JS_SetErrorReporter(m_rt, ScriptException::ErrorReporter); m_cx = JS_NewContext(m_rt, STACK_CHUNK_SIZE); ENSURE(m_cx); // TODO: error handling @@ -172,8 +128,6 @@ JS_SetContextPrivate(m_cx, nullptr); - JS_SetErrorReporter(m_rt, ErrorReporter); - JS_SetGlobalJitCompilerOption(m_rt, JSJITCOMPILER_ION_ENABLE, 1); JS_SetGlobalJitCompilerOption(m_rt, JSJITCOMPILER_BASELINE_ENABLE, 1); Index: ps/trunk/source/scriptinterface/ScriptConversions.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptConversions.h +++ ps/trunk/source/scriptinterface/ScriptConversions.h @@ -23,7 +23,7 @@ #include -template static void ToJSVal_vector(const ScriptInterface::Request& rq, JS::MutableHandleValue ret, const std::vector& val) +template static void ToJSVal_vector(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::vector& val) { JS::RootedObject obj(rq.cx, JS_NewArrayObject(rq.cx, 0)); if (!obj) @@ -42,9 +42,9 @@ ret.setObject(*obj); } -#define FAIL(msg) STMT(JS_ReportError(rq.cx, msg); return false) +#define FAIL(msg) STMT(ScriptException::Raise(rq, msg); return false) -template static bool FromJSVal_vector(const ScriptInterface::Request& rq, JS::HandleValue v, std::vector& out) +template static bool FromJSVal_vector(const ScriptRequest& rq, JS::HandleValue v, std::vector& out) { JS::RootedObject obj(rq.cx); if (!v.isObject()) @@ -76,16 +76,16 @@ #undef FAIL #define JSVAL_VECTOR(T) \ -template<> void ScriptInterface::ToJSVal >(const ScriptInterface::Request& rq, JS::MutableHandleValue ret, const std::vector& val) \ +template<> void ScriptInterface::ToJSVal >(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::vector& val) \ { \ ToJSVal_vector(rq, ret, val); \ } \ -template<> bool ScriptInterface::FromJSVal >(const ScriptInterface::Request& rq, JS::HandleValue v, std::vector& out) \ +template<> bool ScriptInterface::FromJSVal >(const ScriptRequest& rq, JS::HandleValue v, std::vector& out) \ { \ return FromJSVal_vector(rq, v, out); \ } -template bool ScriptInterface::FromJSProperty(const ScriptInterface::Request& rq, const JS::HandleValue val, const char* name, T& ret, bool strict) +template bool ScriptInterface::FromJSProperty(const ScriptRequest& rq, const JS::HandleValue val, const char* name, T& ret, bool strict) { if (!val.isObject()) return false; Index: ps/trunk/source/scriptinterface/ScriptConversions.cpp =================================================================== --- ps/trunk/source/scriptinterface/ScriptConversions.cpp +++ ps/trunk/source/scriptinterface/ScriptConversions.cpp @@ -24,7 +24,7 @@ #include "ps/utf16string.h" #include "ps/CStr.h" -#define FAIL(msg) STMT(JS_ReportError(rq.cx, msg); return false) +#define FAIL(msg) STMT(LOGERROR(msg); return false) // Implicit type conversions often hide bugs, so warn about them #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)); }) @@ -50,14 +50,14 @@ return "value"; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, bool& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, bool& out) { WARN_IF_NOT(v.isBoolean(), v); out = JS::ToBoolean(v); return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, float& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, float& out) { double tmp; WARN_IF_NOT(v.isNumber(), v); @@ -67,7 +67,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, double& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, double& out) { WARN_IF_NOT(v.isNumber(), v); if (!JS::ToNumber(rq.cx, v, &out)) @@ -75,7 +75,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, i32& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, i32& out) { WARN_IF_NOT(v.isNumber(), v); if (!JS::ToInt32(rq.cx, v, &out)) @@ -83,7 +83,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, u32& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, u32& out) { WARN_IF_NOT(v.isNumber(), v); if (!JS::ToUint32(rq.cx, v, &out)) @@ -91,7 +91,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, u16& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, u16& out) { WARN_IF_NOT(v.isNumber(), v); if (!JS::ToUint16(rq.cx, v, &out)) @@ -99,7 +99,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, u8& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, u8& out) { u16 tmp; WARN_IF_NOT(v.isNumber(), v); @@ -109,7 +109,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, std::wstring& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, std::wstring& out) { WARN_IF_NOT(v.isString() || v.isNumber(), v); // allow implicit number conversions JS::RootedString str(rq.cx, JS::ToString(rq.cx, v)); @@ -139,7 +139,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, Path& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, Path& out) { std::wstring string; if (!FromJSVal(rq, v, string)) @@ -148,7 +148,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, std::string& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, std::string& out) { std::wstring wideout; if (!FromJSVal(rq, v, wideout)) @@ -157,17 +157,17 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CStr8& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CStr8& out) { return ScriptInterface::FromJSVal(rq, v, static_cast(out)); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CStrW& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CStrW& out) { return ScriptInterface::FromJSVal(rq, v, static_cast(out)); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, Entity& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, Entity& out) { if (!v.isObject()) FAIL("Argument must be an object"); @@ -197,42 +197,42 @@ //////////////////////////////////////////////////////////////// // Primitive types: -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, const bool& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const bool& val) { ret.setBoolean(val); } -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, const float& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const float& val) { ret.set(JS::NumberValue(val)); } -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, const double& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const double& val) { ret.set(JS::NumberValue(val)); } -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, const i32& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const i32& val) { ret.set(JS::NumberValue(val)); } -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u16& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const u16& val) { ret.set(JS::NumberValue(val)); } -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u8& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const u8& val) { ret.set(JS::NumberValue(val)); } -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, const u32& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const u32& val) { ret.set(JS::NumberValue(val)); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const std::wstring& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::wstring& val) { utf16string utf16(val.begin(), val.end()); JS::RootedString str(rq.cx, JS_NewUCStringCopyN(rq.cx, reinterpret_cast (utf16.c_str()), utf16.length())); @@ -242,22 +242,22 @@ ret.setUndefined(); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const Path& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const Path& val) { ToJSVal(rq, ret, val.string()); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const std::string& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::string& val) { ToJSVal(rq, ret, static_cast(CStr(val).FromUTF8())); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const wchar_t* const& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const wchar_t* const& val) { ToJSVal(rq, ret, std::wstring(val)); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const char* const& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const char* const& val) { JS::RootedString str(rq.cx, JS_NewStringCopyZ(rq.cx, val)); if (str) @@ -267,11 +267,11 @@ } #define TOJSVAL_CHAR(N) \ -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const wchar_t (&val)[N]) \ +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const wchar_t (&val)[N]) \ { \ ToJSVal(rq, ret, static_cast(val)); \ } \ -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const char (&val)[N]) \ +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const char (&val)[N]) \ { \ ToJSVal(rq, ret, static_cast(val)); \ } @@ -300,12 +300,12 @@ TOJSVAL_CHAR(256) #undef TOJSVAL_CHAR -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CStrW& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CStrW& val) { ToJSVal(rq, ret, static_cast(val)); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CStr8& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CStr8& val) { ToJSVal(rq, ret, static_cast(val)); } @@ -326,23 +326,23 @@ class IComponent; -template<> void ScriptInterface::ToJSVal >(const Request& rq, JS::MutableHandleValue ret, const std::vector& val) +template<> void ScriptInterface::ToJSVal >(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::vector& val) { ToJSVal_vector(rq, ret, val); } -template<> bool ScriptInterface::FromJSVal >(const Request& rq, JS::HandleValue v, std::vector& out) +template<> bool ScriptInterface::FromJSVal >(const ScriptRequest& rq, JS::HandleValue v, std::vector& out) { return FromJSVal_vector(rq, v, out); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CVector2D& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CVector2D& val) { std::vector vec = {val.X, val.Y}; ToJSVal_vector(rq, ret, vec); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CVector2D& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CVector2D& out) { std::vector vec; Index: ps/trunk/source/scriptinterface/ScriptExceptions.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptExceptions.h +++ ps/trunk/source/scriptinterface/ScriptExceptions.h @@ -0,0 +1,53 @@ +/* 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 + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_SCRIPTEXCEPTIONS +#define INCLUDED_SCRIPTEXCEPTIONS + +struct JSContext; +class JSErrorReport; +class ScriptRequest; + +namespace ScriptException +{ +/** + * @return Whether there is a JS exception pending. + */ +bool IsPending(const ScriptRequest& rq); + +/** + * Log and then clear the current pending exception. This function should always be called after calling a + * JS script (or anything that can throw JS errors, such as structured clones), + * in case that script doesn't catch an exception thrown during its execution. + * If no exception is pending, this does nothing. + * Note that JS code that wants to throw errors should throw new Error(...), otherwise the stack cannot be used. + * @return Whether there was a pending exception. + */ +bool CatchPending(const ScriptRequest& rq); + +void ErrorReporter(JSContext* rt, const char* message, JSErrorReport* report); + +/** + * Raise a JS exception from C++ code. + * This is only really relevant in JSNative functions that don't use ObjectOpResult, + * as the latter overwrites the pending exception. + * Prefer either simply logging an error if you know a stack-trace will be raised elsewhere. + */ +void Raise(const ScriptRequest& rq, const char* format, ...); +} + +#endif // INCLUDED_SCRIPTEXCEPTIONS Index: ps/trunk/source/scriptinterface/ScriptExceptions.cpp =================================================================== --- ps/trunk/source/scriptinterface/ScriptExceptions.cpp +++ ps/trunk/source/scriptinterface/ScriptExceptions.cpp @@ -0,0 +1,151 @@ +/* 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 + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + + +#include "precompiled.h" + +#include "ScriptExceptions.h" + +#include "ps/CLogger.h" +#include "scriptinterface/ScriptInterface.h" + +bool ScriptException::IsPending(const ScriptRequest& rq) +{ + return JS_IsExceptionPending(rq.cx); +} + +bool ScriptException::CatchPending(const ScriptRequest& rq) +{ + if (!JS_IsExceptionPending(rq.cx)) + return false; + + JS::RootedValue excn(rq.cx); + ENSURE(JS_GetPendingException(rq.cx, &excn)); + + if (excn.isUndefined()) + { + LOGERROR("JavaScript error: (undefined)"); + JS_ClearPendingException(rq.cx); + return true; + } + + // As of SM45/52, there is no way to recover a stack in case the thrown thing is not an Error object. + if (!excn.isObject()) + { + CStr error; + ScriptInterface::FromJSVal(rq, excn, error); + LOGERROR("JavaScript error: %s", error); + JS_ClearPendingException(rq.cx); + return true; + } + + JS::RootedObject excnObj(rq.cx, &excn.toObject()); + JSErrorReport* report = JS_ErrorFromException(rq.cx, excnObj); + + if (!report) + { + CStr error; + ScriptInterface::FromJSVal(rq, excn, error); + LOGERROR("JavaScript error: %s", error); + JS_ClearPendingException(rq.cx); + return true; + } + + std::stringstream msg; + msg << (JSREPORT_IS_EXCEPTION(report->flags) ? "JavaScript exception: " : "JavaScript error: "); + if (report->filename) + { + msg << report->filename; + msg << " line " << report->lineno << "\n"; + } + + // TODO SM52: + // msg << report->message(); + + JS::RootedObject stackObj(rq.cx, ExceptionStackOrNull(rq.cx, excnObj)); + JS::RootedValue stackVal(rq.cx, JS::ObjectOrNullValue(stackObj)); + if (!stackVal.isNull()) + { + std::string stackText; + ScriptInterface::FromJSVal(rq, stackVal, stackText); + + std::istringstream stream(stackText); + for (std::string line; std::getline(stream, line);) + msg << "\n " << line; + } + + LOGERROR("%s", msg.str().c_str()); + + // When running under Valgrind, print more information in the error message + // VALGRIND_PRINTF_BACKTRACE("->"); + + JS_ClearPendingException(rq.cx); + return true; +} + +void ScriptException::ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report) +{ + if (!ScriptInterface::GetScriptInterfaceAndCBData(cx)) + { + LOGERROR("Javascript - Out of Memory error"); + return; + } + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); + + std::stringstream msg; + bool isWarning = JSREPORT_IS_WARNING(report->flags); + msg << (isWarning ? "JavaScript warning: " : "JavaScript error: "); + if (report->filename) + { + msg << report->filename; + msg << " line " << report->lineno << "\n"; + } + + msg << message; + + // If there is an exception, then print its stack trace + JS::RootedValue excn(rq.cx); + if (JS_GetPendingException(rq.cx, &excn) && excn.isObject()) + { + JS::RootedValue stackVal(rq.cx); + JS::RootedObject excnObj(rq.cx, &excn.toObject()); + JS_GetProperty(rq.cx, excnObj, "stack", &stackVal); + + std::string stackText; + ScriptInterface::FromJSVal(rq, stackVal, stackText); + + std::istringstream stream(stackText); + for (std::string line; std::getline(stream, line);) + msg << "\n " << line; + } + + if (isWarning) + LOGWARNING("%s", msg.str().c_str()); + else + LOGERROR("%s", msg.str().c_str()); + + // When running under Valgrind, print more information in the error message + // VALGRIND_PRINTF_BACKTRACE("->"); +} + +void ScriptException::Raise(const ScriptRequest& rq, const char* format, ...) +{ + va_list ap; + va_start(ap, format); + JS_ReportError(rq.cx, format, ap); + va_end(ap); +} Index: ps/trunk/source/scriptinterface/ScriptInterface.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptInterface.h +++ ps/trunk/source/scriptinterface/ScriptInterface.h @@ -20,8 +20,9 @@ #include "lib/file/vfs/vfs_path.h" #include "maths/Fixed.h" -#include "ScriptTypes.h" #include "ps/Errors.h" +#include "scriptinterface/ScriptExceptions.h" +#include "scriptinterface/ScriptTypes.h" #include #include @@ -48,6 +49,7 @@ // but as large as necessary for all wrapped functions) #define SCRIPT_INTERFACE_MAX_ARGS 8 +class ScriptInterface; struct ScriptInterface_impl; class ScriptContext; @@ -56,6 +58,32 @@ // use their own threads and also their own contexts. extern thread_local shared_ptr g_ScriptContext; +/** + * RAII structure which encapsulates an access to the context and compartment of a ScriptInterface. + * This struct provides: + * - a pointer to the context, while acting like JSAutoRequest + * - a pointer to the global object of the compartment, while acting like JSAutoCompartment + * + * This way, getting and using those pointers is safe with respect to the GC + * and to the separation of compartments. + */ +class ScriptRequest +{ +public: + ScriptRequest() = delete; + ScriptRequest(const ScriptRequest& rq) = delete; + ScriptRequest& operator=(const ScriptRequest& rq) = delete; + ScriptRequest(const ScriptInterface& scriptInterface); + ScriptRequest(const ScriptInterface* scriptInterface) : ScriptRequest(*scriptInterface) {} + ScriptRequest(shared_ptr scriptInterface) : ScriptRequest(*scriptInterface) {} + ~ScriptRequest(); + + JS::Value globalValue() const; + JSContext* cx; + JSObject* glob; +private: + JSCompartment* m_formerCompartment; +}; /** * Abstraction around a SpiderMonkey JSCompartment. @@ -69,6 +97,7 @@ { NONCOPYABLE(ScriptInterface); + friend class ScriptRequest; public: /** @@ -95,34 +124,6 @@ shared_ptr GetContext() const; /** - * RAII structure which encapsulates an access to the context and compartment of a ScriptInterface. - * This struct provides: - * - a pointer to the context, while acting like JSAutoRequest - * - a pointer to the global object of the compartment, while acting like JSAutoCompartment - * - * This way, getting and using those pointers is safe with respect to the GC - * and to the separation of compartments. - */ - struct Request - { - 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) : Request(*scriptInterface) {} - Request(const CmptPrivate* cmptPrivate) : Request(cmptPrivate->pScriptInterface) {} - ~Request(); - - JS::Value globalValue() const; - JSContext* cx; - JSObject* glob; - private: - JSCompartment* m_formerCompartment; - }; - friend struct Request; - - /** * Load global scripts that most script interfaces need, * located in the /globalscripts directory. VFS must be initialized. */ @@ -150,7 +151,7 @@ * Can throw an exception. */ template - static bool CreateObject(const Request& rq, JS::MutableHandleValue objectValue, Args const&... args) + static bool CreateObject(const ScriptRequest& rq, JS::MutableHandleValue objectValue, Args const&... args) { JS::RootedObject obj(rq.cx); @@ -164,7 +165,7 @@ /** * Sets the given value to a new JS object or Null Value in case of out-of-memory. */ - static void CreateArray(const Request& rq, JS::MutableHandleValue objectValue, size_t length = 0); + static void CreateArray(const ScriptRequest& rq, JS::MutableHandleValue objectValue, size_t length = 0); /** * Set the named property on the global object. @@ -268,13 +269,6 @@ std::string StringifyJSON(JS::MutableHandleValue obj, bool indent = true) const; /** - * Report the given error message through the JS error reporting mechanism, - * and throw a JS exception. (Callers can check IsPendingException, and must - * return false in that case to propagate the exception.) - */ - void ReportError(const char* msg) const; - - /** * Load and execute the given script in a new function scope. * @param filename Name for debugging purposes (not used to load the file) * @param code JS code to execute @@ -307,7 +301,7 @@ /** * Convert a JS::Value to a C++ type. (This might trigger GC.) */ - template static bool FromJSVal(const Request& rq, const JS::HandleValue val, T& ret); + template static bool FromJSVal(const ScriptRequest& rq, const JS::HandleValue val, T& ret); /** * Convert a C++ type to a JS::Value. (This might trigger GC. The return @@ -316,12 +310,12 @@ * 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 static void ToJSVal(const Request& rq, JS::MutableHandleValue ret, T const& val); + template static void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, T const& val); /** * Convert a named property of an object to a C++ type. */ - template static bool FromJSProperty(const Request& rq, const JS::HandleValue val, const char* name, T& ret, bool strict = false); + template static bool FromJSProperty(const ScriptRequest& 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 @@ -355,11 +349,13 @@ * Retrieve the private data field of a JSObject that is an instance of the given JSClass. */ template - static T* GetPrivate(const Request& rq, JS::HandleObject thisobj, JSClass* jsClass) + static T* GetPrivate(const ScriptRequest& rq, JS::HandleObject thisobj, JSClass* jsClass) { T* value = static_cast(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!"); + + if (value == nullptr) + ScriptException::Raise(rq, "Private data of the given object is null!"); + return value; } @@ -368,17 +364,20 @@ * If an error occurs, GetPrivate will report it with the according stack. */ template - static T* GetPrivate(const Request& rq, JS::CallArgs& callArgs, JSClass* jsClass) + static T* GetPrivate(const ScriptRequest& rq, JS::CallArgs& callArgs, JSClass* jsClass) { if (!callArgs.thisv().isObject()) { - JS_ReportError(rq.cx, "Cannot retrieve private JS class data because from a non-object value!"); + ScriptException::Raise(rq, "Cannot retrieve private JS class data because from a non-object value!"); return nullptr; } + JS::RootedObject thisObj(rq.cx, &callArgs.thisv().toObject()); T* value = static_cast(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!"); + + if (value == nullptr) + ScriptException::Raise(rq, "Private data of the given object is null!"); + return value; } @@ -391,7 +390,7 @@ * because "conversions" from JS::HandleValue to JS::MutableHandleValue are unusual and should not happen "by accident". */ template - static void AssignOrToJSVal(const Request& rq, JS::MutableHandleValue handle, const T& a); + static void AssignOrToJSVal(const ScriptRequest& rq, JS::MutableHandleValue handle, const T& a); /** * The same as AssignOrToJSVal, but also allows JS::Value for T. @@ -401,7 +400,7 @@ * "unrooted" version of AssignOrToJSVal. */ template - static void AssignOrToJSValUnrooted(const Request& rq, JS::MutableHandleValue handle, const T& a) + static void AssignOrToJSValUnrooted(const ScriptRequest& rq, JS::MutableHandleValue handle, const T& a) { AssignOrToJSVal(rq, handle, a); } @@ -412,14 +411,14 @@ * other types. */ template - static T AssignOrFromJSVal(const Request& rq, const JS::HandleValue& val, bool& ret); + static T AssignOrFromJSVal(const ScriptRequest& rq, const JS::HandleValue& val, bool& ret); private: - static bool CreateObject_(const Request& rq, JS::MutableHandleObject obj); + static bool CreateObject_(const ScriptRequest& rq, JS::MutableHandleObject obj); template - static bool CreateObject_(const Request& rq, JS::MutableHandleObject obj, const char* propertyName, const T& propertyValue, Args const&... args) + static bool CreateObject_(const ScriptRequest& rq, JS::MutableHandleObject obj, const char* propertyName, const T& propertyValue, Args const&... args) { JS::RootedValue val(rq.cx); AssignOrToJSVal(rq, &val, propertyValue); @@ -436,7 +435,6 @@ 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(const Request& rq); struct CustomType { @@ -490,43 +488,43 @@ #include "NativeWrapperDefns.h" template -inline void ScriptInterface::AssignOrToJSVal(const Request& rq, JS::MutableHandleValue handle, const T& a) +inline void ScriptInterface::AssignOrToJSVal(const ScriptRequest& rq, JS::MutableHandleValue handle, const T& a) { ToJSVal(rq, handle, a); } template<> -inline void ScriptInterface::AssignOrToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::PersistentRootedValue& a) +inline void ScriptInterface::AssignOrToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::PersistentRootedValue& a) { handle.set(a); } template<> -inline void ScriptInterface::AssignOrToJSVal >(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::Heap& a) +inline void ScriptInterface::AssignOrToJSVal >(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::Heap& a) { handle.set(a); } template<> -inline void ScriptInterface::AssignOrToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::RootedValue& a) +inline void ScriptInterface::AssignOrToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::RootedValue& a) { handle.set(a); } template <> -inline void ScriptInterface::AssignOrToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::HandleValue& a) +inline void ScriptInterface::AssignOrToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::HandleValue& a) { handle.set(a); } template <> -inline void ScriptInterface::AssignOrToJSValUnrooted(const Request& UNUSED(rq), JS::MutableHandleValue handle, const JS::Value& a) +inline void ScriptInterface::AssignOrToJSValUnrooted(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::Value& a) { handle.set(a); } template -inline T ScriptInterface::AssignOrFromJSVal(const Request& rq, const JS::HandleValue& val, bool& ret) +inline T ScriptInterface::AssignOrFromJSVal(const ScriptRequest& rq, const JS::HandleValue& val, bool& ret) { T retVal; ret = FromJSVal(rq, val, retVal); @@ -534,7 +532,7 @@ } template<> -inline JS::HandleValue ScriptInterface::AssignOrFromJSVal(const Request& UNUSED(rq), const JS::HandleValue& val, bool& ret) +inline JS::HandleValue ScriptInterface::AssignOrFromJSVal(const ScriptRequest& UNUSED(rq), const JS::HandleValue& val, bool& ret) { ret = true; return val; @@ -543,7 +541,7 @@ template bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace, bool constant, bool enumerate) { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue val(rq.cx); AssignOrToJSVal(rq, &val, value); return SetGlobal_(name, val, replace, constant, enumerate); @@ -552,7 +550,7 @@ template bool ScriptInterface::SetProperty(JS::HandleValue obj, const char* name, const T& value, bool constant, bool enumerate) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue val(rq.cx); AssignOrToJSVal(rq, &val, value); return SetProperty_(obj, name, val, constant, enumerate); @@ -561,7 +559,7 @@ template bool ScriptInterface::SetProperty(JS::HandleValue obj, const wchar_t* name, const T& value, bool constant, bool enumerate) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue val(rq.cx); AssignOrToJSVal(rq, &val, value); return SetProperty_(obj, name, val, constant, enumerate); @@ -570,7 +568,7 @@ template bool ScriptInterface::SetPropertyInt(JS::HandleValue obj, int name, const T& value, bool constant, bool enumerate) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue val(rq.cx); AssignOrToJSVal(rq, &val, value); return SetPropertyInt_(obj, name, val, constant, enumerate); @@ -579,7 +577,7 @@ template bool ScriptInterface::GetProperty(JS::HandleValue obj, const char* name, T& out) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue val(rq.cx); if (!GetProperty_(obj, name, &val)) return false; @@ -589,7 +587,7 @@ template bool ScriptInterface::GetPropertyInt(JS::HandleValue obj, int name, T& out) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue val(rq.cx); if (!GetPropertyInt_(obj, name, &val)) return false; @@ -607,7 +605,7 @@ template bool ScriptInterface::Eval(const CHAR* code, T& ret) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue rval(rq.cx); if (!Eval_(code, &rval)) return false; Index: ps/trunk/source/scriptinterface/ScriptInterface.cpp =================================================================== --- ps/trunk/source/scriptinterface/ScriptInterface.cpp +++ ps/trunk/source/scriptinterface/ScriptInterface.cpp @@ -62,7 +62,7 @@ // members have to be called before the context destructor. shared_ptr m_context; - friend ScriptInterface::Request; + friend ScriptRequest; private: JSContext* m_cx; JS::PersistentRootedObject m_glob; // global scope object @@ -72,7 +72,7 @@ JS::PersistentRootedObject m_nativeScope; // native function scope object }; -ScriptInterface::Request::Request(const ScriptInterface& scriptInterface) : +ScriptRequest::ScriptRequest(const ScriptInterface& scriptInterface) : cx(scriptInterface.m->m_cx) { JS_BeginRequest(cx); @@ -80,12 +80,12 @@ glob = JS::CurrentGlobalOrNull(cx); } -JS::Value ScriptInterface::Request::globalValue() const +JS::Value ScriptRequest::globalValue() const { return JS::ObjectValue(*glob); } -ScriptInterface::Request::~Request() +ScriptRequest::~ScriptRequest() { JS_LeaveCompartment(cx, m_formerCompartment); JS_EndRequest(cx); @@ -108,7 +108,7 @@ bool print(JSContext* cx, uint argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ for (uint i = 0; i < args.length(); ++i) { @@ -131,7 +131,7 @@ return true; } - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ std::wstring str; if (!ScriptInterface::FromJSVal(rq, args[0], str)) return false; @@ -149,7 +149,7 @@ return true; } - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ std::wstring str; if (!ScriptInterface::FromJSVal(rq, args[0], str)) return false; @@ -167,7 +167,7 @@ return true; } - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ std::wstring str; if (!ScriptInterface::FromJSVal(rq, args[0], str)) return false; @@ -185,7 +185,7 @@ return true; } - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ JS::RootedValue ret(cx); if (!JS_StructuredClone(rq.cx, args[0], &ret, NULL, NULL)) return false; @@ -197,11 +197,11 @@ bool deepfreeze(JSContext* cx, uint argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ if (args.length() != 1 || !args.get(0).isObject()) { - JS_ReportError(cx, "deepfreeze requires exactly one object as an argument."); + ScriptException::Raise(rq, "deepfreeze requires exactly one object as an argument."); return false; } @@ -215,7 +215,7 @@ const char* name = "(ProfileStart)"; JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ if (args.length() >= 1) { std::string str; @@ -257,7 +257,7 @@ const char* name = "(ProfileAttribute)"; JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - ScriptInterface::Request rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ + ScriptRequest rq(*ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface); \ if (args.length() >= 1) { std::string str; @@ -374,7 +374,7 @@ g_ScriptStatsTable->Add(this, debugName); } - Request rq(this); + ScriptRequest rq(this); m_CmptPrivate.pScriptInterface = this; JS_SetCompartmentPrivate(js::GetObjectCompartment(rq.glob), (void*)&m_CmptPrivate); } @@ -421,7 +421,7 @@ bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng) { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue math(rq.cx); JS::RootedObject global(rq.cx, rq.glob); if (JS_GetProperty(rq.cx, global, "Math", &math) && math.isObject()) @@ -436,6 +436,7 @@ } } + ScriptException::CatchPending(rq); LOGERROR("ReplaceNondeterministicRNG: failed to replace Math.random"); return false; } @@ -457,7 +458,7 @@ void ScriptInterface::CallConstructor(JS::HandleValue ctor, JS::HandleValueArray argv, JS::MutableHandleValue out) const { - Request rq(this); + ScriptRequest rq(this); if (!ctor.isObject()) { LOGERROR("CallConstructor: ctor is not an object"); @@ -471,7 +472,7 @@ void ScriptInterface::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) { - Request rq(this); + ScriptRequest rq(this); std::string typeName = clasp->name; if (m_CustomObjectTypes.find(typeName) != m_CustomObjectTypes.end()) @@ -488,7 +489,10 @@ static_ps, static_fs)); // Constructor properties, methods if (obj == NULL) + { + ScriptException::CatchPending(rq); throw PSERROR_Scripting_DefineType_CreationFailed(); + } CustomType& type = m_CustomObjectTypes[typeName]; @@ -504,14 +508,14 @@ if (it == m_CustomObjectTypes.end()) throw PSERROR_Scripting_TypeDoesNotExist(); - Request rq(this); + ScriptRequest 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 { - Request rq(this); + ScriptRequest rq(this); JS::RootedObject obj(rq.cx); if (!JS_ValueToObject(rq.cx, val, &obj) || !obj) return false; @@ -522,10 +526,14 @@ if (!JS_HasProperty(rq.cx, obj, name, &found) || !found) return false; - return JS_CallFunctionName(rq.cx, obj, name, argv, ret); + if (JS_CallFunctionName(rq.cx, obj, name, argv, ret)) + return true; + + ScriptException::CatchPending(rq); + return false; } -bool ScriptInterface::CreateObject_(const Request& rq, JS::MutableHandleObject object) +bool ScriptInterface::CreateObject_(const ScriptRequest& rq, JS::MutableHandleObject object) { object.set(JS_NewPlainObject(rq.cx)); @@ -535,7 +543,7 @@ return true; } -void ScriptInterface::CreateArray(const Request& rq, JS::MutableHandleValue objectValue, size_t length) +void ScriptInterface::CreateArray(const ScriptRequest& rq, JS::MutableHandleValue objectValue, size_t length) { objectValue.setObjectOrNull(JS_NewArrayObject(rq.cx, length)); if (!objectValue.isObject()) @@ -544,7 +552,7 @@ bool ScriptInterface::SetGlobal_(const char* name, JS::HandleValue value, bool replace, bool constant, bool enumerate) { - Request rq(this); + ScriptRequest rq(this); JS::RootedObject global(rq.cx, rq.glob); bool found; @@ -560,7 +568,7 @@ { if (!replace) { - JS_ReportError(rq.cx, "SetGlobal \"%s\" called multiple times", name); + ScriptException::Raise(rq, "SetGlobal \"%s\" called multiple times", name); return false; } @@ -568,7 +576,7 @@ // instead of using SetGlobal. if (!desc.configurable()) { - JS_ReportError(rq.cx, "The global \"%s\" is permanent and cannot be hotloaded", name); + ScriptException::Raise(rq, "The global \"%s\" is permanent and cannot be hotloaded", name); return false; } @@ -588,7 +596,7 @@ bool ScriptInterface::SetProperty_(JS::HandleValue obj, const char* name, JS::HandleValue value, bool constant, bool enumerate) const { - Request rq(this); + ScriptRequest rq(this); uint attrs = 0; if (constant) attrs |= JSPROP_READONLY | JSPROP_PERMANENT; @@ -599,14 +607,12 @@ return false; JS::RootedObject object(rq.cx, &obj.toObject()); - if (!JS_DefineProperty(rq.cx, object, name, value, attrs)) - return false; - return true; + return JS_DefineProperty(rq.cx, object, name, value, attrs); } bool ScriptInterface::SetProperty_(JS::HandleValue obj, const wchar_t* name, JS::HandleValue value, bool constant, bool enumerate) const { - Request rq(this); + ScriptRequest rq(this); uint attrs = 0; if (constant) attrs |= JSPROP_READONLY | JSPROP_PERMANENT; @@ -618,14 +624,12 @@ JS::RootedObject object(rq.cx, &obj.toObject()); utf16string name16(name, name + wcslen(name)); - if (!JS_DefineUCProperty(rq.cx, object, reinterpret_cast(name16.c_str()), name16.length(), value, attrs)) - return false; - return true; + return JS_DefineUCProperty(rq.cx, object, reinterpret_cast(name16.c_str()), name16.length(), value, attrs); } bool ScriptInterface::SetPropertyInt_(JS::HandleValue obj, int name, JS::HandleValue value, bool constant, bool enumerate) const { - Request rq(this); + ScriptRequest rq(this); uint attrs = 0; if (constant) attrs |= JSPROP_READONLY | JSPROP_PERMANENT; @@ -637,9 +641,7 @@ JS::RootedObject object(rq.cx, &obj.toObject()); JS::RootedId id(rq.cx, INT_TO_JSID(name)); - if (!JS_DefinePropertyById(rq.cx, object, id, value, attrs)) - return false; - return true; + return JS_DefinePropertyById(rq.cx, object, id, value, attrs); } bool ScriptInterface::GetProperty(JS::HandleValue obj, const char* name, JS::MutableHandleValue out) const @@ -649,7 +651,7 @@ bool ScriptInterface::GetProperty(JS::HandleValue obj, const char* name, JS::MutableHandleObject out) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue val(rq.cx); if (!GetProperty_(obj, name, &val)) return false; @@ -670,33 +672,28 @@ bool ScriptInterface::GetProperty_(JS::HandleValue obj, const char* name, JS::MutableHandleValue out) const { - Request rq(this); + ScriptRequest rq(this); if (!obj.isObject()) return false; JS::RootedObject object(rq.cx, &obj.toObject()); - if (!JS_GetProperty(rq.cx, object, name, out)) - return false; - return true; + return JS_GetProperty(rq.cx, object, name, out); } bool ScriptInterface::GetPropertyInt_(JS::HandleValue obj, int name, JS::MutableHandleValue out) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedId nameId(rq.cx, INT_TO_JSID(name)); if (!obj.isObject()) return false; JS::RootedObject object(rq.cx, &obj.toObject()); - if (!JS_GetPropertyById(rq.cx, object, nameId, out)) - return false; - return true; + return JS_GetPropertyById(rq.cx, object, nameId, out); } bool ScriptInterface::HasProperty(JS::HandleValue obj, const char* name) const { - // TODO: proper errorhandling - Request rq(this); + ScriptRequest rq(this); if (!obj.isObject()) return false; JS::RootedObject object(rq.cx, &obj.toObject()); @@ -709,7 +706,7 @@ bool ScriptInterface::EnumeratePropertyNames(JS::HandleValue objVal, bool enumerableOnly, std::vector& out) const { - Request rq(this); + ScriptRequest rq(this); if (!objVal.isObjectOrNull()) { @@ -748,7 +745,7 @@ bool ScriptInterface::SetPrototype(JS::HandleValue objVal, JS::HandleValue protoVal) { - Request rq(this); + ScriptRequest rq(this); if (!objVal.isObject() || !protoVal.isObject()) return false; JS::RootedObject obj(rq.cx, &objVal.toObject()); @@ -758,7 +755,7 @@ bool ScriptInterface::FreezeObject(JS::HandleValue objVal, bool deep) const { - Request rq(this); + ScriptRequest rq(this); if (!objVal.isObject()) return false; @@ -772,7 +769,7 @@ bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& code) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedObject global(rq.cx, rq.glob); utf16string codeUtf16(code.begin(), code.end()); uint lineNo = 1; @@ -788,15 +785,22 @@ JS::AutoObjectVector emptyScopeChain(rq.cx); if (!JS::CompileFunction(rq.cx, emptyScopeChain, options, NULL, 0, NULL, reinterpret_cast(codeUtf16.c_str()), (uint)(codeUtf16.length()), &func)) + { + ScriptException::CatchPending(rq); return false; + } JS::RootedValue rval(rq.cx); - return JS_CallFunction(rq.cx, nullptr, func, JS::HandleValueArray::empty(), &rval); + if (JS_CallFunction(rq.cx, nullptr, func, JS::HandleValueArray::empty(), &rval)) + return true; + + ScriptException::CatchPending(rq); + return false; } bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstring& code) const { - Request rq(this); + ScriptRequest rq(this); utf16string codeUtf16(code.begin(), code.end()); uint lineNo = 1; // CompileOptions does not copy the contents of the filename string pointer. @@ -806,13 +810,16 @@ JS::RootedValue rval(rq.cx); JS::CompileOptions opts(rq.cx); opts.setFileAndLine(filenameStr.c_str(), lineNo); - return JS::Evaluate(rq.cx, opts, - reinterpret_cast(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval); + if (JS::Evaluate(rq.cx, opts, reinterpret_cast(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval)) + return true; + + ScriptException::CatchPending(rq); + return false; } bool ScriptInterface::LoadGlobalScriptFile(const VfsPath& path) const { - Request rq(this); + ScriptRequest rq(this); if (!VfsFileExists(path)) { LOGERROR("File '%s' does not exist", path.string8()); @@ -840,66 +847,57 @@ JS::RootedValue rval(rq.cx); JS::CompileOptions opts(rq.cx); opts.setFileAndLine(filenameStr.c_str(), lineNo); - return JS::Evaluate(rq.cx, opts, - reinterpret_cast(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval); + if (JS::Evaluate(rq.cx, opts, reinterpret_cast(codeUtf16.c_str()), (uint)(codeUtf16.length()), &rval)) + return true; + + ScriptException::CatchPending(rq); + return false; } bool ScriptInterface::Eval(const char* code) const { - Request rq(this); + ScriptRequest rq(this); JS::RootedValue rval(rq.cx); return Eval_(code, &rval); } bool ScriptInterface::Eval_(const char* code, JS::MutableHandleValue rval) const { - Request rq(this); + ScriptRequest rq(this); utf16string codeUtf16(code, code+strlen(code)); JS::CompileOptions opts(rq.cx); opts.setFileAndLine("(eval)", 1); - return JS::Evaluate(rq.cx, opts, reinterpret_cast(codeUtf16.c_str()), (uint)codeUtf16.length(), rval); + if (JS::Evaluate(rq.cx, opts, reinterpret_cast(codeUtf16.c_str()), (uint)codeUtf16.length(), rval)) + return true; + + ScriptException::CatchPending(rq); + return false; } bool ScriptInterface::Eval_(const wchar_t* code, JS::MutableHandleValue rval) const { - Request rq(this); + ScriptRequest rq(this); utf16string codeUtf16(code, code+wcslen(code)); JS::CompileOptions opts(rq.cx); opts.setFileAndLine("(eval)", 1); - return JS::Evaluate(rq.cx, opts, reinterpret_cast(codeUtf16.c_str()), (uint)codeUtf16.length(), rval); + if (JS::Evaluate(rq.cx, opts, reinterpret_cast(codeUtf16.c_str()), (uint)codeUtf16.length(), rval)) + return true; + + ScriptException::CatchPending(rq); + return false; } bool ScriptInterface::ParseJSON(const std::string& string_utf8, JS::MutableHandleValue out) const { - Request rq(this); + ScriptRequest rq(this); std::wstring attrsW = wstring_from_utf8(string_utf8); utf16string string(attrsW.begin(), attrsW.end()); if (JS_ParseJSON(rq.cx, reinterpret_cast(string.c_str()), (u32)string.size(), out)) return true; - LOGERROR("JS_ParseJSON failed!"); - if (!JS_IsExceptionPending(rq.cx)) - return false; - - JS::RootedValue exc(rq.cx); - if (!JS_GetPendingException(rq.cx, &exc)) - return false; - - JS_ClearPendingException(rq.cx); - // We expect an object of type SyntaxError - if (!exc.isObject()) - return false; - - 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(rq, rval, error); - LOGERROR("%s", utf8_from_wstring(error)); + ScriptException::CatchPending(rq); return false; } @@ -946,13 +944,12 @@ // It probably has historical reasons and could be changed by SpiderMonkey in the future. std::string ScriptInterface::StringifyJSON(JS::MutableHandleValue obj, bool indent) const { - Request rq(this); + ScriptRequest rq(this); Stringifier 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(rq.cx); - LOGERROR("StringifyJSON failed"); + ScriptException::CatchPending(rq); return std::string(); } @@ -962,7 +959,7 @@ std::string ScriptInterface::ToString(JS::MutableHandleValue obj, bool pretty) const { - Request rq(this); + ScriptRequest rq(this); if (obj.isUndefined()) return "(void 0)"; @@ -985,7 +982,7 @@ if (ok) return str.stream.str(); - // Clear the exception set when Stringify failed + // Drop exceptions raised by cyclic values before trying something else JS_ClearPendingException(rq.cx); } @@ -997,29 +994,10 @@ return utf8_from_wstring(source); } -void ScriptInterface::ReportError(const char* msg) const -{ - 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(rq.cx, JS::UndefinedHandleValue); - // And report the actual error - JS_ReportError(rq.cx, "%s", msg); - - // TODO: Why doesn't JS_ReportPendingException(cx); work? -} - -bool ScriptInterface::IsExceptionPending(const Request& rq) -{ - return JS_IsExceptionPending(rq.cx) ? true : false; -} - JS::Value ScriptInterface::CloneValueFromOtherCompartment(const ScriptInterface& otherCompartment, JS::HandleValue val) const { PROFILE("CloneValueFromOtherCompartment"); - Request rq(this); + ScriptRequest rq(this); JS::RootedValue out(rq.cx); shared_ptr structuredClone = otherCompartment.WriteStructuredClone(val); ReadStructuredClone(structuredClone, &out); @@ -1039,12 +1017,13 @@ shared_ptr ScriptInterface::WriteStructuredClone(JS::HandleValue v) const { - Request rq(this); + ScriptRequest rq(this); u64* data = NULL; size_t nbytes = 0; if (!JS_WriteStructuredClone(rq.cx, v, &data, &nbytes, NULL, NULL, JS::UndefinedHandleValue)) { debug_warn(L"Writing a structured clone with JS_WriteStructuredClone failed!"); + ScriptException::CatchPending(rq); return shared_ptr(); } @@ -1056,6 +1035,7 @@ void ScriptInterface::ReadStructuredClone(const shared_ptr& ptr, JS::MutableHandleValue ret) const { - Request rq(this); - JS_ReadStructuredClone(rq.cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, ret, NULL, NULL); + ScriptRequest rq(this); + if (!JS_ReadStructuredClone(rq.cx, ptr->m_Data, ptr->m_Size, JS_STRUCTURED_CLONE_VERSION, ret, NULL, NULL)) + ScriptException::CatchPending(rq); } Index: ps/trunk/source/scriptinterface/tests/test_ScriptConversions.h =================================================================== --- ps/trunk/source/scriptinterface/tests/test_ScriptConversions.h +++ ps/trunk/source/scriptinterface/tests/test_ScriptConversions.h @@ -35,7 +35,7 @@ { ScriptInterface script("Test", "Test", g_ScriptContext); TS_ASSERT(script.LoadGlobalScripts()); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); JS::RootedValue v1(rq.cx); ScriptInterface::ToJSVal(rq, &v1, value); @@ -54,7 +54,7 @@ { ScriptInterface script("Test", "Test", g_ScriptContext); TS_ASSERT(script.LoadGlobalScripts()); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); JS::RootedValue v1(rq.cx); ScriptInterface::ToJSVal(rq, &v1, value); @@ -76,7 +76,7 @@ { ScriptInterface script("Test", "Test", g_ScriptContext); TS_ASSERT(script.LoadGlobalScripts()); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); JS::RootedValue v1(rq.cx); ScriptInterface::ToJSVal(rq, &v1, v); @@ -169,7 +169,7 @@ void test_integers() { ScriptInterface script("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest 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(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); @@ -201,7 +201,7 @@ convert_to(std::numeric_limits::quiet_NaN(), "NaN"); // can't use roundtrip since nan != nan ScriptInterface script("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); float f = 0; JS::RootedValue testNANVal(rq.cx); @@ -252,7 +252,7 @@ // Fancier conversion: we store UTF8 and get UTF16 and vice-versa ScriptInterface script("Test", "Test", g_ScriptContext); TS_ASSERT(script.LoadGlobalScripts()); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); std::string in_utf8("éè!§$-aezi134900°°©©¢¢ÇÇ‘{¶«¡Ç’[å»ÛÁØ"); std::wstring in_utf16(L"éè!§$-aezi134900°°©©¢¢ÇÇ‘{¶«¡Ç’[å»ÛÁØ"); Index: ps/trunk/source/scriptinterface/tests/test_ScriptInterface.h =================================================================== --- ps/trunk/source/scriptinterface/tests/test_ScriptInterface.h +++ ps/trunk/source/scriptinterface/tests/test_ScriptInterface.h @@ -40,7 +40,7 @@ ScriptInterface script("Test", "Test", g_ScriptContext); TestLogger logger; TS_ASSERT(!script.LoadScript(L"test.js", "1+")); - TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "JavaScript error: test.js line 1\nSyntaxError: expected expression, got end of script"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "ERROR: JavaScript error: test.js line 1\nSyntaxError: expected expression, got end of script"); } void test_loadscript_strict_warning() @@ -57,7 +57,7 @@ ScriptInterface script("Test", "Test", g_ScriptContext); TestLogger logger; TS_ASSERT(!script.LoadScript(L"test.js", "with(1){}")); - TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "JavaScript error: test.js line 1\nSyntaxError: strict mode code may not contain \'with\' statements"); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "ERROR: JavaScript error: test.js line 1\nSyntaxError: strict mode code may not contain \'with\' statements"); } void test_clone_basic() @@ -65,12 +65,12 @@ ScriptInterface script1("Test", "Test", g_ScriptContext); ScriptInterface script2("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq1(script1); + ScriptRequest rq1(script1); JS::RootedValue obj1(rq1.cx); TS_ASSERT(script1.Eval("({'x': 123, 'y': [1, 1.5, '2', 'test', undefined, null, true, false]})", &obj1)); { - ScriptInterface::Request rq2(script2); + ScriptRequest rq2(script2); JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); @@ -86,13 +86,13 @@ ScriptInterface script1("Test", "Test", g_ScriptContext); ScriptInterface script2("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq1(script1); + ScriptRequest rq1(script1); 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)); { - ScriptInterface::Request rq2(script2); + ScriptRequest rq2(script2); JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); @@ -107,13 +107,13 @@ ScriptInterface script1("Test", "Test", g_ScriptContext); ScriptInterface script2("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq1(script1); + ScriptRequest rq1(script1); JS::RootedValue obj1(rq1.cx); TS_ASSERT(script1.Eval("var x = []; x[0] = x; ({'a': x, 'b': x})", &obj1)); { - ScriptInterface::Request rq2(script2); + ScriptRequest rq2(script2); JS::RootedValue obj2(rq2.cx, script2.CloneValueFromOtherCompartment(script1, obj1)); // Use JSAPI function to check if the values of the properties "a", "b" are equals a.x[0] @@ -138,7 +138,7 @@ { ScriptInterface script("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); JS::RootedValue val(rq.cx); JS::RootedValue out(rq.cx); @@ -183,7 +183,7 @@ void handle_templates_test(const ScriptInterface& script, JS::HandleValue val, JS::MutableHandleValue out, JS::HandleValue nbrVal) { - ScriptInterface::Request rq(script); + ScriptRequest rq(script); int nbr = 0; @@ -236,7 +236,7 @@ void test_json() { ScriptInterface script("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); std::string input = "({'x':1,'z':[2,'3\\u263A\\ud800'],\"y\":true})"; JS::RootedValue val(rq.cx); @@ -254,7 +254,7 @@ void test_function_override() { ScriptInterface script("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); TS_ASSERT(script.Eval( "function f() { return 1; }" Index: ps/trunk/source/simulation2/Simulation2.cpp =================================================================== --- ps/trunk/source/simulation2/Simulation2.cpp +++ ps/trunk/source/simulation2/Simulation2.cpp @@ -170,7 +170,7 @@ std::vector newCommands; newCommands.reserve(commands.size()); - ScriptInterface::Request rqNew(newScript); + ScriptRequest rqNew(newScript); for (const SimulationCommand& command : commands) { JS::RootedValue tmpCommand(rqNew.cx, newScript.CloneValueFromOtherCompartment(oldScript, command.data)); @@ -421,7 +421,7 @@ // Load the trigger scripts after we have loaded the simulation. { - ScriptInterface::Request rq2(m_SecondaryComponentManager->GetScriptInterface()); + ScriptRequest rq2(m_SecondaryComponentManager->GetScriptInterface()); JS::RootedValue mapSettingsCloned(rq2.cx, m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherCompartment( scriptInterface, m_MapSettings)); @@ -733,14 +733,14 @@ void CSimulation2::PreInitGame() { - ScriptInterface::Request rq(GetScriptInterface()); + ScriptRequest rq(GetScriptInterface()); JS::RootedValue global(rq.cx, rq.globalValue()); GetScriptInterface().CallFunctionVoid(global, "PreInitGame"); } void CSimulation2::InitGame() { - ScriptInterface::Request rq(GetScriptInterface()); + ScriptRequest rq(GetScriptInterface()); JS::RootedValue global(rq.cx, rq.globalValue()); JS::RootedValue settings(rq.cx); @@ -839,14 +839,14 @@ void CSimulation2::LoadPlayerSettings(bool newPlayers) { - ScriptInterface::Request rq(GetScriptInterface()); + ScriptRequest rq(GetScriptInterface()); JS::RootedValue global(rq.cx, rq.globalValue()); GetScriptInterface().CallFunctionVoid(global, "LoadPlayerSettings", m->m_MapSettings, newPlayers); } void CSimulation2::LoadMapSettings() { - ScriptInterface::Request rq(GetScriptInterface()); + ScriptRequest rq(GetScriptInterface()); JS::RootedValue global(rq.cx, rq.globalValue()); @@ -982,7 +982,7 @@ std::string CSimulation2::GetAIData() { const ScriptInterface& scriptInterface = GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue aiData(rq.cx, ICmpAIManager::GetAIs(scriptInterface)); // Build single JSON string with array of AI data Index: ps/trunk/source/simulation2/components/CCmpAIManager.cpp =================================================================== --- ps/trunk/source/simulation2/components/CCmpAIManager.cpp +++ ps/trunk/source/simulation2/components/CCmpAIManager.cpp @@ -96,7 +96,7 @@ if (!m_Worker.LoadScripts(m_AIName)) return false; - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; JS::RootedValue metadata(rq.cx); @@ -312,7 +312,7 @@ { ENSURE(pCmptPrivate->pCBData); CAIWorker* self = static_cast (pCmptPrivate->pCBData); - ScriptInterface::Request rq(self->m_ScriptInterface); + ScriptRequest rq(self->m_ScriptInterface); CFixedVector2D pos, goalPos; std::vector waypoints; @@ -402,7 +402,7 @@ bool TryLoadSharedComponent() { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); // we don't need to load it. if (!m_HasSharedComponent) @@ -491,7 +491,7 @@ // 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. - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); JS::RootedValue state(rq.cx); m_ScriptInterface->ReadStructuredClone(gameState, &state); @@ -545,7 +545,7 @@ m_HierarchicalPathfinder.Update(&m_PassabilityMap, dirtinessGrid); } - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); if (dimensionChange || justDeserialized) ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, m_PassabilityMap); else @@ -573,7 +573,7 @@ m_TerritoryMap = territoryMap; - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); if (dimensionChange) ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, m_TerritoryMap); else @@ -623,7 +623,7 @@ void LoadEntityTemplates(const std::vector >& templates) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); m_HasLoadedEntityTemplates = true; @@ -659,7 +659,7 @@ if (m_Players.empty()) return; - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); std::stringstream rngStream; rngStream << m_RNG; @@ -721,7 +721,7 @@ if (numAis == 0) return; - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); ENSURE(m_CommandsComputed); // deserializing while we're still actively computing would be bad @@ -833,7 +833,7 @@ void PerformComputation() { // Deserialize the game state, to pass to the AI's HandleMessage - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); JS::RootedValue state(rq.cx); { PROFILE3("AI compute read state"); @@ -986,7 +986,7 @@ virtual void RunGamestateInit() { const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); CmpPtr cmpAIInterface(GetSystemEntity()); ENSURE(cmpAIInterface); @@ -1024,7 +1024,7 @@ PROFILE("AI setup"); const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); if (m_Worker.getPlayerSize() == 0) return; @@ -1088,7 +1088,7 @@ return; const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue clonedCommandVal(rq.cx); for (size_t i = 0; i < commands.size(); ++i) @@ -1139,7 +1139,7 @@ return; const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue classesVal(rq.cx); ScriptInterface::CreateObject(rq, &classesVal); Index: ps/trunk/source/simulation2/components/CCmpCommandQueue.cpp =================================================================== --- ps/trunk/source/simulation2/components/CCmpCommandQueue.cpp +++ ps/trunk/source/simulation2/components/CCmpCommandQueue.cpp @@ -51,7 +51,7 @@ virtual void Serialize(ISerializer& serialize) { - ScriptInterface::Request rq(GetSimContext().GetScriptInterface()); + ScriptRequest rq(GetSimContext().GetScriptInterface()); serialize.NumberU32_Unbounded("num commands", (u32)m_LocalQueue.size()); for (size_t i = 0; i < m_LocalQueue.size(); ++i) @@ -63,7 +63,7 @@ virtual void Deserialize(const CParamNode& UNUSED(paramNode), IDeserializer& deserialize) { - ScriptInterface::Request rq(GetSimContext().GetScriptInterface()); + ScriptRequest rq(GetSimContext().GetScriptInterface()); u32 numCmds; deserialize.NumberU32_Unbounded("num commands", numCmds); @@ -79,13 +79,13 @@ virtual void PushLocalCommand(player_id_t player, JS::HandleValue cmd) { - ScriptInterface::Request rq(GetSimContext().GetScriptInterface()); + ScriptRequest rq(GetSimContext().GetScriptInterface()); m_LocalQueue.emplace_back(SimulationCommand(player, rq.cx, cmd)); } virtual void PostNetworkCommand(JS::HandleValue cmd1) { - ScriptInterface::Request rq(GetSimContext().GetScriptInterface()); + ScriptRequest rq(GetSimContext().GetScriptInterface()); // TODO: This is a workaround because we need to pass a MutableHandle to StringifyJSON. JS::RootedValue cmd(rq.cx, cmd1.get()); @@ -101,7 +101,7 @@ virtual void FlushTurn(const std::vector& commands) { const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue global(rq.cx, rq.globalValue()); std::vector localCommands; Index: ps/trunk/source/simulation2/components/ICmpAIManager.cpp =================================================================== --- ps/trunk/source/simulation2/components/ICmpAIManager.cpp +++ ps/trunk/source/simulation2/components/ICmpAIManager.cpp @@ -41,7 +41,7 @@ m_ScriptInterface(scriptInterface), m_AIs(scriptInterface.GetJSRuntime()) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); m_AIs = JS_NewArrayObject(rq.cx, 0); } @@ -53,7 +53,7 @@ static Status Callback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData) { GetAIsHelper* self = (GetAIsHelper*)cbData; - ScriptInterface::Request rq(self->m_ScriptInterface); + ScriptRequest rq(self->m_ScriptInterface); // Extract the 3rd component of the path (i.e. the directory after simulation/ai/) fs::wpath components = pathname.string(); Index: ps/trunk/source/simulation2/components/ICmpFootprint.cpp =================================================================== --- ps/trunk/source/simulation2/components/ICmpFootprint.cpp +++ ps/trunk/source/simulation2/components/ICmpFootprint.cpp @@ -30,7 +30,7 @@ entity_pos_t size0, size1, height; GetShape(shape, size0, size1, height); - ScriptInterface::Request rq(GetSimContext().GetScriptInterface()); + ScriptRequest rq(GetSimContext().GetScriptInterface()); JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx)); if (!obj) Index: ps/trunk/source/simulation2/components/tests/test_CommandQueue.h =================================================================== --- ps/trunk/source/simulation2/components/tests/test_CommandQueue.h +++ ps/trunk/source/simulation2/components/tests/test_CommandQueue.h @@ -35,7 +35,7 @@ void test_basic() { ComponentTestHelper test(g_ScriptContext); - ScriptInterface::Request rq(test.GetScriptInterface()); + ScriptRequest rq(test.GetScriptInterface()); std::vector empty; Index: ps/trunk/source/simulation2/scripting/EngineScriptConversions.cpp =================================================================== --- ps/trunk/source/simulation2/scripting/EngineScriptConversions.cpp +++ ps/trunk/source/simulation2/scripting/EngineScriptConversions.cpp @@ -31,10 +31,10 @@ #include "simulation2/system/IComponent.h" #include "simulation2/system/ParamNode.h" -#define FAIL(msg) STMT(JS_ReportError(rq.cx, msg); return false) -#define FAIL_VOID(msg) STMT(JS_ReportError(rq.cx, msg); return) +#define FAIL(msg) STMT(LOGERROR(msg); return false) +#define FAIL_VOID(msg) STMT(ScriptException::Raise(rq, msg); return) -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, IComponent* const& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, IComponent* const& val) { if (val == NULL) { @@ -65,7 +65,7 @@ ret.setObject(*obj); } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, CParamNode const& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, CParamNode const& val) { val.ToJSVal(rq, true, ret); @@ -78,7 +78,7 @@ } } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CParamNode* const& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CParamNode* const& val) { if (val) ToJSVal(rq, ret, *val); @@ -86,7 +86,7 @@ ret.setUndefined(); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CColor& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CColor& out) { if (!v.isObject()) FAIL("CColor has to be an object"); @@ -109,7 +109,7 @@ return true; } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, CColor const& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, CColor const& val) { CreateObject( rq, @@ -120,7 +120,7 @@ "a", val.a); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, fixed& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, fixed& out) { double ret; if (!JS::ToNumber(rq.cx, v, &ret)) @@ -131,12 +131,12 @@ return true; } -template<> void ScriptInterface::ToJSVal(const Request& UNUSED(rq), JS::MutableHandleValue ret, const fixed& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const fixed& val) { ret.set(JS::NumberValue(val.ToDouble())); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CFixedVector3D& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CFixedVector3D& out) { if (!v.isObject()) return false; // TODO: report type error @@ -156,7 +156,7 @@ return true; } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CFixedVector3D& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CFixedVector3D& val) { JS::RootedObject global(rq.cx, rq.glob); JS::RootedValue valueVector3D(rq.cx); @@ -172,7 +172,7 @@ FAIL_VOID("Failed to construct Vector3D object"); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CFixedVector2D& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CFixedVector2D& out) { if (!v.isObject()) return false; // TODO: report type error @@ -189,7 +189,7 @@ return true; } -template<> void ScriptInterface::ToJSVal(const Request& rq, JS::MutableHandleValue ret, const CFixedVector2D& val) +template<> void ScriptInterface::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const CFixedVector2D& val) { JS::RootedObject global(rq.cx, rq.glob); JS::RootedValue valueVector2D(rq.cx); @@ -204,7 +204,7 @@ FAIL_VOID("Failed to construct Vector2D object"); } -template<> void ScriptInterface::ToJSVal >(const Request& rq, JS::MutableHandleValue ret, const Grid& val) +template<> void ScriptInterface::ToJSVal >(const ScriptRequest& rq, JS::MutableHandleValue ret, const Grid& val) { u32 length = (u32)(val.m_W * val.m_H); u32 nbytes = (u32)(length * sizeof(u8)); @@ -225,7 +225,7 @@ "data", data); } -template<> void ScriptInterface::ToJSVal >(const Request& rq, JS::MutableHandleValue ret, const Grid& val) +template<> void ScriptInterface::ToJSVal >(const ScriptRequest& rq, JS::MutableHandleValue ret, const Grid& val) { u32 length = (u32)(val.m_W * val.m_H); u32 nbytes = (u32)(length * sizeof(u16)); @@ -246,7 +246,7 @@ "data", data); } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, TNSpline& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, TNSpline& out) { if (!v.isObject()) FAIL("Argument must be an object"); @@ -283,7 +283,7 @@ return true; } -template<> bool ScriptInterface::FromJSVal(const Request& rq, JS::HandleValue v, CCinemaPath& out) +template<> bool ScriptInterface::FromJSVal(const ScriptRequest& rq, JS::HandleValue v, CCinemaPath& out) { if (!v.isObject()) FAIL("Argument must be an object"); Index: ps/trunk/source/simulation2/scripting/JSInterface_Simulation.cpp =================================================================== --- ps/trunk/source/simulation2/scripting/JSInterface_Simulation.cpp +++ ps/trunk/source/simulation2/scripting/JSInterface_Simulation.cpp @@ -50,7 +50,7 @@ if (!cmpGuiInterface) return JS::UndefinedValue(); - ScriptInterface::Request rqSim(sim->GetScriptInterface()); + ScriptRequest rqSim(sim->GetScriptInterface()); JS::RootedValue arg(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), data)); JS::RootedValue ret(rqSim.cx); cmpGuiInterface->ScriptCall(g_Game->GetViewedPlayerID(), name, arg, &ret); @@ -70,7 +70,7 @@ if (!cmpCommandQueue) return; - ScriptInterface::Request rqSim(sim->GetScriptInterface()); + ScriptRequest rqSim(sim->GetScriptInterface()); JS::RootedValue cmd2(rqSim.cx, sim->GetScriptInterface().CloneValueFromOtherCompartment(*(pCmptPrivate->pScriptInterface), cmd)); cmpCommandQueue->PostNetworkCommand(cmd2); @@ -124,7 +124,7 @@ CSimulation2* sim = g_Game->GetSimulation2(); ENSURE(sim); - ScriptInterface::Request rq(pCmptPrivate); + ScriptRequest rq(pCmptPrivate->pScriptInterface); JS::RootedValue edgeList(rq.cx); ScriptInterface::CreateArray(rq, &edgeList); int edgeListIndex = 0; Index: ps/trunk/source/simulation2/scripting/MessageTypeConversions.cpp =================================================================== --- ps/trunk/source/simulation2/scripting/MessageTypeConversions.cpp +++ ps/trunk/source/simulation2/scripting/MessageTypeConversions.cpp @@ -21,7 +21,7 @@ #include "simulation2/MessageTypes.h" #define TOJSVAL_SETUP() \ - ScriptInterface::Request rq(scriptInterface); \ + ScriptRequest rq(scriptInterface); \ JS::RootedObject obj(rq.cx, JS_NewPlainObject(rq.cx)); \ if (!obj) \ return JS::UndefinedValue(); @@ -35,7 +35,7 @@ } while (0); #define FROMJSVAL_SETUP() \ - ScriptInterface::Request rq(scriptInterface); \ + ScriptRequest rq(scriptInterface); \ if (val.isPrimitive()) \ return NULL; \ JS::RootedObject obj(rq.cx, &val.toObject()); \ Index: ps/trunk/source/simulation2/scripting/ScriptComponent.cpp =================================================================== --- ps/trunk/source/simulation2/scripting/ScriptComponent.cpp +++ ps/trunk/source/simulation2/scripting/ScriptComponent.cpp @@ -26,7 +26,7 @@ m_ScriptInterface(scriptInterface), m_Instance(scriptInterface.GetJSRuntime(), instance) { // Cache the property detection for efficiency - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); m_HasCustomSerialize = m_ScriptInterface.HasProperty(m_Instance, "Serialize"); m_HasCustomDeserialize = m_ScriptInterface.HasProperty(m_Instance, "Deserialize"); @@ -54,7 +54,7 @@ void CComponentTypeScript::HandleMessage(const CMessage& msg, bool global) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); const char* name = global ? msg.GetScriptGlobalHandlerName() : msg.GetScriptHandlerName(); @@ -70,7 +70,7 @@ if (m_HasNullSerialize) return; - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); // Support a custom "Serialize" function, which returns a new object that will be // serialized instead of the component itself @@ -89,7 +89,7 @@ void CComponentTypeScript::Deserialize(const CParamNode& paramNode, IDeserializer& deserialize, entity_id_t ent) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); m_ScriptInterface.SetProperty(m_Instance, "entity", (int)ent, true, false); m_ScriptInterface.SetProperty(m_Instance, "template", paramNode, true, false); Index: ps/trunk/source/simulation2/serialization/BinarySerializer.cpp =================================================================== --- ps/trunk/source/simulation2/serialization/BinarySerializer.cpp +++ ps/trunk/source/simulation2/serialization/BinarySerializer.cpp @@ -57,14 +57,14 @@ CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(const ScriptInterface& scriptInterface, ISerializer& serializer) : m_ScriptInterface(scriptInterface), m_Serializer(serializer), m_ScriptBackrefsNext(0) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); m_ScriptBackrefSymbol.init(rq.cx, JS::NewSymbol(rq.cx, nullptr)); } void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); switch (JS_TypeOfValue(rq.cx, val)) { @@ -375,7 +375,7 @@ void CBinarySerializerScriptImpl::ScriptString(const char* name, JS::HandleString string) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); #if BYTE_ORDER != LITTLE_ENDIAN #error TODO: probably need to convert JS strings to little-endian @@ -415,7 +415,7 @@ // 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). - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); JS::RootedValue symbolValue(rq.cx, JS::SymbolValue(m_ScriptBackrefSymbol)); JS::RootedId symbolId(rq.cx); Index: ps/trunk/source/simulation2/serialization/StdDeserializer.cpp =================================================================== --- ps/trunk/source/simulation2/serialization/StdDeserializer.cpp +++ ps/trunk/source/simulation2/serialization/StdDeserializer.cpp @@ -112,7 +112,7 @@ JS::Value CStdDeserializer::ReadScriptVal(const char* UNUSED(name), JS::HandleObject appendParent) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); uint8_t type; NumberU8_Unbounded("type", type); @@ -405,7 +405,7 @@ #error TODO: probably need to convert JS strings from little-endian #endif - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); bool isLatin1; Bool("isLatin1", isLatin1); @@ -436,7 +436,7 @@ void CStdDeserializer::ScriptObjectAppend(const char* name, JS::HandleValue objVal) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); if (!objVal.isObject()) throw PSERROR_Deserialize_ScriptError(); Index: ps/trunk/source/simulation2/system/ComponentManager.cpp =================================================================== --- ps/trunk/source/simulation2/system/ComponentManager.cpp +++ ps/trunk/source/simulation2/system/ComponentManager.cpp @@ -152,13 +152,13 @@ void CComponentManager::Script_RegisterComponentType_Common(ScriptInterface::CmptPrivate* pCmptPrivate, int iid, const std::string& cname, JS::HandleValue ctor, bool reRegister, bool systemComponent) { CComponentManager* componentManager = static_cast (pCmptPrivate->pCBData); - ScriptInterface::Request rq(componentManager->m_ScriptInterface); + ScriptRequest rq(componentManager->m_ScriptInterface); // Find the C++ component that wraps the interface int cidWrapper = componentManager->GetScriptWrapper(iid); if (cidWrapper == CID__Invalid) { - componentManager->m_ScriptInterface.ReportError("Invalid interface id"); + ScriptException::Raise(rq, "Invalid interface id"); return; } const ComponentType& ctWrapper = componentManager->m_ComponentTypesById[cidWrapper]; @@ -170,7 +170,7 @@ { if (reRegister) { - componentManager->m_ScriptInterface.ReportError(("ReRegistering component type that was not registered before '" + cname + "'").c_str()); + ScriptException::Raise(rq, "ReRegistering component type that was not registered before '%s'", cname.c_str()); return; } // Allocate a new cid number @@ -185,7 +185,7 @@ if (!componentManager->m_CurrentlyHotloading && !reRegister) { - componentManager->m_ScriptInterface.ReportError(("Registering component type with already-registered name '" + cname + "'").c_str()); + ScriptException::Raise(rq, "Registering component type with already-registered name '%s'", cname.c_str()); return; } @@ -194,7 +194,7 @@ // We can only replace scripted component types, not native ones if (ctPrevious.type != CT_Script) { - componentManager->m_ScriptInterface.ReportError(("Loading script component type with same name '" + cname + "' as native component").c_str()); + ScriptException::Raise(rq, "Loading script component type with same name '%s' as native component", cname.c_str()); return; } @@ -205,7 +205,7 @@ // ...though it only matters if any components exist with this type if (!componentManager->m_ComponentsByTypeId[cid].empty()) { - componentManager->m_ScriptInterface.ReportError("Hotloading script component type mustn't change interface ID"); + ScriptException::Raise(rq, "Hotloading script component type mustn't change interface ID"); return; } } @@ -233,12 +233,12 @@ JS::RootedValue protoVal(rq.cx); if (!componentManager->m_ScriptInterface.GetProperty(ctor, "prototype", &protoVal)) { - componentManager->m_ScriptInterface.ReportError("Failed to get property 'prototype'"); + ScriptException::Raise(rq, "Failed to get property 'prototype'"); return; } if (!protoVal.isObject()) { - componentManager->m_ScriptInterface.ReportError("Component has no constructor"); + ScriptException::Raise(rq, "Component has no constructor"); return; } std::string schema = ""; @@ -265,7 +265,7 @@ if (!componentManager->m_ScriptInterface.EnumeratePropertyNames(protoVal, false, methods)) { - componentManager->m_ScriptInterface.ReportError("Failed to enumerate component properties."); + ScriptException::Raise(rq, "Failed to enumerate component properties."); return; } @@ -288,7 +288,7 @@ std::map::const_iterator mit = componentManager->m_MessageTypeIdsByName.find(name); if (mit == componentManager->m_MessageTypeIdsByName.end()) { - componentManager->m_ScriptInterface.ReportError(("Registered component has unrecognized '" + *it + "' message handler method").c_str()); + ScriptException::Raise(rq, "Registered component has unrecognized '%s' message handler method", it->c_str()); return; } @@ -344,7 +344,10 @@ // Redefinitions are fine (and just get ignored) when hotloading; otherwise // they're probably unintentional and should be reported if (!componentManager->m_CurrentlyHotloading) - componentManager->m_ScriptInterface.ReportError(("Registering interface with already-registered name '" + name + "'").c_str()); + { + ScriptRequest rq(componentManager->m_ScriptInterface); + ScriptException::Raise(rq, "Registering interface with already-registered name '%s'", name.c_str()); + } return; } @@ -365,7 +368,10 @@ // Redefinitions are fine (and just get ignored) when hotloading; otherwise // they're probably unintentional and should be reported if (!componentManager->m_CurrentlyHotloading) - componentManager->m_ScriptInterface.ReportError(("Registering message type with already-registered name '" + name + "'").c_str()); + { + ScriptRequest rq(componentManager->m_ScriptInterface); + ScriptException::Raise(rq, "Registering message type with already-registered name '%s'", name.c_str()); + } return; } @@ -729,7 +735,7 @@ IComponent* CComponentManager::ConstructComponent(CEntityHandle ent, ComponentTypeId cid) { - ScriptInterface::Request rq(m_ScriptInterface); + ScriptRequest rq(m_ScriptInterface); std::map::const_iterator it = m_ComponentTypesById.find(cid); if (it == m_ComponentTypesById.end()) Index: ps/trunk/source/simulation2/system/ParamNode.h =================================================================== --- ps/trunk/source/simulation2/system/ParamNode.h +++ ps/trunk/source/simulation2/system/ParamNode.h @@ -22,14 +22,15 @@ #include "maths/Fixed.h" #include "ps/CStrIntern.h" #include "ps/Errors.h" -#include "scriptinterface/ScriptInterface.h" - +#include "scriptinterface/ScriptTypes.h" #include #include class XMBFile; class XMBElement; +class ScriptRequest; + /** * An entity initialisation parameter node. * Each node has a text value, plus a number of named child nodes (in a tree structure). @@ -248,7 +249,7 @@ * 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(const ScriptInterface::Request& rq, bool cacheValue, JS::MutableHandleValue ret) const; + void ToJSVal(const ScriptRequest& rq, bool cacheValue, JS::MutableHandleValue ret) const; /** * Returns the names/nodes of the children of this node, ordered by name @@ -275,7 +276,7 @@ void ResetScriptVal(); - void ConstructJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue ret) const; + void ConstructJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret) const; std::wstring m_Value; ChildrenMap m_Childs; Index: ps/trunk/source/simulation2/system/ParamNode.cpp =================================================================== --- ps/trunk/source/simulation2/system/ParamNode.cpp +++ ps/trunk/source/simulation2/system/ParamNode.cpp @@ -358,7 +358,7 @@ } } -void CParamNode::ToJSVal(const ScriptInterface::Request& rq, bool cacheValue, JS::MutableHandleValue ret) const +void CParamNode::ToJSVal(const ScriptRequest& rq, bool cacheValue, JS::MutableHandleValue ret) const { if (cacheValue && m_ScriptVal != NULL) { @@ -372,7 +372,7 @@ m_ScriptVal.reset(new JS::PersistentRootedValue(rq.cx, ret)); } -void CParamNode::ConstructJSVal(const ScriptInterface::Request& rq, JS::MutableHandleValue ret) const +void CParamNode::ConstructJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret) const { if (m_Childs.empty()) { Index: ps/trunk/source/simulation2/system/ReplayTurnManager.cpp =================================================================== --- ps/trunk/source/simulation2/system/ReplayTurnManager.cpp +++ ps/trunk/source/simulation2/system/ReplayTurnManager.cpp @@ -87,7 +87,7 @@ LOGERROR("Replay out of sync on turn %d", turn); const ScriptInterface& scriptInterface = m_Simulation2.GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::AutoValueVector paramData(rq.cx); @@ -110,7 +110,7 @@ m_TurnLength = m_ReplayTurnLengths[turn]; - ScriptInterface::Request rq(m_Simulation2.GetScriptInterface()); + ScriptRequest rq(m_Simulation2.GetScriptInterface()); // Simulate commands for that turn for (const std::pair& p : m_ReplayCommands[turn]) Index: ps/trunk/source/simulation2/system/TurnManager.cpp =================================================================== --- ps/trunk/source/simulation2/system/TurnManager.cpp +++ ps/trunk/source/simulation2/system/TurnManager.cpp @@ -240,7 +240,7 @@ m_Simulation2.GetScriptInterface().FreezeObject(data, true); - ScriptInterface::Request rq(m_Simulation2.GetScriptInterface()); + ScriptRequest rq(m_Simulation2.GetScriptInterface()); m_QueuedCommands[turn - (m_CurrentTurn+1)][client].emplace_back(player, rq.cx, data); } @@ -304,7 +304,7 @@ m_QuickSaveState = stream.str(); - ScriptInterface::Request rq(m_Simulation2.GetScriptInterface()); + ScriptRequest rq(m_Simulation2.GetScriptInterface()); if (JS_StructuredClone(rq.cx, GUIMetadata, &m_QuickSaveMetadata, nullptr, nullptr)) { @@ -343,7 +343,7 @@ if (!g_GUI) return; - ScriptInterface::Request rq(m_Simulation2.GetScriptInterface()); + ScriptRequest rq(m_Simulation2.GetScriptInterface()); // Provide a copy, so that GUI components don't have to clone to get mutable objects JS::RootedValue quickSaveMetadataClone(rq.cx); Index: ps/trunk/source/simulation2/tests/test_CmpTemplateManager.h =================================================================== --- ps/trunk/source/simulation2/tests/test_CmpTemplateManager.h +++ ps/trunk/source/simulation2/tests/test_CmpTemplateManager.h @@ -99,7 +99,7 @@ TS_ASSERT(tempMan != NULL); tempMan->DisableValidation(); - ScriptInterface::Request rq(man.GetScriptInterface()); + ScriptRequest rq(man.GetScriptInterface()); // This is testing some bugs in the template JS object caching Index: ps/trunk/source/simulation2/tests/test_ComponentManager.h =================================================================== --- ps/trunk/source/simulation2/tests/test_ComponentManager.h +++ ps/trunk/source/simulation2/tests/test_ComponentManager.h @@ -367,14 +367,12 @@ ScriptTestSetup(man.m_ScriptInterface); man.LoadComponentTypes(); - { - TestLogger log; - TS_ASSERT(man.LoadScript(L"simulation/components/error.js")); - // In SpiderMonkey 1.6, JS_ReportError calls the error reporter even if it's inside - // a try{} in the script; in recent versions (not sure when it changed) it doesn't - // so the error here won't get reported. - TS_ASSERT_STR_NOT_CONTAINS(log.GetOutput(), "ERROR: JavaScript error: simulation/components/error.js line 4\nInvalid interface id"); - } + TestLogger log; + TS_ASSERT(man.LoadScript(L"simulation/components/error.js")); + // The following exception is caught and dropped by the JS script, and should not appear in the logs. + TS_ASSERT_STR_NOT_CONTAINS(log.GetOutput(), "ERROR: JavaScript error: simulation/components/error.js line 4\nInvalid interface id"); + // The following exception is not caught by the JS script. + TS_ASSERT_STR_CONTAINS(log.GetOutput(), "ERROR: No script wrapper found for interface id 12345"); } void test_script_entityID() Index: ps/trunk/source/simulation2/tests/test_Serializer.h =================================================================== --- ps/trunk/source/simulation2/tests/test_Serializer.h +++ ps/trunk/source/simulation2/tests/test_Serializer.h @@ -292,7 +292,7 @@ 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_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); JS::RootedValue obj(rq.cx); TSM_ASSERT(msg, script.Eval(input, &obj)); @@ -754,7 +754,7 @@ void test_script_exceptions() { ScriptInterface script("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); JS::RootedValue obj(rq.cx); @@ -765,6 +765,7 @@ TS_ASSERT(script.Eval("([1, 2, function () { }])", &obj)); TS_ASSERT_THROWS(serialize.ScriptVal("script", &obj), const PSERROR_Serialize_InvalidScriptValue&); + TS_ASSERT_STR_CONTAINS(logger.GetOutput(), "ERROR: Cannot serialise JS objects of type 'function': (unnamed)"); } void test_script_splice() @@ -788,7 +789,7 @@ const char* input = "var x = {}; for (var i=0;i<256;++i) x[i]=Math.pow(i, 2); x"; ScriptInterface script("Test", "Test", g_ScriptContext); - ScriptInterface::Request rq(script); + ScriptRequest rq(script); JS::RootedValue obj(rq.cx); TS_ASSERT(script.Eval(input, &obj)); Index: ps/trunk/source/test_setup.cpp =================================================================== --- ps/trunk/source/test_setup.cpp +++ ps/trunk/source/test_setup.cpp @@ -153,6 +153,5 @@ std::ifstream ifs(OsString(path).c_str()); ENSURE(ifs.good()); std::string content((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); - bool ok = scriptinterface.LoadScript(L"test_setup.js", content); - ENSURE(ok); + ENSURE(scriptinterface.LoadScript(L"test_setup.js", content)); } Index: ps/trunk/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp =================================================================== --- ps/trunk/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp +++ ps/trunk/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp @@ -99,7 +99,7 @@ // Random map const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); JS::RootedValue settings(rq.cx); scriptInterface.ParseJSON(*msg->settings, &settings); @@ -127,7 +127,7 @@ InitGame(); const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); // Set up 8-element array of empty objects to satisfy init JS::RootedValue playerData(rq.cx); @@ -166,7 +166,7 @@ InitGame(); const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); - ScriptInterface::Request rq(scriptInterface); + ScriptRequest rq(scriptInterface); // Scenario CStrW map = *msg->filename;