Belatedly remembered that the whole multiple-JavaScript-context thing was a completely bogus hack to work around bad exception handling, and ripped it out for the slight simplicity win.

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@4142 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2011-01-24 17:17:43 +00:00
parent df33517045
commit a9fda60269
15 changed files with 180 additions and 302 deletions

View File

@ -101,7 +101,7 @@ static OODebugMonitor *sSingleton = nil;
[jsEng setMonitor:self];
#endif
context = [jsEng acquireContext];
context = OOJSAcquireContext();
// Set up JavaScript side of console.
BOOL savedShow = OOLogWillDisplayMessagesInClass(@"script.load.notFound");
@ -120,7 +120,7 @@ static OODebugMonitor *sSingleton = nil;
JS_DefineProperty(context, global, "debugConsole", [self oo_jsValueInContext:context], NULL, NULL, JSPROP_ENUMERATE);
}
[jsEng releaseContext:context];
OOJSRelinquishContext(context);
}
return self;
@ -607,15 +607,14 @@ typedef struct
SizeString(visibleTextureDataSize)];
#if OO_NEW_JS
OOJavaScriptEngine *jsEngine = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEngine acquireContext];
JSContext *context = OOJSAcquireContext();
JSRuntime *runtime = JS_GetRuntime(context);
size_t jsSize = JS_GetGCParameter(runtime, JSGC_BYTES);
size_t jsMax = JS_GetGCParameter(runtime, JSGC_MAX_BYTES);
uint32_t jsGCCount = JS_GetGCParameter(runtime, JSGC_NUMBER);
[jsEngine releaseContext:context];
OOJSRelinquishContext(context);
[self writeMemStat:@"JavaScript heap: %@ (limit %@, %u collections to date)", SizeString(jsSize), SizeString(jsMax), jsGCCount];
totalSize += jsSize;

View File

@ -1282,12 +1282,9 @@ static GLfloat sBaseMass = 0.0;
dockedStation = [UNIVERSE station];
target_system_seed = [UNIVERSE findSystemAtCoords:cursor_coordinates withGalaxySeed:galaxy_seed];
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEng acquireContext];
JSContext *context = OOJSAcquireContext();
[self doWorldScriptEvent:OOJSID("startUp") inContext:context withArguments:NULL count:0 timeLimit:kOOJSLongTimeLimit];
[jsEng releaseContext:context];
OOJSRelinquishContext(context);
}
@ -6451,12 +6448,9 @@ static NSString *last_outfitting_key=nil;
- (void) noteGUIWillChangeTo:(OOGUIScreenID)toScreen
{
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEng acquireContext];
JSContext *context = OOJSAcquireContext();
ShipScriptEvent(context, self, "guiScreenWillChange", OOJSValueFromGUIScreenID(context, toScreen), OOJSValueFromGUIScreenID(context, gui_screen));
[jsEng releaseContext:context];
OOJSRelinquishContext(context);
}
@ -6481,12 +6475,9 @@ static NSString *last_outfitting_key=nil;
}
if (![[UNIVERSE gameController] gameIsPaused])
{
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEng acquireContext];
JSContext *context = OOJSAcquireContext();
ShipScriptEvent(context, self, "guiScreenChanged", OOJSValueFromGUIScreenID(context, toScreen), OOJSValueFromGUIScreenID(context, fromScreen));
[jsEng releaseContext:context];
OOJSRelinquishContext(context);
}
}
}
@ -8079,8 +8070,7 @@ static NSString *last_outfitting_key=nil;
- (void) doScriptEvent:(OOJSPropID)message withArguments:(NSArray *)arguments
{
OOJavaScriptEngine *engine = [OOJavaScriptEngine sharedEngine];
JSContext *context = [engine acquireContext];
JSContext *context = OOJSAcquireContext();
uintN i, argc;
jsval *argv = NULL;
@ -8113,7 +8103,7 @@ static NSString *last_outfitting_key=nil;
free(argv);
}
[engine releaseContext:context];
OOJSRelinquishContext(context);
}
@ -8128,7 +8118,7 @@ static NSString *last_outfitting_key=nil;
{
NSEnumerator *scriptEnum = [worldScripts objectEnumerator];
OOScript *theScript;
OOJSPropID messageID = OOJSPropIDFromString(NULL, message);
OOJSPropID messageID = OOJSPropIDFromString(message);
// Check for the pressence of report messages first.
if (gui_screen != GUI_SCREEN_MISSION && [dockingReport length] > 0 && [self isDocked] && ![dockedStation suppressArrivalReports])

View File

@ -9116,8 +9116,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
{
if (!_escortPositionsValid)
{
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEng acquireContext];
JSContext *context = OOJSAcquireContext();
jsval result;
jsval args[] = { INT_TO_JSVAL(0), INT_TO_JSVAL(_maxEscortCount) };
BOOL OK;
@ -9130,7 +9129,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
{
args[0] = INT_TO_JSVAL(i);
OOJSStartTimeLimiter();
OK = [script callMethodNamed:OOJSIDCX(context, "coordinatesForEscortPosition")
OK = [script callMethodNamed:OOJSID("coordinatesForEscortPosition")
withArguments:args count:sizeof args / sizeof *args
inContext:context
gettingResult:&result];
@ -9141,7 +9140,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
if (!OK) _escortPositions[i] = kZeroVector;
}
[jsEng releaseContext:context];
OOJSRelinquishContext(context);
}
}
@ -9896,7 +9895,7 @@ static BOOL AuthorityPredicate(Entity *entity, void *parameter)
// For ease of overriding, these all go through doScriptEvent:withArguments:.
- (void) doScriptEvent:(NSString *)message
{
[self doScriptEvent:OOJSPropIDFromString(NULL, message) withArguments:nil];
[self doScriptEvent:OOJSPropIDFromString(message) withArguments:nil];
}
@ -9909,7 +9908,7 @@ static BOOL AuthorityPredicate(Entity *entity, void *parameter)
else
{
arguments = [NSArray arrayWithObject:argument];
[self doScriptEvent:OOJSPropIDFromString(NULL, message) withArguments:arguments];
[self doScriptEvent:OOJSPropIDFromString(message) withArguments:arguments];
}
}

