Work on using jsids instead of strings to identify methods and properties, starting with the simple cases.

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@4131 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2011-01-23 20:43:56 +00:00
parent 0aba4b0971
commit b636e923ce
9 changed files with 170 additions and 167 deletions

View File

@ -9161,7 +9161,7 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
{
args[0] = INT_TO_JSVAL(i);
OOJSStartTimeLimiter();
OK = [script callMethodNamed:"coordinatesForEscortPosition"
OK = [script callMethodNamed:OOJS_PROPID(context, "coordinatesForEscortPosition")
withArguments:args count:sizeof args / sizeof *args
inContext:context
gettingResult:&result];

View File

@ -722,7 +722,7 @@ NSString *OOStringFromDeciCredits(OOCreditsQuantity tenthsOfCredits, BOOL includ
NSString *result = @"<error>";
JS_BeginRequest(context);
if (JS_GetMethod(context, global, "formatCredits", &fakeRoot, &method))
if (OOJSGetMethod(context, global, OOJS_PROPID(context, "formatCredits"), &fakeRoot, &method))
{
jsval args[3];
if (JS_NewDoubleValue(context, tenthsOfCredits * 0.1, &args[0]))

View File

@ -68,6 +68,12 @@ OOINLINE const jschar *OOJSGetStringCharsAndLength(JSContext *context, JSString
#define OOJSVAL_TO_DOUBLE JSVAL_TO_DOUBLE
#define OOJSGetMethod JS_GetMethodById
#define OOJSGetProperty JS_GetPropertyById
#define OOJSSetProperty JS_SetPropertyById
#define OOJSDefineProperty JS_DefinePropertyById
#else // !OO_NEW_JS
// In old API, jsvals could be pointers to doubles; in new, they're actual doubles.
@ -85,6 +91,19 @@ OOINLINE const jschar *OOJSGetStringCharsAndLength(JSContext *context, JSString
}
#define OOJS_FF4B9 0
#define OOJSGetMethod JS_GetMethod
#define OOJSGetProperty JS_GetProperty
#define OOJSSetProperty JS_SetProperty
#define OOJSDefineProperty JS_DefineProperty
OOINLINE BOOL OOJSGetProperty(JSContext *context, JSObject *object, OOJSPropID propID, jsval *value)
{
return JS_GetPropertyById(context, object, propID, value);
}
#endif

View File

@ -57,14 +57,22 @@ MA 02110-1301, USA.
/* Low-level interface to call a JavaScript method.
Requires a request on context.
FIXME: should take a jsid instead of string for name, but can't be done cleanly without requiring OO_NEW_JS.
*/
- (BOOL) callMethodNamed:(const char *)methodName
- (BOOL) callMethodNamed:(OOJSPropID)methodID
withArguments:(jsval *)argv count:(intN)argc
inContext:(JSContext *)context
gettingResult:(jsval *)outResult;
- (id) propertyWithID:(OOJSPropID)propID inContext:(JSContext *)context;
// Set a property which can be modified or deleted by the script.
- (BOOL) setProperty:(id)value withID:(OOJSPropID)propID inContext:(JSContext *)context;
// Set a special property which cannot be modified or deleted by the script.
- (BOOL) defineProperty:(id)value withID:(OOJSPropID)propID inContext:(JSContext *)context;
- (id) propertyNamed:(NSString *)name;
- (BOOL) setProperty:(id)value named:(NSString *)name;
- (BOOL) defineProperty:(id)value named:(NSString *)name;
@end

View File

@ -183,7 +183,8 @@ 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.
*/
[self setProperty:[self scriptNameFromPath:path] named:@"name"];
OOJSPropID nameID = OOJS_PROPID(context, "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)
if (!problem)
@ -208,15 +209,15 @@ static JSFunctionSpec sScriptMethods[] =
{
// Get display attributes from script
DESTROY(name);
name = [StrippedName([[self propertyNamed:@"name"] description]) copy];
name = [StrippedName([[self propertyWithID:nameID inContext:context] description]) copy];
if (name == nil)
{
name = [[self scriptNameFromPath:path] retain];
[self setProperty:name named:@"name"];
[self setProperty:name withID:nameID inContext:context];
}
version = [[[self propertyNamed:@"version"] description] copy];
description = [[[self propertyNamed:@"description"] description] copy];
version = [[[self propertyWithID:OOJS_PROPID(context, "version") inContext:context] description] copy];
description = [[[self propertyWithID:OOJS_PROPID(context, "description") inContext:context] description] copy];
OOLog(@"script.javaScript.load.success", @"Loaded JavaScript OXP: %@ -- %@", [self displayName], description ? description : (NSString *)@"(no description)");
}
@ -421,7 +422,7 @@ static JSFunctionSpec sScriptMethods[] =
}
- (BOOL) callMethodNamed:(const char *)methodName
- (BOOL) callMethodNamed:(OOJSPropID)methodID
withArguments:(jsval *)argv count:(intN)argc
inContext:(JSContext *)context
gettingResult:(jsval *)outResult
@ -431,10 +432,10 @@ static JSFunctionSpec sScriptMethods[] =
BOOL OK = NO;
JSObject *fakeRoot = NULL;
jsval method;
if (EXPECT(JS_GetMethod(context, _jsSelf, methodName, &fakeRoot, &method) && !JSVAL_IS_VOID(method)))
if (EXPECT(OOJSGetMethod(context, _jsSelf, methodID, &fakeRoot, &method) && !JSVAL_IS_VOID(method)))
{
#ifndef NDEBUG
OOLog(@"script.trace.javaScript.callback", @"Calling [%@].%s()", [self name], methodName);
OOLog(@"script.trace.javaScript.callback", @"Calling [%@].%@()", [self name], OOStringFromJSPropertyID(context, methodID, NULL));
OOLogIndentIf(@"script.trace.javaScript.callback");
#endif
@ -463,57 +464,78 @@ static JSFunctionSpec sScriptMethods[] =
}
- (id)propertyNamed:(NSString *)propName
- (id) propertyWithID:(OOJSPropID)propID inContext:(JSContext *)context
{
BOOL OK;
jsval value = JSVAL_VOID;
JSContext *context = NULL;
id result = nil;
NSParameterAssert(context != NULL && JS_IsInRequest(context));
jsval jsValue = JSVAL_VOID;
if (OOJSGetProperty(context, _jsSelf, propID, &jsValue))
{
return OOJSNativeObjectFromJSValue(context, jsValue);
}
return nil;
}
- (BOOL) setProperty:(id)value withID:(OOJSPropID)propID inContext:(JSContext *)context
{
NSParameterAssert(context != NULL && JS_IsInRequest(context));
jsval jsValue = OOJSValueFromNativeObject(context, value);
return OOJSSetProperty(context, _jsSelf, propID, &jsValue);
}
- (BOOL) defineProperty:(id)value withID:(OOJSPropID)propID inContext:(JSContext *)context
{
NSParameterAssert(context != NULL && JS_IsInRequest(context));
jsval jsValue = OOJSValueFromNativeObject(context, value);
return OOJSDefineProperty(context, _jsSelf, propID, jsValue, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
}
- (id) propertyNamed:(NSString *)propName
{
if (propName == nil) return nil;
context = [[OOJavaScriptEngine sharedEngine] acquireContext];
OK = OOJSGetProperty(context, _jsSelf, propName, &value);
if (OK && !JSVAL_IS_VOID(value)) result = OOJSNativeObjectFromJSValue(context, value);
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JS_BeginRequest(context);
id result = [self propertyWithID:OOJSPropIDFromString(context, propName) inContext:context];
JS_EndRequest(context);
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
return result;
}
- (BOOL)setProperty:(id)value named:(NSString *)propName
- (BOOL) setProperty:(id)value named:(NSString *)propName
{
jsval jsValue;
JSContext *context = NULL;
BOOL result = NO;
if (value == nil || propName == nil) return NO;
context = [[OOJavaScriptEngine sharedEngine] acquireContext];
jsValue = [value oo_jsValueInContext:context];
if (!JSVAL_IS_VOID(jsValue))
{
result = OOJSDefineProperty(context, _jsSelf, propName, jsValue, NULL, NULL, JSPROP_ENUMERATE);
}
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JS_BeginRequest(context);
BOOL result = [self setProperty:value withID:OOJSPropIDFromString(context, propName) inContext:context];
JS_EndRequest(context);
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
return result;
}
- (BOOL)defineProperty:(id)value named:(NSString *)propName
- (BOOL) defineProperty:(id)value named:(NSString *)propName
{
jsval jsValue;
JSContext *context = NULL;
BOOL result = NO;
if (value == nil || propName == nil) return NO;
context = [[OOJavaScriptEngine sharedEngine] acquireContext];
jsValue = [value oo_jsValueInContext:context];
if (!JSVAL_IS_VOID(jsValue))
{
result = OOJSDefineProperty(context, _jsSelf, propName, jsValue, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
}
JSContext *context = [[OOJavaScriptEngine sharedEngine] acquireContext];
JS_BeginRequest(context);
BOOL result = [self defineProperty:value withID:OOJSPropIDFromString(context, propName) inContext:context];
JS_EndRequest(context);
[[OOJavaScriptEngine sharedEngine] releaseContext:context];
return result;
}

View File

@ -122,6 +122,25 @@ enum
@end
/* OOJSPropID
A temporary type to identify JavaScript object properties/methods. When
OO_NEW_JS is folded, it will be replaced with jsid.
OOJS_PROPID(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.
*/
#if OO_NEW_JS
typedef jsid OOJSPropID;
#define OOJS_PROPID(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);
#else
typedef const char *OOJSPropID;
#define OOJS_PROPID(context, str) (str)
#endif
OOJSPropID OOJSPropIDFromString(JSContext *context, NSString *string);
/* Error and warning reporters.
Note that after reporting an error in a JavaScript callback, the caller
@ -173,18 +192,6 @@ OOINLINE jsval OOJSValueFromBOOL(int b)
}
/* OOJSFooProperty()
Wrappers to corresponding JS_FooProperty()/JS_FooUCProperty() functions,
but taking an NSString.
Require a request on context.
*/
BOOL OOJSGetProperty(JSContext *context, JSObject *object, NSString *name, jsval *value);
BOOL OOJSSetProperty(JSContext *context, JSObject *object, NSString *name, jsval *value);
BOOL OOJSDefineProperty(JSContext *context, JSObject *object, NSString *name, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs);
@interface NSObject (OOJavaScript)
/* -oo_jsValueInContext:

View File

@ -900,7 +900,57 @@ void OOJSMarkConsoleEvalLocation(JSContext *context, JSStackFrame *stackFrame)
{
GetLocationNameAndLine(context, stackFrame, &sConsoleScriptName, &sConsoleEvalLineNo);
}
#endif
#if OO_NEW_JS
void OOJSInitPropIDCachePRIVATE(JSContext *context, const char *name, jsid *idCache, BOOL *inited)
{
NSCParameterAssert(context != NULL && JS_IsInRequest(context));
NSCParameterAssert(name != NULL && idCache != NULL && inited != NULL && !*inited);
JSString *string = JS_InternString(context, name);
if (EXPECT_NOT(string == NULL))
{
[NSException raise:NSGenericException format:@"Failed to initialize JS ID cache for \"%s\".", name];
}
*idCache = INTERNED_STRING_TO_JSID(string);
*inited = YES;
}
OOJSPropID OOJSPropIDFromString(JSContext *context, NSString *string)
{
NSCParameterAssert(context != NULL && JS_IsInRequest(context) && string != nil);
enum { kStackBufSize = 1024 };
unichar stackBuf[kStackBufSize];
unichar *buffer;
size_t length = [string length];
if (length < kStackBufSize)
{
buffer = stackBuf;
}
else
{
buffer = malloc(sizeof (unichar) * length);
if (EXPECT_NOT(buffer == NULL)) return JSID_VOID;
}
[string getCharacters:buffer];
JSString *jsString = JS_InternUCStringN(context, buffer, length);
if (EXPECT_NOT(jsString == NULL)) return JSID_VOID;
if (EXPECT_NOT(buffer != stackBuf)) free(buffer);
return INTERNED_STRING_TO_JSID(jsString);
}
#else
OOJSPropID OOJSPropIDFromString(JSContext *context, NSString *string)
{
return [string UTF8String];
}
#endif
@ -1090,92 +1140,6 @@ BOOL OOJSArgumentListGetNumberNoError(JSContext *context, uintN argc, jsval *arg
}
static BOOL ExtractString(NSString *string, jschar **outString, size_t *outLength)
{
OOJS_PROFILE_ENTER
assert(outString != NULL && outLength != NULL);
assert(sizeof (unichar) == sizeof (jschar)); // Should both be 16 bits
*outLength = [string length];
if (*outLength == 0) return NO; // nil/empty strings not accepted.
*outString = malloc(sizeof (unichar) * *outLength);
if (*outString == NULL) return NO;
[string getCharacters:(unichar *)*outString];
return YES;
OOJS_PROFILE_EXIT
}
BOOL OOJSGetProperty(JSContext *context, JSObject *object, NSString *name, jsval *value)
{
OOJS_PROFILE_ENTER
jschar *buffer = NULL;
size_t length;
BOOL OK = NO;
NSCParameterAssert(context != NULL && name != nil);
if (ExtractString(name, &buffer, &length))
{
OK = JS_GetUCProperty(context, object, buffer, length, value);
free(buffer);
}
return OK;
OOJS_PROFILE_EXIT
}
BOOL OOJSSetProperty(JSContext *context, JSObject *object, NSString *name, jsval *value)
{
OOJS_PROFILE_ENTER
jschar *buffer = NULL;
size_t length;
BOOL OK = NO;
NSCParameterAssert(context != NULL && name != nil);
if (ExtractString(name, &buffer, &length))
{
OK = JS_SetUCProperty(context, object, buffer, length, value);
free(buffer);
}
return OK;
OOJS_PROFILE_EXIT
}
BOOL OOJSDefineProperty(JSContext *context, JSObject *object, NSString *name, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
{
OOJS_PROFILE_ENTER
jschar *buffer = NULL;
size_t length;
BOOL OK = NO;
NSCParameterAssert(context != NULL && name != nil);
if (ExtractString(name, &buffer, &length))
{
OK = JS_DefineUCProperty(context, object, buffer, length, value, getter, setter, attrs);
free(buffer);
}
return OK;
OOJS_PROFILE_EXIT
}
static JSObject *JSArrayFromNSArray(JSContext *context, NSArray *array)
{
OOJS_PROFILE_ENTER
@ -1272,7 +1236,7 @@ static JSObject *JSObjectFromNSDictionary(JSContext *context, NSDictionary *dict
value = [[dictionary objectForKey:key] oo_jsValueInContext:context];
if (!JSVAL_IS_VOID(value))
{
OK = OOJSSetProperty(context, result, key, &value);
OK = OOJSSetProperty(context, result, OOJSPropIDFromString(context, key), &value);
if (EXPECT_NOT(!OK)) break;
}
}
@ -1536,7 +1500,14 @@ NSString *OOStringFromJSPropertyID(JSContext *context, jsval propID, JSPropertyS
}
}
return @"<unknown>";
jsval value;
#if OO_NEW_JS
if (!JS_IdToValue(context, propID, &value)) return @"unknown";
#else
value = propID;
#endif
return OOStringFromJSString(context, JS_ValueToString(context, value));
}

View File

@ -67,10 +67,4 @@ MA 02110-1301, USA.
- (BOOL)doEvent:(NSString *)eventName withArguments:(NSArray *)arguments;
- (BOOL)doEvent:(NSString *)eventName withArgument:(id)argument;
- (id)propertyNamed:(NSString *)name;
// Set a property which can be modified or deleted by the script.
- (BOOL)setProperty:(id)value named:(NSString *)name;
// Set a special property which cannot be modified or deleted by the script.
- (BOOL)defineProperty:(id)value named:(NSString *)name;
@end

View File

@ -280,22 +280,4 @@ static NSString * const kOOLogLoadScriptNone = @"script.load.none";
return [self doEvent:eventName withArguments:[NSArray arrayWithObject:argument]];
}
- (id)propertyNamed:(NSString *)name
{
return nil;
}
- (BOOL)setProperty:(id)value named:(NSString *)name
{
return NO;
}
- (BOOL)defineProperty:(id)value named:(NSString *)name
{
return NO;
}
@end