1
0
forked from mirrors/0ad

Rename ScriptRuntime to ScriptContext

SM52 essentially replaces JSRuntime with JSContext (though JSContext
itself was replaced with JSCompartment).
To prepare for this migration, rename all Runtime-related things to
Context.

Part of the SM52 migration, stage: SM45 compatible.

Patch by: Itms
Refs #4893

Differential Revision: https://code.wildfiregames.com/D3091
This was SVN commit r24181.
This commit is contained in:
wraitii
2020-11-14 10:57:50 +00:00
parent aae417bd29
commit aa15066c69
49 changed files with 250 additions and 250 deletions
@@ -17,7 +17,7 @@
#include "precompiled.h"
#include "ScriptRuntime.h"
#include "ScriptContext.h"
#include "ps/GameSetup/Config.h"
#include "ps/Profile.h"
@@ -135,35 +135,32 @@ void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
} // anonymous namespace
shared_ptr<ScriptRuntime> ScriptRuntime::CreateRuntime(int runtimeSize, int heapGrowthBytesGCTrigger)
shared_ptr<ScriptContext> ScriptContext::CreateContext(int contextSize, int heapGrowthBytesGCTrigger)
{
return shared_ptr<ScriptRuntime>(new ScriptRuntime(runtimeSize, heapGrowthBytesGCTrigger));
return shared_ptr<ScriptContext>(new ScriptContext(contextSize, heapGrowthBytesGCTrigger));
}
ScriptRuntime::ScriptRuntime(int runtimeSize, int heapGrowthBytesGCTrigger):
ScriptContext::ScriptContext(int contextSize, int heapGrowthBytesGCTrigger):
m_LastGCBytes(0),
m_LastGCCheck(0.0f),
m_HeapGrowthBytesGCTrigger(heapGrowthBytesGCTrigger),
m_RuntimeSize(runtimeSize)
m_ContextSize(contextSize)
{
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be initialized before constructing any ScriptRuntimes!");
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be initialized before constructing any ScriptContexts!");
m_rt = JS_NewRuntime(runtimeSize, JS::DefaultNurseryBytes, nullptr);
m_rt = JS_NewRuntime(contextSize, JS::DefaultNurseryBytes, nullptr);
ENSURE(m_rt); // TODO: error handling
JS::SetGCSliceCallback(m_rt, GCSliceCallbackHook);
JS_SetGCParameter(m_rt, JSGC_MAX_MALLOC_BYTES, m_RuntimeSize);
JS_SetGCParameter(m_rt, JSGC_MAX_BYTES, m_RuntimeSize);
JS_SetGCParameter(m_rt, JSGC_MAX_MALLOC_BYTES, m_ContextSize);
JS_SetGCParameter(m_rt, JSGC_MAX_BYTES, m_ContextSize);
JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
// The whole heap-growth mechanism seems to work only for non-incremental GCs.
// 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);
ScriptEngine::GetSingleton().RegisterRuntime(m_rt);
m_cx = JS_NewContext(m_rt, STACK_CHUNK_SIZE);
ENSURE(m_cx); // TODO: error handling
@@ -184,30 +181,33 @@ ScriptRuntime::ScriptRuntime(int runtimeSize, int heapGrowthBytesGCTrigger):
.setExtraWarnings(true)
.setWerror(false)
.setStrictMode(true);
ScriptEngine::GetSingleton().RegisterContext(m_cx);
}
ScriptRuntime::~ScriptRuntime()
ScriptContext::~ScriptContext()
{
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be active (initialized and not yet shut down) when destroying a ScriptContext!");
JS_DestroyContext(m_cx);
JS_DestroyRuntime(m_rt);
ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be active (initialized and not yet shut down) when destroying a ScriptRuntime!");
ScriptEngine::GetSingleton().UnRegisterRuntime(m_rt);
ScriptEngine::GetSingleton().UnRegisterContext(m_cx);
}
void ScriptRuntime::RegisterCompartment(JSCompartment* cmpt)
void ScriptContext::RegisterCompartment(JSCompartment* cmpt)
{
ENSURE(cmpt);
m_Compartments.push_back(cmpt);
}
void ScriptRuntime::UnRegisterCompartment(JSCompartment* cmpt)
void ScriptContext::UnRegisterCompartment(JSCompartment* cmpt)
{
m_Compartments.remove(cmpt);
}
#define GC_DEBUG_PRINT 0
void ScriptRuntime::MaybeIncrementalGC(double delay)
void ScriptContext::MaybeIncrementalGC(double delay)
{
PROFILE2("MaybeIncrementalGC");
@@ -260,31 +260,31 @@ void ScriptRuntime::MaybeIncrementalGC(double delay)
m_HeapGrowthBytesGCTrigger / 1024);
#endif
// A hack to make sure we never exceed the runtime size because we can't collect the memory
// A hack to make sure we never exceed the context size because we can't collect the memory
// fast enough.
if (gcBytes > m_RuntimeSize / 2)
if (gcBytes > m_ContextSize / 2)
{
if (JS::IsIncrementalGCInProgress(m_rt))
{
#if GC_DEBUG_PRINT
printf("Finishing incremental GC because gcBytes > m_RuntimeSize / 2. \n");
printf("Finishing incremental GC because gcBytes > m_ContextSize / 2. \n");
#endif
PrepareCompartmentsForIncrementalGC();
JS::FinishIncrementalGC(m_rt, JS::gcreason::REFRESH_FRAME);
}
else
{
if (gcBytes > m_RuntimeSize * 0.75)
if (gcBytes > m_ContextSize * 0.75)
{
ShrinkingGC();
#if GC_DEBUG_PRINT
printf("Running shrinking GC because gcBytes > m_RuntimeSize * 0.75. \n");
printf("Running shrinking GC because gcBytes > m_ContextSize * 0.75. \n");
#endif
}
else
{
#if GC_DEBUG_PRINT
printf("Running full GC because gcBytes > m_RuntimeSize / 2. \n");
printf("Running full GC because gcBytes > m_ContextSize / 2. \n");
#endif
JS_GC(m_rt);
}
@@ -309,7 +309,7 @@ void ScriptRuntime::MaybeIncrementalGC(double delay)
}
}
void ScriptRuntime::ShrinkingGC()
void ScriptContext::ShrinkingGC()
{
JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_COMPARTMENT);
JS::PrepareForFullGC(m_rt);
@@ -317,7 +317,7 @@ void ScriptRuntime::ShrinkingGC()
JS_SetGCParameter(m_rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
}
void ScriptRuntime::PrepareCompartmentsForIncrementalGC() const
void ScriptContext::PrepareCompartmentsForIncrementalGC() const
{
for (JSCompartment* const& cmpt : m_Compartments)
JS::PrepareZoneForGC(js::GetCompartmentZone(cmpt));
@@ -15,8 +15,8 @@
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_SCRIPTRUNTIME
#define INCLUDED_SCRIPTRUNTIME
#ifndef INCLUDED_SCRIPTCONTEXT
#define INCLUDED_SCRIPTCONTEXT
#include "ScriptTypes.h"
#include "ScriptExtraHeaders.h"
@@ -26,37 +26,38 @@
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_CONTEXT_SIZE = 16 * 1024 * 1024;
constexpr int DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER = 2 * 1024 * 1024;
/**
* Abstraction around a SpiderMonkey JSRuntime/JSContext.
*
* A single ScriptRuntime, with the associated runtime and context,
* A single ScriptContext, with the associated runtime and context,
* should only be used on a single thread.
*
* (One means to share data between threads and runtimes is to create
* (One means to share data between threads and contexts is to create
* a ScriptInterface::StructuredClone.)
*/
class ScriptRuntime
class ScriptContext
{
public:
ScriptRuntime(int runtimeSize, int heapGrowthBytesGCTrigger);
~ScriptRuntime();
ScriptContext(int contextSize, int heapGrowthBytesGCTrigger);
~ScriptContext();
/**
* Returns a runtime/context, in which any number of ScriptInterfaces compartments can live.
* Each runtime should only ever be used on a single thread.
* @param runtimeSize Maximum size in bytes of the new runtime
* Returns a context, in which any number of ScriptInterfaces compartments can live.
* Each context should only ever be used on a single thread.
* @param parentContext Parent context from the parent thread, with which we share some thread-safe data
* @param contextSize Maximum size in bytes of the new context
* @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,
static shared_ptr<ScriptContext> CreateContext(
int contextSize = DEFAULT_CONTEXT_SIZE,
int heapGrowthBytesGCTrigger = DEFAULT_HEAP_GROWTH_BYTES_GCTRIGGER);
/**
* MaybeIncrementalRuntimeGC tries to determine whether a runtime-wide garbage collection would free up enough memory to
* 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
* such functionality currently isn't available out of the box.
* It does incremental GC which means it will collect one slice each time it's called until the garbage collection is done.
@@ -93,10 +94,10 @@ private:
void PrepareCompartmentsForIncrementalGC() const;
std::list<JSCompartment*> m_Compartments;
int m_RuntimeSize;
int m_ContextSize;
int m_HeapGrowthBytesGCTrigger;
int m_LastGCBytes;
double m_LastGCCheck;
};
#endif // INCLUDED_SCRIPTRUNTIME
#endif // INCLUDED_SCRIPTCONTEXT
+9 -9
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2019 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -25,10 +25,10 @@
/**
* A class using the RAII (Resource Acquisition Is Initialization) idiom to manage initialization
* and shutdown of the SpiderMonkey script engine. It also keeps a count of active script runtimes
* and shutdown of the SpiderMonkey script engine. It also keeps a count of active script contexts
* in order to validate the following constraints:
* 1. JS_Init must be called before any ScriptRuntimes are initialized
* 2. JS_Shutdown must be called after all ScriptRuntimes have been destroyed
* 1. JS_Init must be called before any ScriptContexts are initialized
* 2. JS_Shutdown must be called after all ScriptContexts have been destroyed
*/
class ScriptEngine : public Singleton<ScriptEngine>
@@ -36,21 +36,21 @@ class ScriptEngine : public Singleton<ScriptEngine>
public:
ScriptEngine()
{
ENSURE(m_Runtimes.empty() && "JS_Init must be called before any runtimes are created!");
ENSURE(m_Contexts.empty() && "JS_Init must be called before any contexts are created!");
JS_Init();
}
~ScriptEngine()
{
ENSURE(m_Runtimes.empty() && "All runtimes must be destroyed before calling JS_ShutDown!");
ENSURE(m_Contexts.empty() && "All contexts must be destroyed before calling JS_ShutDown!");
JS_ShutDown();
}
void RegisterRuntime(const JSRuntime* rt) { m_Runtimes.push_back(rt); }
void UnRegisterRuntime(const JSRuntime* rt) { m_Runtimes.remove(rt); }
void RegisterContext(const JSContext* cx) { m_Contexts.push_back(cx); }
void UnRegisterContext(const JSContext* cx) { m_Contexts.remove(cx); }
private:
std::list<const JSRuntime*> m_Runtimes;
std::list<const JSContext*> m_Contexts;
};
#endif // INCLUDED_SCRIPTENGINE
+13 -13
View File
@@ -17,8 +17,8 @@
#include "precompiled.h"
#include "ScriptContext.h"
#include "ScriptInterface.h"
#include "ScriptRuntime.h"
#include "ScriptStats.h"
#include "lib/debug.h"
@@ -54,13 +54,13 @@
struct ScriptInterface_impl
{
ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime);
ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptContext>& context);
~ScriptInterface_impl();
void Register(const char* name, JSNative fptr, uint 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.
shared_ptr<ScriptRuntime> m_runtime;
// members have to be called before the context destructor.
shared_ptr<ScriptContext> m_context;
friend ScriptInterface::Request;
private:
@@ -318,8 +318,8 @@ bool ScriptInterface::MathRandom(double& nbr)
return true;
}
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) :
m_runtime(runtime), m_cx(runtime->GetGeneralJSContext()), m_glob(runtime->GetJSRuntime()), m_nativeScope(runtime->GetJSRuntime())
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptContext>& context) :
m_context(context), m_cx(context->GetGeneralJSContext()), m_glob(context->GetJSRuntime()), m_nativeScope(context->GetJSRuntime())
{
JS::CompartmentOptions opt;
opt.setVersion(JSVERSION_LATEST);
@@ -348,12 +348,12 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const sh
Register("ProfileStop", ::ProfileStop, 0);
Register("ProfileAttribute", ::ProfileAttribute, 1);
m_runtime->RegisterCompartment(js::GetObjectCompartment(m_glob));
m_context->RegisterCompartment(js::GetObjectCompartment(m_glob));
}
ScriptInterface_impl::~ScriptInterface_impl()
{
m_runtime->UnRegisterCompartment(js::GetObjectCompartment(m_glob));
m_context->UnRegisterCompartment(js::GetObjectCompartment(m_glob));
}
void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint nargs) const
@@ -364,8 +364,8 @@ void ScriptInterface_impl::Register(const char* name, JSNative fptr, uint nargs)
JS::RootedFunction func(m_cx, JS_DefineFunction(m_cx, nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT));
}
ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName, const shared_ptr<ScriptRuntime>& runtime) :
m(new ScriptInterface_impl(nativeScopeName, runtime))
ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName, const shared_ptr<ScriptContext>& context) :
m(new ScriptInterface_impl(nativeScopeName, context))
{
// Profiler stats table isn't thread-safe, so only enable this on the main thread
if (ThreadUtil::IsMainThread())
@@ -447,12 +447,12 @@ void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs) co
JSRuntime* ScriptInterface::GetJSRuntime() const
{
return m->m_runtime->GetJSRuntime();
return m->m_context->GetJSRuntime();
}
shared_ptr<ScriptRuntime> ScriptInterface::GetRuntime() const
shared_ptr<ScriptContext> ScriptInterface::GetContext() const
{
return m->m_runtime;
return m->m_context;
}
void ScriptInterface::CallConstructor(JS::HandleValue ctor, JS::HandleValueArray argv, JS::MutableHandleValue out) const
+7 -7
View File
@@ -50,11 +50,11 @@ ERROR_TYPE(Scripting_DefineType, CreationFailed);
struct ScriptInterface_impl;
class ScriptRuntime;
class ScriptContext;
// 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;
// Using a global object for the context is a workaround until Simulation, AI, etc,
// use their own threads and also their own contexts.
extern thread_local shared_ptr<ScriptContext> g_ScriptContext;
/**
@@ -76,9 +76,9 @@ public:
* @param nativeScopeName Name of global object that functions (via RegisterFunction) will
* be placed into, as a scoping mechanism; typically "Engine"
* @param debugName Name of this interface for CScriptStats purposes.
* @param runtime ScriptRuntime to use when initializing this interface.
* @param context ScriptContext to use when initializing this interface.
*/
ScriptInterface(const char* nativeScopeName, const char* debugName, const shared_ptr<ScriptRuntime>& runtime);
ScriptInterface(const char* nativeScopeName, const char* debugName, const shared_ptr<ScriptContext>& context);
~ScriptInterface();
@@ -92,7 +92,7 @@ public:
static CmptPrivate* GetScriptInterfaceAndCBData(JSContext* cx);
JSRuntime* GetJSRuntime() const;
shared_ptr<ScriptRuntime> GetRuntime() const;
shared_ptr<ScriptContext> GetContext() const;
/**
* RAII structure which encapsulates an access to the context and compartment of a ScriptInterface.
@@ -33,7 +33,7 @@ class TestScriptConversions : public CxxTest::TestSuite
template <typename T>
void convert_to(const T& value, const std::string& expected)
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
TS_ASSERT(script.LoadGlobalScripts());
ScriptInterface::Request rq(script);
@@ -52,7 +52,7 @@ class TestScriptConversions : public CxxTest::TestSuite
template <typename T>
void roundtrip(const T& value, const char* expected)
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
TS_ASSERT(script.LoadGlobalScripts());
ScriptInterface::Request rq(script);
@@ -74,7 +74,7 @@ class TestScriptConversions : public CxxTest::TestSuite
template <typename T>
void call_prototype_function(const T& u, const T& v, const std::string& func, const std::string& expected)
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
TS_ASSERT(script.LoadGlobalScripts());
ScriptInterface::Request rq(script);
@@ -168,7 +168,7 @@ public:
void test_integers()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
ScriptInterface::Request rq(script);
// using new uninitialized variables each time to be sure the test doesn't succeeed if ToJSVal doesn't touch the value at all.
@@ -200,7 +200,7 @@ public:
roundtrip<float>(-std::numeric_limits<float>::infinity(), "-Infinity");
convert_to<float>(std::numeric_limits<float>::quiet_NaN(), "NaN"); // can't use roundtrip since nan != nan
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
ScriptInterface::Request rq(script);
float f = 0;
@@ -250,7 +250,7 @@ public:
void test_utf8utf16_conversion()
{
// Fancier conversion: we store UTF8 and get UTF16 and vice-versa
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
TS_ASSERT(script.LoadGlobalScripts());
ScriptInterface::Request rq(script);
@@ -28,7 +28,7 @@ class TestScriptInterface : public CxxTest::TestSuite
public:
void test_loadscript_basic()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
TestLogger logger;
TS_ASSERT(script.LoadScript(L"test.js", "var x = 1+1;"));
TS_ASSERT_STR_NOT_CONTAINS(logger.GetOutput(), "JavaScript error");
@@ -37,7 +37,7 @@ public:
void test_loadscript_error()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
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");
@@ -45,7 +45,7 @@ public:
void test_loadscript_strict_warning()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
TestLogger logger;
// in strict mode, this inside a function doesn't point to the global object
TS_ASSERT(script.LoadScript(L"test.js", "var isStrict = (function() { return !this; })();warn('isStrict is '+isStrict);"));
@@ -54,7 +54,7 @@ public:
void test_loadscript_strict_error()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
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");
@@ -62,8 +62,8 @@ public:
void test_clone_basic()
{
ScriptInterface script1("Test", "Test", g_ScriptRuntime);
ScriptInterface script2("Test", "Test", g_ScriptRuntime);
ScriptInterface script1("Test", "Test", g_ScriptContext);
ScriptInterface script2("Test", "Test", g_ScriptContext);
ScriptInterface::Request rq1(script1);
JS::RootedValue obj1(rq1.cx);
@@ -83,8 +83,8 @@ public:
void test_clone_getters()
{
// The tests should be run with JS_SetGCZeal so this can try to find GC bugs
ScriptInterface script1("Test", "Test", g_ScriptRuntime);
ScriptInterface script2("Test", "Test", g_ScriptRuntime);
ScriptInterface script1("Test", "Test", g_ScriptContext);
ScriptInterface script2("Test", "Test", g_ScriptContext);
ScriptInterface::Request rq1(script1);
@@ -104,8 +104,8 @@ public:
void test_clone_cyclic()
{
ScriptInterface script1("Test", "Test", g_ScriptRuntime);
ScriptInterface script2("Test", "Test", g_ScriptRuntime);
ScriptInterface script1("Test", "Test", g_ScriptContext);
ScriptInterface script2("Test", "Test", g_ScriptContext);
ScriptInterface::Request rq1(script1);
@@ -136,7 +136,7 @@ public:
*/
void test_rooted_templates()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
ScriptInterface::Request rq(script);
@@ -215,7 +215,7 @@ public:
void test_random()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
double d1, d2;
TS_ASSERT(script.Eval("Math.random()", d1));
@@ -235,7 +235,7 @@ public:
void test_json()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
ScriptInterface::Request rq(script);
std::string input = "({'x':1,'z':[2,'3\\u263A\\ud800'],\"y\":true})";
@@ -253,7 +253,7 @@ public:
// extends the functionality and is then assigned to the name of the function.
void test_function_override()
{
ScriptInterface script("Test", "Test", g_ScriptRuntime);
ScriptInterface script("Test", "Test", g_ScriptContext);
ScriptInterface::Request rq(script);
TS_ASSERT(script.Eval(