View File

@ -1969,7 +1969,7 @@ static WormholeEntity *whole = nil;
OOJSFunction *function = nil;
JSContext *context = NULL;
context = [[OOJavaScriptEngine sharedEngine] acquireContext];
context = OOJSAcquireContext();
if (predicateExpression == nil) predicateExpression = @"false";
@ -2035,7 +2035,7 @@ static WormholeEntity *whole = nil;
}
JS_ReportPendingException(context);
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
OOJSRelinquishContext(context);
}

View File

@ -59,7 +59,9 @@ static OORegExpMatcher *sActiveInstance;
unsigned codeLine = __LINE__ + 1; // NB: should remain line before code.
NSString *code = @"return regexp.test(string);";
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
[OOJavaScriptEngine sharedEngine]; // Summon the beast from the Pit.
JSContext *context = OOJSAcquireContext();
_tester = [[OOJSFunction alloc] initWithName:@"matchesRegExp"
scope:NULL
code:code
@ -69,7 +71,7 @@ static OORegExpMatcher *sActiveInstance;
lineNumber:codeLine
context:context];
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
OOJSRelinquishContext(context);
if (_tester == nil) DESTROY(self);
}
@ -105,7 +107,7 @@ static OORegExpMatcher *sActiveInstance;
size_t expLength = [regExp length];
if (EXPECT_NOT(expLength == 0)) return NO;
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JSContext *context = OOJSAcquireContext();
// Create new RegExp object if necessary.
if (flags != _cachedFlags || ![regExp isEqualToString:_cachedRegExpString])
@ -134,7 +136,7 @@ static OORegExpMatcher *sActiveInstance;
scope:nil
arguments:[NSArray arrayWithObjects:string, _cachedRegExpObject, nil]];
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
OOJSRelinquishContext(context);
return result;
}

View File

@ -713,15 +713,14 @@ NSString *OOPadStringTo(NSString * string, float numSpaces)
NSString *OOStringFromDeciCredits(OOCreditsQuantity tenthsOfCredits, BOOL includeDecimal, BOOL includeSymbol)
{
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEng acquireContext];
JSObject *global = [jsEng globalObject];
JSContext *context = OOJSAcquireContext();
JSObject *global = [[OOJavaScriptEngine sharedEngine] globalObject];
JSObject *fakeRoot;
jsval method;
jsval rval;
NSString *result = @"<error>";
if (OOJSGetMethod(context, global, OOJSIDCX(context, "formatCredits"), &fakeRoot, &method))
if (OOJSGetMethod(context, global, OOJSID("formatCredits"), &fakeRoot, &method))
{
jsval args[3];
if (JS_NewDoubleValue(context, tenthsOfCredits * 0.1, &args[0]))
@ -737,7 +736,7 @@ NSString *OOStringFromDeciCredits(OOCreditsQuantity tenthsOfCredits, BOOL includ
}
}
[jsEng releaseContext:context];
OOJSRelinquishContext(context);
return result;
}

View File

@ -90,12 +90,9 @@ MA 02110-1301, USA.
const char *JSValueToStrDbg(jsval val)
{
OOJavaScriptEngine *jsEngine = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEngine acquireContext];
JSContext *context = OOJSAcquireContext();
const char *result = [[NSString stringWithJavaScriptValue:val inContext:context] UTF8String];
[jsEngine releaseContext:context];
OOJSRelinquishContext(context);
return result;
}

View File

