Encapsulate runtime creation.
- Makes it easier to change down the line (and change is coming) - Allows making g_ScriptRuntime thread-local easily. - Remove ParentRuntime, which is not used at the moment. Part of the SM52 migration, stage: SM45 compatible. Patch by: Itms Tested By: Freagarach Refs #4893 Differential Revision: https://code.wildfiregames.com/D3087 This was SVN commit r24171.
This commit is contained in:
parent
90367cdc53
commit
66cc595c53
@ -39,8 +39,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// TODO: what's a good default? perhaps based on map size
|
||||
#define RMS_RUNTIME_SIZE 96 * 1024 * 1024
|
||||
// TODO: Maybe this should be optimized depending on the map size.
|
||||
constexpr int RMS_RUNTIME_SIZE = 96 * 1024 * 1024;
|
||||
|
||||
extern bool IsQuitRequested();
|
||||
|
||||
@ -89,7 +89,7 @@ void* CMapGeneratorWorker::RunThread(CMapGeneratorWorker* self)
|
||||
debug_SetThreadName("MapGenerator");
|
||||
g_Profiler2.RegisterCurrentThread("MapGenerator");
|
||||
|
||||
shared_ptr<ScriptRuntime> mapgenRuntime = ScriptInterface::CreateRuntime(g_ScriptRuntime, RMS_RUNTIME_SIZE);
|
||||
shared_ptr<ScriptRuntime> mapgenRuntime = ScriptRuntime::CreateRuntime(RMS_RUNTIME_SIZE);
|
||||
|
||||
// Enable the script to be aborted
|
||||
JS_SetInterruptCallback(mapgenRuntime->m_rt, MapGeneratorInterruptCallback);
|
||||
|
@ -388,7 +388,8 @@ void CNetServerWorker::Run()
|
||||
|
||||
// To avoid the need for JS_SetContextThread, we create and use and destroy
|
||||
// the script interface entirely within this network thread
|
||||
m_ScriptInterface = new ScriptInterface("Engine", "Net server", ScriptInterface::CreateRuntime(g_ScriptRuntime));
|
||||
shared_ptr<ScriptRuntime> netServerRuntime = ScriptRuntime::CreateRuntime();
|
||||
m_ScriptInterface = new ScriptInterface("Engine", "Net server", netServerRuntime);
|
||||
m_GameAttributes.init(m_ScriptInterface->GetJSRuntime(), JS::UndefinedValue());
|
||||
|
||||
while (true)
|
||||
|
@ -109,7 +109,7 @@ bool g_DoRenderGui = true;
|
||||
bool g_DoRenderLogger = true;
|
||||
bool g_DoRenderCursor = true;
|
||||
|
||||
shared_ptr<ScriptRuntime> g_ScriptRuntime;
|
||||
thread_local shared_ptr<ScriptRuntime> g_ScriptRuntime;
|
||||
|
||||
static const int SANE_TEX_QUALITY_DEFAULT = 5; // keep in sync with code
|
||||
|
||||
@ -895,7 +895,7 @@ bool Init(const CmdLineArgs& args, int flags)
|
||||
// their own threads and also their own runtimes.
|
||||
const int runtimeSize = 384 * 1024 * 1024;
|
||||
const int heapGrowthBytesGCTrigger = 20 * 1024 * 1024;
|
||||
g_ScriptRuntime = ScriptInterface::CreateRuntime(shared_ptr<ScriptRuntime>(), runtimeSize, heapGrowthBytesGCTrigger);
|
||||
g_ScriptRuntime = ScriptRuntime::CreateRuntime(runtimeSize, heapGrowthBytesGCTrigger);
|
||||
|
||||
Mod::CacheEnabledModVersions(g_ScriptRuntime);
|
||||
|
||||
|
@ -208,7 +208,7 @@ void CReplayPlayer::Replay(const bool serializationtest, const int rejointesttur
|
||||
|
||||
const int runtimeSize = 384 * 1024 * 1024;
|
||||
const int heapGrowthBytesGCTrigger = 20 * 1024 * 1024;
|
||||
g_ScriptRuntime = ScriptInterface::CreateRuntime(shared_ptr<ScriptRuntime>(), runtimeSize, heapGrowthBytesGCTrigger);
|
||||
g_ScriptRuntime = ScriptRuntime::CreateRuntime(runtimeSize, heapGrowthBytesGCTrigger);
|
||||
|
||||
Mod::CacheEnabledModVersions(g_ScriptRuntime);
|
||||
|
||||
|
@ -183,8 +183,7 @@ bool ScriptInterface::CallFunction(JS::HandleValue val, const char* name, R& ret
|
||||
JS::AutoValueVector argv(cx);
|
||||
argv.resize(sizeof...(Ts));
|
||||
AssignOrToJSValHelper<0>(cx, argv, params...);
|
||||
bool ok = CallFunction_(val, name, argv, &jsRet);
|
||||
if (!ok)
|
||||
if (!CallFunction_(val, name, argv, &jsRet))
|
||||
return false;
|
||||
return FromJSVal(cx, jsRet, ret);
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ struct ScriptInterface_impl
|
||||
|
||||
JSContext* m_cx;
|
||||
JS::PersistentRootedObject m_glob; // global scope object
|
||||
JSCompartment* m_comp;
|
||||
JSCompartment* m_formerCompartment;
|
||||
boost::rand48* m_rng;
|
||||
JS::PersistentRootedObject m_nativeScope; // native function scope object
|
||||
};
|
||||
@ -333,8 +333,6 @@ bool ScriptInterface::MathRandom(double& nbr)
|
||||
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) :
|
||||
m_runtime(runtime), m_glob(runtime->m_rt), m_nativeScope(runtime->m_rt)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
m_cx = JS_NewContext(m_runtime->m_rt, STACK_CHUNK_SIZE);
|
||||
ENSURE(m_cx);
|
||||
|
||||
@ -362,9 +360,8 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const sh
|
||||
|
||||
JSAutoRequest rq(m_cx);
|
||||
JS::RootedObject globalRootedVal(m_cx, JS_NewGlobalObject(m_cx, &global_class, NULL, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt));
|
||||
m_comp = JS_EnterCompartment(m_cx, globalRootedVal);
|
||||
ok = JS_InitStandardClasses(m_cx, globalRootedVal);
|
||||
ENSURE(ok);
|
||||
m_formerCompartment = JS_EnterCompartment(m_cx, globalRootedVal);
|
||||
ENSURE(JS_InitStandardClasses(m_cx, globalRootedVal));
|
||||
m_glob = globalRootedVal.get();
|
||||
|
||||
JS_DefineProperty(m_cx, m_glob, "global", globalRootedVal, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
@ -390,7 +387,7 @@ ScriptInterface_impl::~ScriptInterface_impl()
|
||||
m_runtime->UnRegisterContext(m_cx);
|
||||
{
|
||||
JSAutoRequest rq(m_cx);
|
||||
JS_LeaveCompartment(m_cx, m_comp);
|
||||
JS_LeaveCompartment(m_cx, m_formerCompartment);
|
||||
}
|
||||
JS_DestroyContext(m_cx);
|
||||
}
|
||||
@ -563,9 +560,7 @@ bool ScriptInterface::CallFunction_(JS::HandleValue val, const char* name, JS::H
|
||||
if (!JS_HasProperty(m->m_cx, obj, name, &found) || !found)
|
||||
return false;
|
||||
|
||||
bool ok = JS_CallFunctionName(m->m_cx, obj, name, argv, ret);
|
||||
|
||||
return ok;
|
||||
return JS_CallFunctionName(m->m_cx, obj, name, argv, ret);
|
||||
}
|
||||
|
||||
bool ScriptInterface::CreateObject_(JSContext* cx, JS::MutableHandleObject object)
|
||||
@ -848,11 +843,6 @@ bool ScriptInterface::LoadScript(const VfsPath& filename, const std::string& cod
|
||||
return JS_CallFunction(m->m_cx, nullptr, func, JS::HandleValueArray::empty(), &rval);
|
||||
}
|
||||
|
||||
shared_ptr<ScriptRuntime> ScriptInterface::CreateRuntime(shared_ptr<ScriptRuntime> parentRuntime, int runtimeSize, int heapGrowthBytesGCTrigger)
|
||||
{
|
||||
return shared_ptr<ScriptRuntime>(new ScriptRuntime(parentRuntime, runtimeSize, heapGrowthBytesGCTrigger));
|
||||
}
|
||||
|
||||
bool ScriptInterface::LoadGlobalScript(const VfsPath& filename, const std::wstring& code) const
|
||||
{
|
||||
JSAutoRequest rq(m->m_cx);
|
||||
|
@ -48,15 +48,13 @@ ERROR_TYPE(Scripting_DefineType, CreationFailed);
|
||||
// but as large as necessary for all wrapped functions)
|
||||
#define SCRIPT_INTERFACE_MAX_ARGS 8
|
||||
|
||||
// TODO: what's a good default?
|
||||
#define DEFAULT_RUNTIME_SIZE 16 * 1024 * 1024
|
||||
#define DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER 2 * 1024 *1024
|
||||
|
||||
struct ScriptInterface_impl;
|
||||
|
||||
class ScriptRuntime;
|
||||
|
||||
extern shared_ptr<ScriptRuntime> g_ScriptRuntime;
|
||||
// Using a global object for the runtime is a workaround until Simulation, AI, etc,
|
||||
// use their own threads and also their own runtimes.
|
||||
extern thread_local shared_ptr<ScriptRuntime> g_ScriptRuntime;
|
||||
|
||||
|
||||
/**
|
||||
@ -73,17 +71,6 @@ class ScriptInterface
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns a runtime, which can used to initialise any number of
|
||||
* ScriptInterfaces contexts. Values created in one context may be used
|
||||
* in any other context from the same runtime (but not any other runtime).
|
||||
* Each runtime should only ever be used on a single thread.
|
||||
* @param runtimeSize Maximum size in bytes of the new runtime
|
||||
*/
|
||||
static shared_ptr<ScriptRuntime> CreateRuntime(shared_ptr<ScriptRuntime> parentRuntime = shared_ptr<ScriptRuntime>(), int runtimeSize = DEFAULT_RUNTIME_SIZE,
|
||||
int heapGrowthBytesGCTrigger = DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER);
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param nativeScopeName Name of global object that functions (via RegisterFunction) will
|
||||
@ -442,7 +429,7 @@ private:
|
||||
void Register(const char* name, JSNative fptr, size_t nargs) const;
|
||||
|
||||
// Take care to keep this declaration before heap rooted members. Destructors of heap rooted
|
||||
// members have to be called before the runtime destructor.
|
||||
// members have to be called before the custom destructor of ScriptInterface_impl.
|
||||
std::unique_ptr<ScriptInterface_impl> m;
|
||||
|
||||
boost::rand48* m_rng;
|
||||
|
@ -89,7 +89,12 @@ void GCSliceCallbackHook(JSRuntime* UNUSED(rt), JS::GCProgress progress, const J
|
||||
#endif
|
||||
}
|
||||
|
||||
ScriptRuntime::ScriptRuntime(shared_ptr<ScriptRuntime> parentRuntime, int runtimeSize, int heapGrowthBytesGCTrigger):
|
||||
shared_ptr<ScriptRuntime> ScriptRuntime::CreateRuntime(int runtimeSize, int heapGrowthBytesGCTrigger)
|
||||
{
|
||||
return shared_ptr<ScriptRuntime>(new ScriptRuntime(runtimeSize, heapGrowthBytesGCTrigger));
|
||||
}
|
||||
|
||||
ScriptRuntime::ScriptRuntime(int runtimeSize, int heapGrowthBytesGCTrigger):
|
||||
m_LastGCBytes(0),
|
||||
m_LastGCCheck(0.0f),
|
||||
m_HeapGrowthBytesGCTrigger(heapGrowthBytesGCTrigger),
|
||||
@ -97,8 +102,7 @@ ScriptRuntime::ScriptRuntime(shared_ptr<ScriptRuntime> parentRuntime, int runtim
|
||||
{
|
||||
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be initialized before constructing any ScriptRuntimes!");
|
||||
|
||||
JSRuntime* parentJSRuntime = parentRuntime ? parentRuntime->m_rt : nullptr;
|
||||
m_rt = JS_NewRuntime(runtimeSize, JS::DefaultNurseryBytes, parentJSRuntime);
|
||||
m_rt = JS_NewRuntime(runtimeSize, JS::DefaultNurseryBytes, nullptr);
|
||||
ENSURE(m_rt); // TODO: error handling
|
||||
|
||||
JS::SetGCSliceCallback(m_rt, GCSliceCallbackHook);
|
||||
|
@ -23,7 +23,11 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#define STACK_CHUNK_SIZE 8192
|
||||
constexpr int STACK_CHUNK_SIZE = 8192;
|
||||
|
||||
// Those are minimal defaults. The runtime for the main game is larger and GCs upon a larger growth.
|
||||
constexpr int DEFAULT_RUNTIME_SIZE = 16 * 1024 * 1024;
|
||||
constexpr int DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER = 2 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* Abstraction around a SpiderMonkey JSRuntime.
|
||||
@ -38,9 +42,21 @@
|
||||
class ScriptRuntime
|
||||
{
|
||||
public:
|
||||
ScriptRuntime(shared_ptr<ScriptRuntime> parentRuntime, int runtimeSize, int heapGrowthBytesGCTrigger);
|
||||
ScriptRuntime(int runtimeSize, int heapGrowthBytesGCTrigger);
|
||||
~ScriptRuntime();
|
||||
|
||||
/**
|
||||
* Returns a runtime, which can used to initialise any number of
|
||||
* ScriptInterfaces contexts. Values created in one context may be used
|
||||
* in any other context from the same runtime (but not any other runtime).
|
||||
* Each runtime should only ever be used on a single thread.
|
||||
* @param runtimeSize Maximum size in bytes of the new runtime
|
||||
* @param heapGrowthBytesGCTrigger Size in bytes of cumulated allocations after which a GC will be triggered
|
||||
*/
|
||||
static shared_ptr<ScriptRuntime> CreateRuntime(
|
||||
int runtimeSize = DEFAULT_RUNTIME_SIZE,
|
||||
int heapGrowthBytesGCTrigger = DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER);
|
||||
|
||||
/**
|
||||
* MaybeIncrementalRuntimeGC tries to determine whether a runtime-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
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -37,7 +37,7 @@
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "ps/Profiler2.h"
|
||||
#include "scriptinterface/ScriptEngine.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "scriptinterface/ScriptRuntime.h"
|
||||
|
||||
class LeakReporter : public CxxTest::GlobalFixture
|
||||
{
|
||||
@ -80,7 +80,7 @@ class MiscSetup : public CxxTest::GlobalFixture
|
||||
|
||||
g_Profiler2.Initialise();
|
||||
m_ScriptEngine = new ScriptEngine;
|
||||
g_ScriptRuntime = ScriptInterface::CreateRuntime();
|
||||
g_ScriptRuntime = ScriptRuntime::CreateRuntime();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user