diff --git a/source/graphics/MapWriter.cpp b/source/graphics/MapWriter.cpp index 2e2c4738f5..bc281976c5 100644 --- a/source/graphics/MapWriter.cpp +++ b/source/graphics/MapWriter.cpp @@ -497,27 +497,3 @@ void CMapWriter::WriteTrigger(XMLWriter_File& xml_file_, const MapTrigger& trigg } //Effects' scope } */ - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// RewriteAllMaps -void CMapWriter::RewriteAllMaps(CTerrain* pTerrain, - WaterManager* pWaterMan, SkyManager* pSkyMan, - CLightEnv* pLightEnv, CGameView* pGameView, CCinemaManager* pCinema, - CTriggerManager* pTrigMan, CSimulation2* pSimulation2) -{ - VfsPaths pathnames; - (void)fs_util::GetPathnames(g_VFS, L"maps/scenarios", L"*.pmp", pathnames); - for (size_t i = 0; i < pathnames.size(); i++) - { - CMapReader* reader = new CMapReader; - LDR_BeginRegistering(); - reader->LoadMap(pathnames[i], pTerrain, pWaterMan, pSkyMan, pLightEnv, pGameView, pCinema, pTrigMan, pSimulation2, -1); - LDR_EndRegistering(); - LDR_NonprogressiveLoad(); - - CStrW newPathname(pathnames[i].string()); - newPathname.Replace(L"scenarios/", L"scenarios/new/"); - CMapWriter writer; - writer.SaveMap(newPathname, pTerrain, pWaterMan, pSkyMan, pLightEnv, pGameView->GetCamera(), pCinema, pSimulation2); - } -} diff --git a/source/graphics/MapWriter.h b/source/graphics/MapWriter.h index 20e4862110..2317cfd12e 100644 --- a/source/graphics/MapWriter.h +++ b/source/graphics/MapWriter.h @@ -48,13 +48,6 @@ public: CLightEnv* pLightEnv, CCamera* pCamera, CCinemaManager* pCinema, CSimulation2* pSimulation2); - // RewriteAllMaps: for use during development: load/save all maps, to - // update them to the newest format. - static void RewriteAllMaps(CTerrain* pTerrain, WaterManager* pWaterMan, - SkyManager* pSkyMan, CLightEnv* pLightEnv, CGameView* pGameView, - CCinemaManager* pCinema, CTriggerManager* pTrigMan, - CSimulation2* pSimulation2); - private: // PackMap: pack the current world into a raw data stream void PackMap(CFilePacker& packer, CTerrain* pTerrain); diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 3c43d73aa4..17d90568d4 100644 --- a/source/gui/scripting/ScriptFunctions.cpp +++ b/source/gui/scripting/ScriptFunctions.cpp @@ -23,14 +23,17 @@ #include "graphics/GameView.h" #include "graphics/MapReader.h" #include "gui/GUIManager.h" +#include "lib/timer.h" #include "lib/sysdep/sysdep.h" #include "maths/FixedVector3D.h" #include "network/NetClient.h" #include "network/NetServer.h" #include "network/NetTurnManager.h" #include "ps/CLogger.h" +#include "ps/CConsole.h" #include "ps/Game.h" #include "ps/Overlay.h" +#include "ps/Pyrogenesis.h" #include "ps/GameSetup/Atlas.h" #include "ps/GameSetup/Config.h" #include "simulation2/Simulation2.h" @@ -322,6 +325,47 @@ void CameraFollow(void* UNUSED(cbdata), entity_id_t entityid) g_Game->GetView()->CameraFollow(entityid); } + +void SetSimRate(void* UNUSED(cbdata), float rate) +{ + g_Game->SetSimRate(rate); +} + +void SetTurnLength(void* UNUSED(cbdata), int length) +{ + if (g_NetServer) + g_NetServer->SetTurnLength(length); + else + LOGERROR(L"Only network host can change turn length"); +} + +// Focus the game camera on a given position. +void SetCameraTarget(void* UNUSED(cbdata), float x, float y, float z) +{ + g_Game->GetView()->ResetCameraTarget(CVector3D(x, y, z)); +} + +// Deliberately cause the game to crash. +// Currently implemented via access violation (read of address 0). +// Useful for testing the crashlog/stack trace code. +int Crash(void* UNUSED(cbdata)) +{ + MICROLOG(L"Crashing at user's request."); + return *(int*)0; +} + +// Force a JS garbage collection cycle to take place immediately. +// Writes an indication of how long this took to the console. +void ForceGC(void* cbdata) +{ + CGUIManager* guiManager = static_cast (cbdata); + + double time = timer_Time(); + JS_GC(guiManager->GetScriptInterface().GetContext()); + time = timer_Time() - time; + g_Console->InsertMessage(L"Garbage collection completed in: %f", time); +} + } // namespace void GuiScriptingInit(ScriptInterface& scriptInterface) @@ -362,4 +406,11 @@ void GuiScriptingInit(ScriptInterface& scriptInterface) scriptInterface.RegisterFunction("LoadMapData"); scriptInterface.RegisterFunction("SetRevealMap"); scriptInterface.RegisterFunction("CameraFollow"); + + // Development/debugging functions + scriptInterface.RegisterFunction("SetSimRate"); + scriptInterface.RegisterFunction("SetTurnLength"); + scriptInterface.RegisterFunction("SetCameraTarget"); + scriptInterface.RegisterFunction("Crash"); + scriptInterface.RegisterFunction("ForceGC"); } diff --git a/source/ps/Profile.h b/source/ps/Profile.h index c747754507..44bc687244 100644 --- a/source/ps/Profile.h +++ b/source/ps/Profile.h @@ -154,7 +154,6 @@ public: class CProfileSample { - static std::map evMap; public: CProfileSample( const char* name ) { @@ -168,6 +167,21 @@ public: } }; +class CProfileSampleScript +{ +public: + CProfileSampleScript( const char* name ) + { + if (CProfileManager::IsInitialised()) + g_Profiler.StartScript( name ); + } + ~CProfileSampleScript() + { + if (CProfileManager::IsInitialised()) + g_Profiler.Stop(); + } +}; + // Put a PROFILE( xyz ) block at the start of all code to be profiled. // Profile blocks last until the end of the containing scope. #define PROFILE( name ) CProfileSample __profile( name ) diff --git a/source/ps/World.cpp b/source/ps/World.cpp index 05ad682ab3..e3115ea89a 100644 --- a/source/ps/World.cpp +++ b/source/ps/World.cpp @@ -58,7 +58,6 @@ CWorld::CWorld(CGame *pGame): m_pGame(pGame), m_Terrain(new CTerrain()), m_UnitManager(new CUnitManager()), - m_LOSManager(NULL), m_TerritoryManager(NULL) { } @@ -105,18 +104,3 @@ CWorld::~CWorld() delete m_Terrain; delete m_UnitManager; } - - -/** - * Redraw the world. - * Provided for JS _rewritemaps function. - * - **/ -void CWorld::RewriteMap() -{ - CMapWriter::RewriteAllMaps(m_Terrain, - g_Renderer.GetWaterManager(), g_Renderer.GetSkyManager(), - &g_LightEnv, m_pGame->GetView(), - m_pGame->GetView()->GetCinema(), NULL, - m_pGame->GetSimulation2()); -} diff --git a/source/ps/World.h b/source/ps/World.h index 0b91ec95e5..19a2b5ee33 100644 --- a/source/ps/World.h +++ b/source/ps/World.h @@ -35,7 +35,6 @@ ERROR_TYPE(Game_World, MapLoadFailed); class CGame; class CUnitManager; -class CLOSManager; class CTerritoryManager; class CTerrain; class CStrW; @@ -61,10 +60,6 @@ class CWorld * pointer to the CUnitManager that holds all the units in the world. **/ CUnitManager *m_UnitManager; - /** - * pointer to the CLOSManager that holds the visibility matrix for the world. - **/ - CLOSManager *m_LOSManager; /** * pointer to the CTerritoryManager that holds territory matrix for the world. **/ @@ -79,9 +74,6 @@ public: */ void RegisterInit(const CStrW& mapFile, int playerID); - // provided for JS _rewritemaps function - void RewriteMap(); - /** * Get the pointer to the terrain object. * @@ -97,13 +89,6 @@ public: **/ inline CUnitManager &GetUnitManager() { return *m_UnitManager; } - /** - * Get the pointer to the LOS manager object. - * - * @return CLOSManager * the value of m_LOSManager. - **/ - inline CLOSManager *GetLOSManager() - { return m_LOSManager; } /** * Get the pointer to the territory manager object. * diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 311f0ed851..d652481995 100644 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -54,9 +54,7 @@ #include "ps/scripting/JSInterface_Console.h" #include "ps/scripting/JSInterface_VFS.h" #include "renderer/Renderer.h" -#include "renderer/SkyManager.h" #include "scriptinterface/ScriptInterface.h" -#include "simulation/LOSManager.h" #include "simulation2/Simulation2.h" #define LOG_CATEGORY L"script" @@ -70,67 +68,10 @@ // JSBool accessor(JSContext* cx, JSObject* globalObject, jsval id, jsval* vp); -//----------------------------------------------------------------------------- -// Output -//----------------------------------------------------------------------------- - -// Write values to the log file. -// params: any number of any type. -// returns: -// notes: -// - Each argument is converted to a string and then written to the log. -// - Output is in NORMAL style (see LOG). -JSBool WriteLog(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval) -{ - JSU_REQUIRE_PARAMS(1); - - CStrW logMessage; - - for (int i = 0; i < (int)argc; i++) - { - try - { - CStrW arg = g_ScriptingHost.ValueToUCString( argv[i] ); - logMessage += arg; - } - catch( PSERROR_Scripting_ConversionFailed ) - { - // Do nothing. - } - } - - LOG(CLogger::Normal, LOG_CATEGORY, L"%ls", logMessage.c_str()); - - *rval = JSVAL_TRUE; - return JS_TRUE; -} - - //----------------------------------------------------------------------------- // Timer //----------------------------------------------------------------------------- -// Set the simulation rate scalar-time becomes time * SimRate. -// Params: rate [float] : sets SimRate -JSBool SetSimRate(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval) -{ - JSU_REQUIRE_PARAMS(1); - - g_Game->SetSimRate( ToPrimitive(argv[0]) ); - return JS_TRUE; -} - -JSBool SetTurnLength(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval) -{ - JSU_REQUIRE_PARAMS(1); - - if (g_NetServer) - g_NetServer->SetTurnLength(ToPrimitive(argv[0])); - else - LOGERROR(L"Only network host can change turn length"); - - return JS_TRUE; -} // Script profiling functions: Begin timing a piece of code with StartJsTimer(num) // and stop timing with StopJsTimer(num). The results will be printed to stdout @@ -214,87 +155,6 @@ JSBool EndGame(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval) return JS_TRUE; } -//----------------------------------------------------------------------------- -// Internationalization -//----------------------------------------------------------------------------- - -// these remain here instead of in the i18n tree because they are -// really related to the engine's use of them, as opposed to i18n itself. -// contrariwise, translate() cannot be moved here because that would -// make i18n dependent on this code and therefore harder to reuse. - -// Replaces the current language (locale) with a new one. -// params: language id [string] as in I18n::LoadLanguage -// returns: -JSBool LoadLanguage(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval) -{ - JSU_REQUIRE_PARAMS(1); - - CStr lang = g_ScriptingHost.ValueToString(argv[0]); - I18n::LoadLanguage(lang); - - return JS_TRUE; -} - - -// Return identifier of the current language (locale) in use. -// params: -// returns: language id [string] as in I18n::LoadLanguage -JSBool GetLanguageID(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval) -{ - JSU_REQUIRE_NO_PARAMS(); - *rval = JSVAL_NULL; - - JSString* s = JS_NewStringCopyZ(cx, I18n::CurrentLanguageName()); - if (!s) - { - JS_ReportError(cx, "Error creating string"); - return JS_FALSE; - } - *rval = STRING_TO_JSVAL(s); - return JS_TRUE; -} - - -//----------------------------------------------------------------------------- -// Debug -//----------------------------------------------------------------------------- - - -// Deliberately cause the game to crash. -// params: -// returns: -// notes: -// - currently implemented via access violation (read of address 0) -// - useful for testing the crashlog/stack trace code. -JSBool ProvokeCrash(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval) -{ - JSU_REQUIRE_NO_PARAMS(); - - MICROLOG(L"Crashing at user's request."); - return *(JSBool*)0; -} - - -// Force a JS garbage collection cycle to take place immediately. -// params: -// returns: true [bool] -// notes: -// - writes an indication of how long this took to the console. -JSBool ForceGarbageCollection(JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval) -{ - JSU_REQUIRE_NO_PARAMS(); - - double time = timer_Time(); - JS_GC(cx); - time = timer_Time() - time; - g_Console->InsertMessage(L"Garbage collection completed in: %f", time); - *rval = JSVAL_TRUE; - return JS_TRUE ; -} - - - //----------------------------------------------------------------------------- // Misc. Engine Interface //----------------------------------------------------------------------------- @@ -360,26 +220,6 @@ JSBool SetCursor( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval return JS_TRUE; } -JSBool GetCursorName( JSContext* UNUSED(cx), JSObject*, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval ) -{ - *rval = ToJSVal(g_CursorName); - return JS_TRUE; -} - -// Trigger a rewrite of all maps. -// params: -// returns: -// notes: -// - Usefulness is unclear. If you need it, consider renaming this and updating the docs. -JSBool _RewriteMaps( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval ) -{ - JSU_REQUIRE_NO_PARAMS(); - - g_Game->GetWorld()->RewriteMap(); - return JS_TRUE; -} - - // Change the LOD bias. // params: LOD bias [float] // returns: @@ -395,26 +235,6 @@ JSBool _LodBias( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval } -// Focus the game camera on a given position. -// params: target position vector [CVector3D] -// returns: success [bool] -JSBool SetCameraTarget( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval ) -{ - JSU_REQUIRE_PARAMS(1); - *rval = JSVAL_NULL; - - CVector3D* target = ToNative( argv[0] ); - if(!target) - { - JS_ReportError( cx, "Invalid camera target" ); - return( JS_TRUE ); - } - g_Game->GetView()->ResetCameraTarget( *target ); - - *rval = JSVAL_TRUE; - return( JS_TRUE ); -} - JSBool GetGUIObjectByName(JSContext* cx, JSObject* UNUSED(obj), uintN UNUSED(argc), jsval* argv, jsval* rval) { try @@ -509,15 +329,6 @@ JSBool DumpHeaps(JSContext* UNUSED(cx), JSObject* UNUSED(globalObject), uintN UN return JS_TRUE; } -// Toggles drawing the sky -JSBool ToggleSky( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval ) -{ - JSU_REQUIRE_NO_PARAMS(); - g_Renderer.GetSkyManager()->m_RenderSky = !g_Renderer.GetSkyManager()->m_RenderSky; - *rval = JSVAL_VOID; - return( JS_TRUE ); -} - //----------------------------------------------------------------------------- // Is the game paused? @@ -558,47 +369,6 @@ JSBool SetPaused( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsv return JS_TRUE; } -// Reveal map -JSBool RevealMap( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval ) -{ - JSU_REQUIRE_MAX_PARAMS(1); - - int newValue; - if(argc == 0) - newValue = LOS_SETTING_ALL_VISIBLE; - else if(!ToPrimitive( g_ScriptingHost.GetContext(), argv[0], newValue ) || newValue > 2) - { - JS_ReportError( cx, "Invalid argument (should be 0, 1 or 2)" ); - *rval = JSVAL_VOID; - return( JS_FALSE ); - } - - g_Game->GetWorld()->GetLOSManager()->m_LOSSetting = (ELOSSetting)newValue; - *rval = JSVAL_VOID; - return( JS_TRUE ); -} - -/** - * isGameRunning - * @return bool - */ -JSBool isGameRunning( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval ) -{ - JSU_REQUIRE_NO_PARAMS(); - - if (g_Game && g_Game->IsGameStarted()) - { - *rval = JSVAL_TRUE; - } - else - { - *rval = JSVAL_FALSE; - } - - return JS_TRUE; -} - - //----------------------------------------------------------------------------- // function table @@ -616,19 +386,6 @@ JSBool isGameRunning( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, JSFunctionSpec ScriptFunctionTable[] = { - // Console - JS_FUNC("writeConsole", JSI_Console::writeConsole, 1) // external - - // Camera - JS_FUNC("setCameraTarget", SetCameraTarget, 1) - - // Sky - JS_FUNC("toggleSky", ToggleSky, 0) - - // Timer - JS_FUNC("setSimRate", SetSimRate, 1) - JS_FUNC("setTurnLength", SetTurnLength, 1) - // Profiling JS_FUNC("startXTimer", StartJsTimer, 1) JS_FUNC("stopXTimer", StopJsTimer, 1) @@ -644,29 +401,14 @@ JSFunctionSpec ScriptFunctionTable[] = JS_FUNC("readFileLines", JSI_VFS::ReadFileLines, 1) JS_FUNC("archiveBuilderCancel", JSI_VFS::ArchiveBuilderCancel, 1) - // Internationalization - JS_FUNC("loadLanguage", LoadLanguage, 1) - JS_FUNC("getLanguageID", GetLanguageID, 0) - // note: i18n/ScriptInterface.cpp registers translate() itself. - // rationale: see implementation section above. - - // Debug - JS_FUNC("crash", ProvokeCrash, 0) - JS_FUNC("forceGC", ForceGarbageCollection, 0) - JS_FUNC("revealMap", RevealMap, 1) - // Misc. Engine Interface - JS_FUNC("writeLog", WriteLog, 1) JS_FUNC("exit", ExitProgram, 0) JS_FUNC("isPaused", IsPaused, 0) JS_FUNC("setPaused", SetPaused, 1) JS_FUNC("vmem", WriteVideoMemToConsole, 0) - JS_FUNC("_rewriteMaps", _RewriteMaps, 0) JS_FUNC("_lodBias", _LodBias, 0) JS_FUNC("setCursor", SetCursor, 1) - JS_FUNC("getCursorName", GetCursorName, 0) JS_FUNC("getFPS", GetFps, 0) - JS_FUNC("isGameRunning", isGameRunning, 0) JS_FUNC("getGUIObjectByName", GetGUIObjectByName, 1) // Miscellany diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp index 0fc3e85de0..4a835415cf 100644 --- a/source/scripting/ScriptingHost.cpp +++ b/source/scripting/ScriptingHost.cpp @@ -100,18 +100,6 @@ void ScriptingHost::RunScript(const VfsPath& pathname, JSObject* globalObject) throw PSERROR_Scripting_LoadFile_EvalErrors(); } -jsval ScriptingHost::CallFunction(const std::string & functionName, jsval * params, int numParams) -{ - jsval result; - - JSBool ok = JS_CallFunctionName(m_Context, m_GlobalObject, functionName.c_str(), numParams, params, &result); - - if (ok == JS_FALSE) - throw PSERROR_Scripting_CallFunctionFailed(); - - return result; -} - jsval ScriptingHost::ExecuteScript(const CStrW& script, const CStrW& calledFrom, JSObject* contextObject ) { jsval rval; @@ -124,18 +112,6 @@ jsval ScriptingHost::ExecuteScript(const CStrW& script, const CStrW& calledFrom, return rval; } -void ScriptingHost::DefineConstant(const std::string & name, int value) -{ - // First remove this constant if it already exists - JS_DeleteProperty(m_Context, m_GlobalObject, name.c_str()); - - JSBool ok = JS_DefineProperty( m_Context, m_GlobalObject, name.c_str(), INT_TO_JSVAL(value), - NULL, NULL, JSPROP_READONLY); - - if (ok == JS_FALSE) - throw PSERROR_Scripting_DefineConstantFailed(); -} - void ScriptingHost::DefineCustomObjectType(JSClass *clasp, JSNative constructor, uintN minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) { std::string typeName = clasp->name; @@ -246,8 +222,3 @@ CStrW ScriptingHost::ValueToUCString( const jsval value ) size_t length=JS_GetStringLength(string); return std::wstring(strptr, strptr+length); } - -jsval ScriptingHost::UCStringToValue( const CStrW& str ) -{ - return STRING_TO_JSVAL(JS_NewUCStringCopyZ(m_Context, str.utf16().c_str())); -} diff --git a/source/scripting/ScriptingHost.h b/source/scripting/ScriptingHost.h index 79a44596cc..1327c8a8dc 100644 --- a/source/scripting/ScriptingHost.h +++ b/source/scripting/ScriptingHost.h @@ -97,12 +97,8 @@ public: void RunScript(const VfsPath& filename, JSObject* globalObject = 0); - jsval CallFunction(const std::string & functionName, jsval * params, int numParams); - jsval ExecuteScript(const CStrW& script, const CStrW& calledFrom = L"Console", JSObject* contextObject = NULL ); - void DefineConstant(const std::string & name, int value); - void DefineCustomObjectType(JSClass *clasp, JSNative constructor, uintN nargs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs); JSObject * CreateCustomObject(const std::string & typeName); @@ -117,7 +113,6 @@ public: std::string ValueToString(const jsval value); CStrW ValueToUCString(const jsval value); - jsval UCStringToValue(const CStrW& str); }; #define g_ScriptingHost ScriptingHost::GetSingleton() diff --git a/source/scriptinterface/NativeWrapperDecls.h b/source/scriptinterface/NativeWrapperDecls.h index 864b1dc468..29e64bccaa 100644 --- a/source/scriptinterface/NativeWrapperDecls.h +++ b/source/scriptinterface/NativeWrapperDecls.h @@ -26,7 +26,7 @@ #define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i // Some other things #define TYPED_ARGS(z, i, data) , T##i a##i -#define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal(cx, argv[i], a##i)) return JS_FALSE; +#define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) return JS_FALSE; // List-generating macros, named roughly after their first list item #define TYPENAME_T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, typename T) // "typename T0, typename T1, " @@ -47,18 +47,18 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS -// JSNative-compatible function that wraps the function identified in the template argument list +// JSFastNative-compatible function that wraps the function identified in the template argument list // (Definition comes later, since it depends on some things we haven't defined yet) #define OVERLOADS(z, i, data) \ template \ - static JSBool call(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); + static JSBool call(JSContext* cx, uintN argc, jsval* vp); BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS // Similar, for class methods #define OVERLOADS(z, i, data) \ template \ - static JSBool callMethod(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); + static JSBool callMethod(JSContext* cx, uintN argc, jsval* vp); BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS diff --git a/source/scriptinterface/NativeWrapperDefns.h b/source/scriptinterface/NativeWrapperDefns.h index 06892b7ad4..0517c0c080 100644 --- a/source/scriptinterface/NativeWrapperDefns.h +++ b/source/scriptinterface/NativeWrapperDefns.h @@ -71,15 +71,27 @@ struct ScriptInterface_NativeMethodWrapper { #undef OVERLOADS }; +// Fast natives don't trigger the hook we use for profiling, so explicitly +// notify the profiler when these functions are being called +#if ENABLE_SCRIPT_PROFILING +#define SCRIPT_PROFILE \ + debug_assert(JSVAL_IS_OBJECT(JS_CALLEE(cx, vp)) && JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)))); \ + const char* name = JS_GetFunctionName(JS_ValueToFunction(cx, JS_CALLEE(cx, vp))); /* native function so ValueToFunction is safe; this makes unsafe lifetime assumptions */ \ + CProfileSampleScript profile(name); +#else +#define SCRIPT_PROFILE +#endif - -// JSNative-compatible function that wraps the function identified in the template argument list +// JSFastNative-compatible function that wraps the function identified in the template argument list #define OVERLOADS(z, i, data) \ template \ - JSBool ScriptInterface::call(JSContext* cx, JSObject* /*obj*/, uintN /*argc*/, jsval* argv, jsval* rval) { \ - (void)argv; /* avoid 'unused parameter' warnings */ \ + JSBool ScriptInterface::call(JSContext* cx, uintN argc, jsval* vp) { \ + UNUSED2(argc); \ + SCRIPT_PROFILE \ BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ - ScriptInterface_NativeWrapper::call(cx, *rval, fptr A0_TAIL(z,i)); \ + jsval rval = JSVAL_VOID; \ + ScriptInterface_NativeWrapper::call(cx, rval, fptr A0_TAIL(z,i)); \ + JS_SET_RVAL(cx, vp, rval); \ return (ScriptInterface::IsExceptionPending(cx) ? JS_FALSE : JS_TRUE); \ } BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) @@ -88,19 +100,23 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) // Same idea but for methods #define OVERLOADS(z, i, data) \ template \ - JSBool ScriptInterface::callMethod(JSContext* cx, JSObject* obj, uintN /*argc*/, jsval* argv, jsval* rval) { \ - (void)argv; /* avoid 'unused parameter' warnings */ \ - if (ScriptInterface::GetClass(cx, obj) != CLS) return JS_FALSE; \ - TC* c = static_cast(ScriptInterface::GetPrivate(cx, obj)); \ + JSBool ScriptInterface::callMethod(JSContext* cx, uintN argc, jsval* vp) { \ + UNUSED2(argc); \ + SCRIPT_PROFILE \ + if (ScriptInterface::GetClass(cx, JS_THIS_OBJECT(cx, vp)) != CLS) return JS_FALSE; \ + TC* c = static_cast(ScriptInterface::GetPrivate(cx, JS_THIS_OBJECT(cx, vp))); \ if (! c) return JS_FALSE; \ BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ - ScriptInterface_NativeMethodWrapper::call(cx, *rval, c, fptr A0_TAIL(z,i)); \ + jsval rval = JSVAL_VOID; \ + ScriptInterface_NativeMethodWrapper::call(cx, rval, c, fptr A0_TAIL(z,i)); \ + JS_SET_RVAL(cx, vp, rval); \ return (ScriptInterface::IsExceptionPending(cx) ? JS_FALSE : JS_TRUE); \ } BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS // Clean up our mess +#undef SCRIPT_PROFILE #undef NUMBERED_LIST_HEAD #undef NUMBERED_LIST_TAIL #undef NUMBERED_LIST_BALANCED diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index 69dd155bd6..5f459a54cb 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -39,12 +39,6 @@ const int RUNTIME_SIZE = 16 * 1024 * 1024; // TODO: how much memory is needed? const int STACK_CHUNK_SIZE = 8192; -#ifdef NDEBUG -#define ENABLE_SCRIPT_PROFILING 0 -#else -#define ENABLE_SCRIPT_PROFILING 1 -#endif - #if ENABLE_SCRIPT_PROFILING #include "js/jsdbgapi.h" #endif @@ -55,7 +49,7 @@ struct ScriptInterface_impl { ScriptInterface_impl(const char* nativeScopeName, JSContext* cx); ~ScriptInterface_impl(); - void Register(const char* name, JSNative fptr, uintN nargs); + void Register(const char* name, JSFastNative fptr, uintN nargs); JSRuntime* m_rt; // NULL if m_cx is shared; non-NULL if we own m_cx JSContext* m_cx; @@ -314,9 +308,9 @@ ScriptInterface_impl::~ScriptInterface_impl() } } -void ScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs) +void ScriptInterface_impl::Register(const char* name, JSFastNative fptr, uintN nargs) { - JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); + JS_DefineFunction(m_cx, m_nativeScope, name, reinterpret_cast(fptr), nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE); } ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName) : @@ -367,7 +361,7 @@ void ScriptInterface::ReplaceNondeterministicFunctions(boost::rand48& rng) JS_SetReservedSlot(m->m_cx, JS_GetFunctionObject(random), 0, PRIVATE_TO_JSVAL(&rng)); } -void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) +void ScriptInterface::Register(const char* name, JSFastNative fptr, size_t nargs) { m->Register(name, fptr, (uintN)nargs); } diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index 5fa6710dda..8e2713d24f 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -29,6 +29,9 @@ #include "ScriptTypes.h" #include "ScriptVal.h" +#include "js/jsapi.h" + +#include "ps/Profile.h" #include "ps/utf16string.h" class AutoGCRooter; @@ -40,6 +43,12 @@ namespace boost { class rand48; } // but as large as necessary for all wrapped functions) #define SCRIPT_INTERFACE_MAX_ARGS 6 +#ifdef NDEBUG +#define ENABLE_SCRIPT_PROFILING 0 +#else +#define ENABLE_SCRIPT_PROFILING 1 +#endif + struct ScriptInterface_impl; class ScriptInterface { @@ -241,7 +250,7 @@ private: static JSClass* GetClass(JSContext* cx, JSObject* obj); static void* GetPrivate(JSContext* cx, JSObject* obj); - void Register(const char* name, JSNative fptr, size_t nargs); + void Register(const char* name, JSFastNative fptr, size_t nargs); std::auto_ptr m; // The nasty macro/template bits are split into a separate file so you don't have to look at them @@ -253,10 +262,10 @@ public: // void RegisterFunction(const char* functionName); // // template - // static JSNative call; + // static JSFastNative call; // // template - // static JSNative callMethod; + // static JSFastNative callMethod; // // template // static size_t nargs(); diff --git a/source/simulation2/system/InterfaceScripted.h b/source/simulation2/system/InterfaceScripted.h index d90b0061cd..9554b9731a 100644 --- a/source/simulation2/system/InterfaceScripted.h +++ b/source/simulation2/system/InterfaceScripted.h @@ -45,38 +45,38 @@ #define DEFINE_INTERFACE_METHOD_0(scriptname, rettype, classname, methodname) \ { scriptname, \ - ScriptInterface::callMethod, \ + reinterpret_cast(static_cast(ScriptInterface::callMethod)), \ 0, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT, 0 }, + JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 }, #define DEFINE_INTERFACE_METHOD_1(scriptname, rettype, classname, methodname, arg1) \ { scriptname, \ - ScriptInterface::callMethod, \ + reinterpret_cast(static_cast(ScriptInterface::callMethod)), \ 1, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT, 0 }, + JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 }, #define DEFINE_INTERFACE_METHOD_2(scriptname, rettype, classname, methodname, arg1, arg2) \ { scriptname, \ - ScriptInterface::callMethod, \ + reinterpret_cast(static_cast(ScriptInterface::callMethod)), \ 2, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT, 0 }, + JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 }, #define DEFINE_INTERFACE_METHOD_3(scriptname, rettype, classname, methodname, arg1, arg2, arg3) \ { scriptname, \ - ScriptInterface::callMethod, \ + reinterpret_cast(static_cast(ScriptInterface::callMethod)), \ 3, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT, 0 }, + JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 }, #define DEFINE_INTERFACE_METHOD_4(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4) \ { scriptname, \ - ScriptInterface::callMethod, \ + reinterpret_cast(static_cast(ScriptInterface::callMethod)), \ 4, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT, 0 }, + JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 }, #define DEFINE_INTERFACE_METHOD_5(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5) \ { scriptname, \ - ScriptInterface::callMethod, \ + reinterpret_cast(static_cast(ScriptInterface::callMethod)), \ 5, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT, 0 }, + JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 }, #endif // INCLUDED_INTERFACE_SCRIPTED