@ -28,11 +28,6 @@ MA 02110-1301, USA.
*/
#if !JS_THREADSAFE
#define JS_IsInRequest(context) (((void)(context)), YES)
#endif
/***** Transitional compatibility stuff - remove when switching to OO_NEW_JS permanently. *****/
@ -139,9 +134,6 @@ static inline void JS_RemoveStringRoot(JSContext *cx, JSString **rp) { JS_Remove
static inline void JS_RemoveObjectRoot(JSContext *cx, JSObject **rp) { JS_RemoveRoot(cx, rp); }
static inline void JS_RemoveGCThingRoot(JSContext *cx, void **rp) { JS_RemoveRoot(cx, rp); }
#define JS_BeginRequest(cx) do {} while (0)
#define JS_EndRequest(cx) do {} while (0)
#endif

View File

@ -135,8 +135,7 @@ void OOJSFrameCallbacksInvoke(OOTimeDelta delta)
if (sCount != 0)
{
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEng acquireContext];
JSContext *context = OOJSAcquireContext();
jsval deltaVal, result;
OOUInteger i;
@ -165,7 +164,7 @@ void OOJSFrameCallbacksInvoke(OOTimeDelta delta)
DESTROY(sDeferredOps);
}
[jsEng releaseContext:context];
OOJSRelinquishContext(context);
}
}
@ -176,12 +175,9 @@ void OOJSFrameCallbacksRemoveAll(void)
if (sCount != 0)
{
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
JSContext *context = [jsEng acquireContext];
JSContext *context = OOJSAcquireContext();
while (sCount != 0) RemoveCallbackAtIndex(context, sCount - 1);
[jsEng releaseContext:context];
OOJSRelinquishContext(context);
}
}

View File

@ -68,7 +68,7 @@ MA 02110-1301, USA.
if (context == NULL)
{
context = [[OOJavaScriptEngine sharedEngine] acquireContext];
context = OOJSAcquireContext();
releaseContext = YES;
}
if (scope == NULL) scope = [[OOJavaScriptEngine sharedEngine] globalObject];
@ -104,7 +104,7 @@ MA 02110-1301, USA.
DESTROY(self);
}
if (releaseContext) [[OOJavaScriptEngine sharedEngine] releaseContext:context];
if (releaseContext) OOJSRelinquishContext(context);
return self;
}

View File

