From b1bdae2e35cad1fff73ffc7e464211700dcd87e5 Mon Sep 17 00:00:00 2001 From: "brendan%mozilla.org" Date: Wed, 11 Jan 2006 01:14:40 +0000 Subject: [PATCH] Fix for bug 320119, a=schrep. git-svn-id: svn://10.0.0.236/branches/MOZILLA_1_8_0_BRANCH@187294 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/src/jsfun.c | 56 +++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/mozilla/js/src/jsfun.c b/mozilla/js/src/jsfun.c index 01ad3a4c685..625dc7ec5be 100644 --- a/mozilla/js/src/jsfun.c +++ b/mozilla/js/src/jsfun.c @@ -893,15 +893,25 @@ JSClass js_CallClass = { #endif /* JS_HAS_CALL_OBJECT */ -/* SHARED because fun_getProperty always computes a new value. */ -#define FUNCTION_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED) +/* + * ECMA-262 specifies that length is a property of function object instances, + * but we can avoid that space cost by delegating to a prototype property that + * is JSPROP_PERMANENT and JSPROP_SHARED. Each fun_getProperty call computes + * a fresh length value based on the arity of the individual function object's + * private data. + * + * The extensions below other than length, i.e., the ones not in ECMA-262, + * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility + * with ECMA we must allow a delegating object to override them. + */ +#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED) static JSPropertySpec function_props[] = { - {js_arguments_str, CALL_ARGUMENTS, FUNCTION_PROP_ATTRS,0,0}, - {js_arity_str, FUN_ARITY, FUNCTION_PROP_ATTRS,0,0}, - {js_length_str, ARGS_LENGTH, FUNCTION_PROP_ATTRS,0,0}, - {js_name_str, FUN_NAME, FUNCTION_PROP_ATTRS,0,0}, - {js_caller_str, FUN_CALLER, FUNCTION_PROP_ATTRS,0,0}, + {js_arguments_str, CALL_ARGUMENTS, JSPROP_PERMANENT, 0,0}, + {js_arity_str, FUN_ARITY, JSPROP_PERMANENT, 0,0}, + {js_caller_str, FUN_CALLER, JSPROP_PERMANENT, 0,0}, + {js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, 0,0}, + {js_name_str, FUN_NAME, JSPROP_PERMANENT, 0,0}, {0,0,0,0,0} }; @@ -916,10 +926,34 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return JS_TRUE; slot = JSVAL_TO_INT(id); - /* No valid function object should lack private data, but check anyway. */ - fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL); - if (!fun) - return JS_TRUE; + /* + * Loop because getter and setter can be delegated from another class, + * but loop only for ARGS_LENGTH because we must pretend that f.length + * is in each function instance f, per ECMA-262, instead of only in the + * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED + * to make it appear so). + * + * This code couples tightly to the attributes for the function_props[] + * initializers above, and to js_SetProperty and js_HasOwnPropertyHelper. + * + * It's important to allow delegating objects, even though they inherit + * this getter (fun_getProperty), to override arguments, arity, caller, + * and name. If we didn't return early for slot != ARGS_LENGTH, we would + * clobber *vp with the native property value, instead of letting script + * override that value in delegating objects. + * + * Note how that clobbering is what simulates JSPROP_READONLY for all of + * the non-standard properties when the directly addressed object (obj) + * is a function object (i.e., when this loop does not iterate). + */ + while (!(fun = (JSFunction *) + JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { + if (slot != ARGS_LENGTH) + return JS_TRUE; + obj = OBJ_GET_PROTO(cx, obj); + if (!obj) + return JS_TRUE; + } /* Find fun's top-most activation record. */ for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));