mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-03 02:25:34 +00:00
Generic static method automation to simplify things for callers of generic prototype methods (304828, r=mrbkap, sr=shaver).
This commit is contained in:
parent
fd98f06afb
commit
48765162d8
@ -3283,15 +3283,82 @@ JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
|
||||
return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSBool)
|
||||
js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
|
||||
uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
jsval fsv;
|
||||
JSFunctionSpec *fs;
|
||||
JSObject *tmp;
|
||||
|
||||
if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
|
||||
return JS_FALSE;
|
||||
fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
|
||||
|
||||
if (argc == 0) {
|
||||
/*
|
||||
* Follow Function.prototype.apply and .call by using the global
|
||||
* object as the 'this' param if no args. We know argv[0] is valid
|
||||
* because JS_DefineFunctions, below, defined us as requiring at
|
||||
* least one argument (it passes fs->nargs + 1 as the penultimate
|
||||
* argument to JS_DefineFunction).
|
||||
*/
|
||||
while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
|
||||
obj = tmp;
|
||||
argv[0] = OBJECT_TO_JSVAL(obj);
|
||||
argc = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy all actual (argc) and required but missing (fs->nargs + 1 - argc)
|
||||
* args down over our |this| parameter, argv[-1], which is almost always
|
||||
* the class constructor object, e.g. Array. Then call the corresponding
|
||||
* prototype native method with our first argument passed as |this|.
|
||||
*/
|
||||
memmove(argv - 1, argv, (fs->nargs + 1) * sizeof(jsval));
|
||||
return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc - 1, argv, rval);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
|
||||
{
|
||||
uintN flags;
|
||||
JSObject *ctor;
|
||||
JSFunction *fun;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
ctor = NULL;
|
||||
for (; fs->name; fs++) {
|
||||
fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs,
|
||||
fs->flags);
|
||||
flags = fs->flags;
|
||||
|
||||
/*
|
||||
* Define a generic arity N+1 static method for the arity N prototype
|
||||
* method if flags contains JSFUN_GENERIC_NATIVE.
|
||||
*/
|
||||
if (flags & JSFUN_GENERIC_NATIVE) {
|
||||
if (!ctor) {
|
||||
ctor = JS_GetConstructor(cx, obj);
|
||||
if (!ctor)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
flags &= ~JSFUN_GENERIC_NATIVE;
|
||||
fun = JS_DefineFunction(cx, ctor, fs->name,
|
||||
js_generic_native_method_dispatcher,
|
||||
fs->nargs + 1, flags);
|
||||
if (!fun)
|
||||
return JS_FALSE;
|
||||
fun->extra = fs->extra;
|
||||
|
||||
/*
|
||||
* As jsapi.h notes, fs must point to storage that lives as long
|
||||
* as fun->object lives.
|
||||
*/
|
||||
if (!JS_SetReservedSlot(cx, fun->object, 0, PRIVATE_TO_JSVAL(fs)))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
|
||||
if (!fun)
|
||||
return JS_FALSE;
|
||||
fun->extra = fs->extra;
|
||||
|
@ -134,6 +134,19 @@ JS_BEGIN_EXTERN_C
|
||||
#define JSFUN_HEAVYWEIGHT 0x80 /* activation requires a Call object */
|
||||
#define JSFUN_FLAGS_MASK 0xf8 /* overlay JSFUN_* attributes */
|
||||
|
||||
/*
|
||||
* Re-use JSFUN_LAMBDA, which applies only to scripted functions, for use in
|
||||
* JSFunctionSpec arrays that specify generic native prototype methods, i.e.,
|
||||
* methods of a class prototype that are exposed as static methods taking an
|
||||
* extra leading argument: the generic |this| parameter.
|
||||
*
|
||||
* If you set this flag in a JSFunctionSpec struct's flags initializer, then
|
||||
* that struct must live at least as long as the native static method object
|
||||
* created due to this flag by JS_DefineFunctions or JS_InitClass. Typically
|
||||
* JSFunctionSpec structs are allocated in static arrays.
|
||||
*/
|
||||
#define JSFUN_GENERIC_NATIVE JSFUN_LAMBDA
|
||||
|
||||
/*
|
||||
* Well-known JS values. The extern'd variables are initialized when the
|
||||
* first JSContext is created by JS_NewContext (see below).
|
||||
|
@ -1718,32 +1718,32 @@ static JSFunctionSpec array_methods[] = {
|
||||
|
||||
/* Perl-ish methods. */
|
||||
#if JS_HAS_SOME_PERL_FUN
|
||||
{"join", array_join, 1,0,0},
|
||||
{"reverse", array_reverse, 0,0,0},
|
||||
{"sort", array_sort, 1,0,0},
|
||||
{"join", array_join, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{"sort", array_sort, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
#endif
|
||||
#if JS_HAS_MORE_PERL_FUN
|
||||
{"push", array_push, 1,0,0},
|
||||
{"pop", array_pop, 0,0,0},
|
||||
{"shift", array_shift, 0,0,0},
|
||||
{"unshift", array_unshift, 1,0,0},
|
||||
{"splice", array_splice, 2,0,0},
|
||||
{"push", array_push, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"pop", array_pop, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{"shift", array_shift, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{"unshift", array_unshift, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"splice", array_splice, 2,JSFUN_GENERIC_NATIVE,0},
|
||||
#endif
|
||||
|
||||
/* Python-esque sequence methods. */
|
||||
#if JS_HAS_SEQUENCE_OPS
|
||||
{"concat", array_concat, 1,0,0},
|
||||
{"slice", array_slice, 2,0,0},
|
||||
{"concat", array_concat, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"slice", array_slice, 2,JSFUN_GENERIC_NATIVE,0},
|
||||
#endif
|
||||
|
||||
#if JS_HAS_ARRAY_EXTRAS
|
||||
{"indexOf", array_indexOf, 1,0,0},
|
||||
{"lastIndexOf", array_lastIndexOf, 1,0,0},
|
||||
{"forEach", array_forEach, 1,0,0},
|
||||
{"map", array_map, 1,0,0},
|
||||
{"filter", array_filter, 1,0,0},
|
||||
{"some", array_some, 1,0,0},
|
||||
{"every", array_every, 1,0,0},
|
||||
{"indexOf", array_indexOf, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"lastIndexOf", array_lastIndexOf, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"forEach", array_forEach, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"map", array_map, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"filter", array_filter, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"some", array_some, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"every", array_every, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
#endif
|
||||
|
||||
{0,0,0,0,0}
|
||||
|
@ -2288,39 +2288,39 @@ str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
|
||||
static JSFunctionSpec string_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
{"quote", str_quote, 0,0,0},
|
||||
{"quote", str_quote, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{js_toSource_str, str_toSource, 0,0,0},
|
||||
#endif
|
||||
|
||||
/* Java-like methods. */
|
||||
{js_toString_str, str_toString, 0,0,0},
|
||||
{js_valueOf_str, str_valueOf, 0,0,0},
|
||||
{"substring", str_substring, 2,0,0},
|
||||
{"toLowerCase", str_toLowerCase, 0,0,0},
|
||||
{"toUpperCase", str_toUpperCase, 0,0,0},
|
||||
{"charAt", str_charAt, 1,0,0},
|
||||
{"charCodeAt", str_charCodeAt, 1,0,0},
|
||||
{"indexOf", str_indexOf, 1,0,0},
|
||||
{"lastIndexOf", str_lastIndexOf, 1,0,0},
|
||||
{"toLocaleLowerCase", str_toLocaleLowerCase, 0,0,0},
|
||||
{"toLocaleUpperCase", str_toLocaleUpperCase, 0,0,0},
|
||||
{"localeCompare", str_localeCompare, 1,0,0},
|
||||
{"substring", str_substring, 2,JSFUN_GENERIC_NATIVE,0},
|
||||
{"toLowerCase", str_toLowerCase, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{"toUpperCase", str_toUpperCase, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{"charAt", str_charAt, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"charCodeAt", str_charCodeAt, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"indexOf", str_indexOf, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"lastIndexOf", str_lastIndexOf, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"toLocaleLowerCase", str_toLocaleLowerCase, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{"toLocaleUpperCase", str_toLocaleUpperCase, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{"localeCompare", str_localeCompare, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
|
||||
/* Perl-ish methods (search is actually Python-esque). */
|
||||
#if JS_HAS_REGEXPS
|
||||
{"match", str_match, 1,0,2},
|
||||
{"search", str_search, 1,0,0},
|
||||
{"replace", str_replace, 2,0,0},
|
||||
{"split", str_split, 2,0,0},
|
||||
{"match", str_match, 1,JSFUN_GENERIC_NATIVE,2},
|
||||
{"search", str_search, 1,JSFUN_GENERIC_NATIVE,0},
|
||||
{"replace", str_replace, 2,JSFUN_GENERIC_NATIVE,0},
|
||||
{"split", str_split, 2,JSFUN_GENERIC_NATIVE,0},
|
||||
#endif
|
||||
#if JS_HAS_PERL_SUBSTR
|
||||
{"substr", str_substr, 2,0,0},
|
||||
{"substr", str_substr, 2,JSFUN_GENERIC_NATIVE,0},
|
||||
#endif
|
||||
|
||||
/* Python-esque sequence methods. */
|
||||
#if JS_HAS_SEQUENCE_OPS
|
||||
{"concat", str_concat, 0,0,0},
|
||||
{"slice", str_slice, 0,0,0},
|
||||
{"concat", str_concat, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
{"slice", str_slice, 0,JSFUN_GENERIC_NATIVE,0},
|
||||
#endif
|
||||
|
||||
/* HTML string methods. */
|
||||
|
Loading…
Reference in New Issue
Block a user