@ -103,7 +103,7 @@ void MissionRunCallback()
jsval rval = JSVAL_VOID;
PlayerEntity *player = OOPlayerForScripting();
OOJavaScriptEngine *engine = [OOJavaScriptEngine sharedEngine];
JSContext *context = [engine acquireContext];
JSContext *context = OOJSAcquireContext();
/* Create temporarily-rooted local copies of sCallbackFunction and
sCallbackThis, then clear the statics. This must be done in advance
@ -146,7 +146,7 @@ void MissionRunCallback()
JS_RemoveValueRoot(context, &cbFunction);
JS_RemoveObjectRoot(context, &cbThis);
[engine releaseContext:context];
OOJSRelinquishContext(context);
}

View File

@ -109,7 +109,6 @@ static JSFunctionSpec sScriptMethods[] =
- (id) initWithPath:(NSString *)path properties:(NSDictionary *)properties
{
OOJavaScriptEngine *engine = nil;
JSContext *context = NULL;
NSString *problem = nil; // Acts as error flag.
JSScript *script = NULL;
@ -122,8 +121,7 @@ static JSFunctionSpec sScriptMethods[] =
self = [super init];
if (self == nil) problem = @"allocation failure";
engine = [OOJavaScriptEngine sharedEngine];
context = [engine acquireContext];
context = OOJSAcquireContext();
// Set up JS object
if (!problem)
@ -183,7 +181,7 @@ static JSFunctionSpec sScriptMethods[] =
the script object can't be renamed after the initial run. This could
probably also be achieved by fiddling with JS property attributes.
*/
OOJSPropID nameID = OOJSIDCX(context, "name");
OOJSPropID nameID = OOJSID("name");
[self setProperty:[self scriptNameFromPath:path] withID:nameID inContext:context];
// Run the script (allowing it to set up the properties we need, as well as setting up those event handlers)
@ -216,8 +214,8 @@ static JSFunctionSpec sScriptMethods[] =
[self setProperty:name withID:nameID inContext:context];
}
version = [[[self propertyWithID:OOJSIDCX(context, "version") inContext:context] description] copy];
description = [[[self propertyWithID:OOJSIDCX(context, "description") inContext:context] description] copy];
version = [[[self propertyWithID:OOJSID("version") inContext:context] description] copy];
description = [[[self propertyWithID:OOJSID("description") inContext:context] description] copy];
OOLog(@"script.javaScript.load.success", @"Loaded JavaScript OXP: %@ -- %@", [self displayName], description ? description : (NSString *)@"(no description)");
}
@ -231,7 +229,7 @@ static JSFunctionSpec sScriptMethods[] =
self = nil;
}
[engine releaseContext:context];
OOJSRelinquishContext(context);
return self;
// Analyzer: object leaked. [Expected, object is retained by JS object.]
@ -245,12 +243,12 @@ static JSFunctionSpec sScriptMethods[] =
[version release];
DESTROY(filePath);
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JSContext *context = OOJSAcquireContext();
OOJSObjectWrapperFinalize(context, _jsSelf); // Release weakref to self
OOJSObjectWrapperFinalize(context, _jsSelf); // Release weakref to self
JS_RemoveObjectRoot(context, &_jsSelf); // Unroot jsSelf
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
OOJSRelinquishContext(context);
[weakSelf weakRefDrop];
@ -322,8 +320,7 @@ static JSFunctionSpec sScriptMethods[] =
- (BOOL) doEvent:(OOJSPropID)eventID withArguments:(NSArray *)arguments
{
OOJavaScriptEngine *engine = [OOJavaScriptEngine sharedEngine];
JSContext *context = [engine acquireContext];
JSContext *context = OOJSAcquireContext();
uintN i, argc;
jsval *argv = NULL;
jsval function;
@ -361,7 +358,7 @@ static JSFunctionSpec sScriptMethods[] =
}
}
[engine releaseContext:context];
OOJSRelinquishContext(context);
return OK;
}
@ -397,7 +394,7 @@ static JSFunctionSpec sScriptMethods[] =
if (EXPECT(OOJSGetMethod(context, _jsSelf, methodID, &fakeRoot, &method) && !JSVAL_IS_VOID(method)))
{
#ifndef NDEBUG
OOLog(@"script.trace.javaScript.callback", @"Calling [%@].%@()", [self name], OOStringFromJSPropID(context, methodID));
OOLog(@"script.trace.javaScript.callback", @"Calling [%@].%@()", [self name], OOStringFromJSPropID(methodID));
OOLogIndentIf(@"script.trace.javaScript.callback");
#endif
@ -461,11 +458,9 @@ static JSFunctionSpec sScriptMethods[] =
{
if (propName == nil) return nil;
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
id result = [self propertyWithID:OOJSPropIDFromString(context, propName) inContext:context];
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
JSContext *context = OOJSAcquireContext();
id result = [self propertyWithID:OOJSPropIDFromString(propName) inContext:context];
OOJSRelinquishContext(context);
return result;
}
@ -475,11 +470,10 @@ static JSFunctionSpec sScriptMethods[] =
{
if (value == nil || propName == nil) return NO;
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JSContext *context = OOJSAcquireContext();
BOOL result = [self setProperty:value withID:OOJSPropIDFromString(propName) inContext:context];
OOJSRelinquishContext(context);
BOOL result = [self setProperty:value withID:OOJSPropIDFromString(context, propName) inContext:context];
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
return result;
}
@ -488,11 +482,10 @@ static JSFunctionSpec sScriptMethods[] =
{
if (value == nil || propName == nil) return NO;
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JSContext *context = OOJSAcquireContext();
BOOL result = [self defineProperty:value withID:OOJSPropIDFromString(propName) inContext:context];
OOJSRelinquishContext(context);
BOOL result = [self defineProperty:value withID:OOJSPropIDFromString(context, propName) inContext:context];
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
return result;
}
@ -589,7 +582,7 @@ static JSFunctionSpec sScriptMethods[] =
#ifndef NDEBUG
NSAssert1(OOJSValueIsFunction(context, method), @"Expected function, got %@.", OOStringFromJSValueEvenIfNull(context, method));
OOLog(@"script.trace.javaScript.event", @"Calling [%@].%@()", [self name], OOStringFromJSPropID(context, eventID));
OOLog(@"script.trace.javaScript.event", @"Calling [%@].%@()", [self name], OOStringFromJSPropID(eventID));
OOLogIndentIf(@"script.trace.javaScript.event");
#endif

View File

@ -101,9 +101,9 @@ static JSClass sTimerClass;
NSString *funcName = nil;
JSContext *context = NULL;
context = [[OOJavaScriptEngine sharedEngine] acquireContext];
context = OOJSAcquireContext();
funcName = OOStringFromJSString(context, JS_GetFunctionId(JS_ValueToFunction(context, _function)));
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
OOJSRelinquishContext(context);
if (funcName == nil)
{
@ -126,7 +126,7 @@ static JSClass sTimerClass;
NSString *description = nil;
OOJavaScriptEngine *engine = [OOJavaScriptEngine sharedEngine];
JSContext *context = [engine acquireContext];
JSContext *context = OOJSAcquireContext();
// stop and remove the timer if _jsThis (the first parameter in the constructor) dies.
id object = OOJSNativeObjectFromJSObject(context, _jsThis);
@ -151,7 +151,7 @@ static JSClass sTimerClass;
result:&rval];
[OOJSScript popScript:_owningScript];
[engine releaseContext:context];
OOJSRelinquishContext(context);
}

View File

@ -42,20 +42,10 @@ MA 02110-1301, USA.
@protocol OOJavaScriptEngineMonitor;
enum
{
kOOJavaScriptEngineContextPoolCount = 5
};
@interface OOJavaScriptEngine: NSObject
{
@private
JSRuntime *runtime;
JSContext *mainContext;
JSContext *contextPool[kOOJavaScriptEngineContextPoolCount];
uint8_t contextPoolCount;
uint8_t mainContextInUse;
JSObject *globalObject;
BOOL _showErrorLocations;
@ -90,11 +80,6 @@ enum
argv:(jsval *)argv
result:(jsval *)outResult;
// Get a JS context, and put it in a request.
- (JSContext *)acquireContext;
// Return a context provided by -acquireContext, and end a request.
- (void)releaseContext:(JSContext *)context;
- (void) removeGCObjectRoot:(JSObject **)rootPtr;
- (void) removeGCValueRoot:(jsval *)rootPtr;
@ -123,32 +108,55 @@ enum
@end
#if !JS_THREADSAFE
#define JS_IsInRequest(context) (((void)(context)), YES)
#define JS_BeginRequest(context) do {} while (0)
#define JS_EndRequest(context) do {} while (0)
#endif
// Get the main thread's JS context, and begin a request on it.
OOINLINE JSContext *OOJSAcquireContext(void)
{
extern JSContext *gOOJSMainThreadContext;
NSCAssert(gOOJSMainThreadContext != NULL, @"Attempt to use JavaScript context before JavaScript engine is initialized.");
JS_BeginRequest(gOOJSMainThreadContext);
return gOOJSMainThreadContext;
}
// End a request on the main thread's context.
OOINLINE void OOJSRelinquishContext(JSContext *context)
{
#ifndef NDEBUG
extern JSContext *gOOJSMainThreadContext;
NSCParameterAssert(context == gOOJSMainThreadContext && JS_IsInRequest(context));
#endif
JS_EndRequest(context);
}
/* OOJSPropID
A temporary type to identify JavaScript object properties/methods. When
OO_NEW_JS is folded, it will be replaced with jsid.
OOJSID(const char *)
OOJSIDCX(context, const char *)
Macro to create a string-based ID. The string is interned and converted
into a string by a helper the first time the macro is hit, then cached.
The CX variant provides a context (with a request) to do the lookup in,
the non-CX variant acquires a context if necessary.
OOStringFromJSPropID(context, propID)
OOJSPropIDFromString(context, string)
Converters. The context parameter may be nil, in which case a temporary
context is acquired. If a context is specified, it must be in a request.
OOStringFromJSPropID(propID)
OOJSPropIDFromString(string)
Converters.
*/
#import "OOJSPropID.h"
#if OO_NEW_JS
#define OOJSIDCX(context, str) ({ static jsid idCache; static BOOL inited; if (EXPECT_NOT(!inited)) OOJSInitPropIDCachePRIVATE(context, str, &idCache, &inited); idCache; })
void OOJSInitPropIDCachePRIVATE(JSContext *context, const char *name, jsid *idCache, BOOL *inited);
#define OOJSID(str) ({ static jsid idCache; static BOOL inited; if (EXPECT_NOT(!inited)) OOJSInitPropIDCachePRIVATE(str, &idCache, &inited); idCache; })
void OOJSInitPropIDCachePRIVATE(const char *name, jsid *idCache, BOOL *inited);
#else
#define OOJSIDCX(context, str) (str)
#define OOJSID(str) (str)
#endif
#define OOJSID(str) OOJSIDCX(NULL, str)
NSString *OOStringFromJSPropID(JSContext *context, OOJSPropID propID);
OOJSPropID OOJSPropIDFromString(JSContext *context, NSString *string);
NSString *OOStringFromJSPropID(OOJSPropID propID);
OOJSPropID OOJSPropIDFromString(NSString *string);
/* Error and warning reporters.

View File

@ -98,6 +98,8 @@ MA 02110-1301, USA.
static OOJavaScriptEngine *sSharedEngine = nil;
static unsigned sErrorHandlerStackSkip = 0;
JSContext *gOOJSMainThreadContext = NULL;
#if OOJSENGINE_MONITOR_SUPPORT
@ -296,19 +298,19 @@ static void ReportJSError(JSContext *context, const char *message, JSErrorReport
OOJSTimeManagementInit(self, runtime);
// create a context and associate it with the JS run time
mainContext = JS_NewContext(runtime, OOJS_STACK_SIZE);
gOOJSMainThreadContext = JS_NewContext(runtime, OOJS_STACK_SIZE);
// if context creation failed, end the program here
if (mainContext == NULL)
if (gOOJSMainThreadContext == NULL)
{
OOLog(@"script.javaScript.init.error", @"***** FATAL ERROR: failed to create JavaScript context.");
exit(1);
}
JS_BeginRequest(mainContext);
JS_BeginRequest(gOOJSMainThreadContext);
JS_SetOptions(mainContext, OOJSENGINE_CONTEXT_OPTIONS);
JS_SetVersion(mainContext, OOJSENGINE_JSVERSION);
JS_SetOptions(gOOJSMainThreadContext, OOJSENGINE_CONTEXT_OPTIONS);
JS_SetVersion(gOOJSMainThreadContext, OOJSENGINE_JSVERSION);
#if JS_GC_ZEAL
uint8_t gcZeal = [[NSUserDefaults standardUserDefaults] oo_unsignedCharForKey:@"js-gc-zeal"];
@ -316,17 +318,17 @@ static void ReportJSError(JSContext *context, const char *message, JSErrorReport
{
// Useful js-gc-zeal values are 0 (off), 1 and 2.
OOLog(@"script.javaScript.debug.gcZeal", @"Setting JavaScript garbage collector zeal to %u.", gcZeal);
JS_SetGCZeal(mainContext, gcZeal);
JS_SetGCZeal(gOOJSMainThreadContext, gcZeal);
}
#endif
JS_SetErrorReporter(mainContext, ReportJSError);
JS_SetErrorReporter(gOOJSMainThreadContext, ReportJSError);
// Create the global object.
CreateOOJSGlobal(mainContext, &globalObject);
CreateOOJSGlobal(gOOJSMainThreadContext, &globalObject);
// Initialize the built-in JS objects and the global object.
JS_InitStandardClasses(mainContext, globalObject);
JS_InitStandardClasses(gOOJSMainThreadContext, globalObject);
if (![self lookUpStandardClassPointers])
{
OOLog(@"script.javaScript.init.error", @"***** FATAL ERROR: failed to look up standard JavaScript classes.");
@ -334,43 +336,43 @@ static void ReportJSError(JSContext *context, const char *message, JSErrorReport
}
[self registerStandardObjectConverters];
SetUpOOJSGlobal(mainContext, globalObject);
OOConstToJSStringInit(mainContext);
SetUpOOJSGlobal(gOOJSMainThreadContext, globalObject);
OOConstToJSStringInit(gOOJSMainThreadContext);
// Initialize Oolite classes.
InitOOJSMissionVariables(mainContext, globalObject);
InitOOJSMission(mainContext, globalObject);
InitOOJSOolite(mainContext, globalObject);
InitOOJSVector(mainContext, globalObject);
InitOOJSQuaternion(mainContext, globalObject);
InitOOJSSystem(mainContext, globalObject);
InitOOJSEntity(mainContext, globalObject);
InitOOJSShip(mainContext, globalObject);
InitOOJSStation(mainContext, globalObject);
InitOOJSPlayer(mainContext, globalObject);
InitOOJSPlayerShip(mainContext, globalObject);
InitOOJSManifest(mainContext, globalObject);
InitOOJSSun(mainContext, globalObject);
InitOOJSPlanet(mainContext, globalObject);
InitOOJSScript(mainContext, globalObject);
InitOOJSTimer(mainContext, globalObject);
InitOOJSClock(mainContext, globalObject);
InitOOJSWorldScripts(mainContext, globalObject);
InitOOJSSound(mainContext, globalObject);
InitOOJSSoundSource(mainContext, globalObject);
InitOOJSSpecialFunctions(mainContext, globalObject);
InitOOJSSystemInfo(mainContext, globalObject);
InitOOJSEquipmentInfo(mainContext, globalObject);
InitOOJSShipGroup(mainContext, globalObject);
InitOOJSFrameCallbacks(mainContext, globalObject);
InitOOJSFont(mainContext, globalObject);
InitOOJSMissionVariables(gOOJSMainThreadContext, globalObject);
InitOOJSMission(gOOJSMainThreadContext, globalObject);
InitOOJSOolite(gOOJSMainThreadContext, globalObject);
InitOOJSVector(gOOJSMainThreadContext, globalObject);
InitOOJSQuaternion(gOOJSMainThreadContext, globalObject);
InitOOJSSystem(gOOJSMainThreadContext, globalObject);
InitOOJSEntity(gOOJSMainThreadContext, globalObject);
InitOOJSShip(gOOJSMainThreadContext, globalObject);
InitOOJSStation(gOOJSMainThreadContext, globalObject);
InitOOJSPlayer(gOOJSMainThreadContext, globalObject);
InitOOJSPlayerShip(gOOJSMainThreadContext, globalObject);
InitOOJSManifest(gOOJSMainThreadContext, globalObject);
InitOOJSSun(gOOJSMainThreadContext, globalObject);
InitOOJSPlanet(gOOJSMainThreadContext, globalObject);
InitOOJSScript(gOOJSMainThreadContext, globalObject);
InitOOJSTimer(gOOJSMainThreadContext, globalObject);
InitOOJSClock(gOOJSMainThreadContext, globalObject);
InitOOJSWorldScripts(gOOJSMainThreadContext, globalObject);
InitOOJSSound(gOOJSMainThreadContext, globalObject);
InitOOJSSoundSource(gOOJSMainThreadContext, globalObject);
InitOOJSSpecialFunctions(gOOJSMainThreadContext, globalObject);
InitOOJSSystemInfo(gOOJSMainThreadContext, globalObject);
InitOOJSEquipmentInfo(gOOJSMainThreadContext, globalObject);
InitOOJSShipGroup(gOOJSMainThreadContext, globalObject);
InitOOJSFrameCallbacks(gOOJSMainThreadContext, globalObject);
InitOOJSFont(gOOJSMainThreadContext, globalObject);
// Run prefix scripts.
[OOJSScript jsScriptFromFileNamed:@"oolite-global-prefix.js"
properties:[NSDictionary dictionaryWithObject:JSSpecialFunctionsObjectWrapper(mainContext)
properties:[NSDictionary dictionaryWithObject:JSSpecialFunctionsObjectWrapper(gOOJSMainThreadContext)
forKey:@"special"]];
JS_EndRequest(mainContext);
JS_EndRequest(gOOJSMainThreadContext);
OOLog(@"script.javaScript.init.success", @"Set up JavaScript context.");
@ -380,15 +382,9 @@ static void ReportJSError(JSContext *context, const char *message, JSErrorReport
- (void) dealloc
{
unsigned i;
sSharedEngine = nil;
for (i = 0; i != contextPoolCount; ++i)
{
JS_DestroyContext(contextPool[i]);
}
JS_DestroyContext(mainContext);
JS_DestroyContext(gOOJSMainThreadContext);
JS_DestroyRuntime(runtime);
[super dealloc];
@ -412,112 +408,44 @@ static void ReportJSError(JSContext *context, const char *message, JSErrorReport
NSParameterAssert(OOJSValueIsFunction(context, function));
context = [self acquireContext];
context = OOJSAcquireContext();
OOJSStartTimeLimiter();
result = JS_CallFunctionValue(context, jsThis, function, argc, argv, outResult);
OOJSStopTimeLimiter();
JS_ReportPendingException(context);
[self releaseContext:context];
OOJSRelinquishContext(context);
return result;
}
- (JSContext *)acquireContext
{
JSContext *context = NULL;
if (!mainContextInUse)
{
/* Favour the main context.
There's overhead to using objects from a different context. By
having one preferred context, most objects will belong to that
context and that context will be the one used in the common case
of only one script running.
*/
mainContextInUse = YES;
context = mainContext;
JS_BeginRequest(context);
}
else if (contextPoolCount != 0)
{
context = contextPool[--contextPoolCount];
JS_BeginRequest(context);
}
else
{
OOLog(@"script.javaScript.context.create", @"Creating JS context.");
context = JS_NewContext(runtime, OOJS_STACK_SIZE);
// if context creation failed, end the program here
if (context == NULL)
{
OOLog(@"script.javaScript.error", @"***** FATAL ERROR: failed to create JavaScript context.");
exit(1);
}
JS_BeginRequest(context); // Explicitly not balanced.
JS_SetOptions(context, OOJSENGINE_CONTEXT_OPTIONS);
JS_SetVersion(context, OOJSENGINE_JSVERSION);
JS_SetErrorReporter(context, ReportJSError);
JS_SetGlobalObject(context, globalObject);
}
return context;
}
- (void)releaseContext:(JSContext *)context
{
if (context == NULL) return;
NSParameterAssert(JS_IsInRequest(context));
JS_EndRequest(context);
if (context == mainContext)
{
mainContextInUse = NO;
}
else if (contextPoolCount < kOOJavaScriptEngineContextPoolCount)
{
contextPool[contextPoolCount++] = context;
}
else
{
OOLog(@"script.javaScript.context.destroy", @"Destroying JS context.");
JS_DestroyContextMaybeGC(context);
}
}
- (void) removeGCObjectRoot:(JSObject **)rootPtr
{
JSContext *context = [self acquireContext];
JSContext *context = OOJSAcquireContext();
JS_RemoveObjectRoot(context, rootPtr);
[self releaseContext:context];
OOJSRelinquishContext(context);
}
- (void) removeGCValueRoot:(jsval *)rootPtr
{
JSContext *context = [self acquireContext];
JSContext *context = OOJSAcquireContext();
JS_RemoveValueRoot(context, rootPtr);
[self releaseContext:context];
OOJSRelinquishContext(context);
}
- (void) garbageCollectionOpportunity
{
JSContext *context = [self acquireContext];
JSContext *context = OOJSAcquireContext();
#ifndef NDEBUG
JS_GC(context);
#else
JS_MaybeGC(context);
#endif
[self releaseContext:context];
OOJSRelinquishContext(context);
}
@ -567,22 +495,22 @@ static void ReportJSError(JSContext *context, const char *message, JSErrorReport
{
JSObject *templateObject = NULL;
templateObject = JS_NewObject(mainContext, NULL, NULL, NULL);
templateObject = JS_NewObject(gOOJSMainThreadContext, NULL, NULL, NULL);
if (EXPECT_NOT(templateObject == NULL)) return NO;
_objectClass = OOJSGetClass(mainContext, templateObject);
_objectClass = OOJSGetClass(gOOJSMainThreadContext, templateObject);
if (EXPECT_NOT(!JS_ValueToObject(mainContext, JS_GetEmptyStringValue(mainContext), &templateObject))) return NO;
_stringClass = OOJSGetClass(mainContext, templateObject);
if (EXPECT_NOT(!JS_ValueToObject(gOOJSMainThreadContext, JS_GetEmptyStringValue(gOOJSMainThreadContext), &templateObject))) return NO;
_stringClass = OOJSGetClass(gOOJSMainThreadContext, templateObject);
templateObject = JS_NewArrayObject(mainContext, 0, NULL);
templateObject = JS_NewArrayObject(gOOJSMainThreadContext, 0, NULL);
if (EXPECT_NOT(templateObject == NULL)) return NO;
_arrayClass = OOJSGetClass(mainContext, templateObject);
_arrayClass = OOJSGetClass(gOOJSMainThreadContext, templateObject);
if (EXPECT_NOT(!JS_ValueToObject(mainContext, INT_TO_JSVAL(0), &templateObject))) return NO;
_numberClass = OOJSGetClass(mainContext, templateObject);
if (EXPECT_NOT(!JS_ValueToObject(gOOJSMainThreadContext, INT_TO_JSVAL(0), &templateObject))) return NO;
_numberClass = OOJSGetClass(gOOJSMainThreadContext, templateObject);
if (EXPECT_NOT(!JS_ValueToObject(mainContext, JSVAL_FALSE, &templateObject))) return NO;
_booleanClass = OOJSGetClass(mainContext, templateObject);
if (EXPECT_NOT(!JS_ValueToObject(gOOJSMainThreadContext, JSVAL_FALSE, &templateObject))) return NO;
_booleanClass = OOJSGetClass(gOOJSMainThreadContext, templateObject);
return YES;
}
@ -902,17 +830,11 @@ void OOJSMarkConsoleEvalLocation(JSContext *context, JSStackFrame *stackFrame)
#if OO_NEW_JS
void OOJSInitPropIDCachePRIVATE(JSContext *context, const char *name, jsid *idCache, BOOL *inited)
void OOJSInitPropIDCachePRIVATE(const char *name, jsid *idCache, BOOL *inited)
{
NSCParameterAssert(context == NULL || JS_IsInRequest(context));
NSCParameterAssert(name != NULL && idCache != NULL && inited != NULL && !*inited);
OOJavaScriptEngine *jsEngIfTempContext = nil;
if (context == NULL)
{
jsEngIfTempContext = [OOJavaScriptEngine sharedEngine];
context = [jsEngIfTempContext acquireContext];
}
JSContext *context = OOJSAcquireContext();
JSString *string = JS_InternString(context, name);
if (EXPECT_NOT(string == NULL))
@ -923,23 +845,15 @@ void OOJSInitPropIDCachePRIVATE(JSContext *context, const char *name, jsid *idCa
*idCache = INTERNED_STRING_TO_JSID(string);
*inited = YES;
if (jsEngIfTempContext != nil)
{
[jsEngIfTempContext releaseContext:context];
}
OOJSRelinquishContext(context);
}
OOJSPropID OOJSPropIDFromString(JSContext *context, NSString *string)
OOJSPropID OOJSPropIDFromString(NSString *string)
{
NSCParameterAssert((context == NULL || JS_IsInRequest(context)) && string != nil);
if (EXPECT_NOT(string == nil)) return JSID_VOID;
OOJavaScriptEngine *jsEngIfTempContext = nil;
if (context == NULL)
{
jsEngIfTempContext = [OOJavaScriptEngine sharedEngine];
context = [jsEngIfTempContext acquireContext];
}
JSContext *context = OOJSAcquireContext();
enum { kStackBufSize = 1024 };
unichar stackBuf[kStackBufSize];
@ -961,25 +875,15 @@ OOJSPropID OOJSPropIDFromString(JSContext *context, NSString *string)
if (EXPECT_NOT(buffer != stackBuf)) free(buffer);
if (jsEngIfTempContext != nil)
{
[jsEngIfTempContext releaseContext:context];
}
OOJSRelinquishContext(context);
return INTERNED_STRING_TO_JSID(jsString);
}
NSString *OOStringFromJSPropID(JSContext *context, OOJSPropID propID)
NSString *OOStringFromJSPropID(OOJSPropID propID)
{
NSCParameterAssert(context == NULL || JS_IsInRequest(context));
OOJavaScriptEngine *jsEngIfTempContext = nil;
if (context == NULL)
{
jsEngIfTempContext = [OOJavaScriptEngine sharedEngine];
context = [jsEngIfTempContext acquireContext];
}
JSContext *context = OOJSAcquireContext();
jsval value;
NSString *result = nil;
@ -988,21 +892,20 @@ NSString *OOStringFromJSPropID(JSContext *context, OOJSPropID propID)
result = OOStringFromJSString(context, JS_ValueToString(context, value));
}
if (jsEngIfTempContext != nil)
{
[jsEngIfTempContext releaseContext:context];
}
OOJSRelinquishContext(context);
return result;
}
#else
OOJSPropID OOJSPropIDFromString(JSContext *context, NSString *string)
OOJSPropID OOJSPropIDFromString(NSString *string)
{
if (EXPECT_NOT(string == nil)) return NULL;
return [string UTF8String];
}
NSString *OOStringFromJSPropID(JSContext *context, OOJSPropID propID)
NSString *OOStringFromJSPropID(OOJSPropID propID)
{
return [NSString stringWithUTF8String:propID];
}
@ -1291,7 +1194,7 @@ static JSObject *JSObjectFromNSDictionary(JSContext *context, NSDictionary *dict
value = [[dictionary objectForKey:key] oo_jsValueInContext:context];
if (!JSVAL_IS_VOID(value))
{
OK = OOJSSetProperty(context, result, OOJSPropIDFromString(context, key), &value);
OK = OOJSSetProperty(context, result, OOJSPropIDFromString(key), &value);
if (EXPECT_NOT(!OK)) break;
}
}
@ -1442,14 +1345,14 @@ static BOOL JSNewNSDictionaryValue(JSContext *context, NSDictionary *dictionary,
BOOL tempCtxt = NO;
if (context == NULL)
{
context = [[OOJavaScriptEngine sharedEngine] acquireContext];
context = OOJSAcquireContext();
tempCtxt = YES;
}
_val = value;
JS_AddNamedValueRoot(context, &_val, "OOJSValue");
if (tempCtxt) [[OOJavaScriptEngine sharedEngine] releaseContext:context];
if (tempCtxt) OOJSRelinquishContext(context);
}
return self;
@ -1465,9 +1368,9 @@ static BOOL JSNewNSDictionaryValue(JSContext *context, NSDictionary *dictionary,
- (void) dealloc
{
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JSContext *context = OOJSAcquireContext();
JS_RemoveValueRoot(context, &_val);
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
OOJSRelinquishContext(context);
[super dealloc];
}