Subj : Re: JavaScript problem To : Adrian Herscu From : Brendan Eich Date : Sun Oct 12 2003 01:23 pm This is a multi-part message in MIME format. --------------060500060004060304050902 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Adrian Herscu wrote: > Brendan Eich wrote: > >> f.caller in the second case will be Function.prototype.call -- the >> native call method. It has no p property, of course. > > > Is there any reason behind this? After all, both call f(). > Why the "caller" refers to different objects, depending on the call > style? The reason is straightforward-- the g function called the Function.prototype.call method via f.call, and g is the caller of f.call, just as f.call is the caller of f. We could change to match IE. That requires more work than is done in the present code, where the default caller reflection "just works" because it traverses one stack frame (activation object) from the top-most to find the caller function object. It doesn't require a lot of new code, though. Attached is the patch. Let me know if it doesn't work for you. /be --------------060500060004060304050902 Content-Type: text/plain; name="caller.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="caller.patch" Index: jsfun.c =================================================================== RCS file: /cvsroot/mozilla/js/src/jsfun.c,v retrieving revision 3.87 diff -p -u -8 -r3.87 jsfun.c --- jsfun.c 26 Jul 2003 22:37:08 -0000 3.87 +++ jsfun.c 12 Oct 2003 19:04:53 -0000 @@ -925,16 +925,18 @@ fun_getProperty(JSContext *cx, JSObject case FUN_NAME: *vp = fun->atom ? ATOM_KEY(fun->atom) : STRING_TO_JSVAL(cx->runtime->emptyString); break; case FUN_CALLER: + while (fp && (fp->flags & JSFRAME_INTERNAL) && fp->down) + fp = fp->down; if (fp && fp->down && fp->down->fun && fp->down->argv) *vp = fp->down->argv[-2]; else *vp = JSVAL_NULL; if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) { id = ATOM_KEY(cx->runtime->atomState.callerAtom); if (!cx->runtime->checkObjectAccess(cx, obj, id, JSACC_READ, vp)) return JS_FALSE; Index: jsinterp.c =================================================================== RCS file: /cvsroot/mozilla/js/src/jsinterp.c,v retrieving revision 3.125 diff -p -u -8 -r3.125 jsinterp.c --- jsinterp.c 24 Sep 2003 16:49:57 -0000 3.125 +++ jsinterp.c 12 Oct 2003 19:04:55 -0000 @@ -656,20 +656,17 @@ js_Invoke(JSContext *cx, uintN argc, uin * Set frame.rval early so native class and object ops can throw and * return false, causing a goto out2 with ok set to false. Also set * frame.flags to 0 or to JSFRAME_CONSTRUCTING so we may test it * anywhere below. */ vp = sp - (2 + argc); v = *vp; frame.rval = JSVAL_VOID; -#if JSINVOKE_CONSTRUCT != JSFRAME_CONSTRUCTING -# error "constructor invoke/frame flag mismatch!" -#endif - frame.flags = (flags & JSINVOKE_CONSTRUCT); + frame.flags = flags; /* A callee must be an object reference. */ if (JSVAL_IS_PRIMITIVE(v)) goto bad; funobj = JSVAL_TO_OBJECT(v); /* Load callee parent and this parameter for later. */ parent = OBJ_GET_PARENT(cx, funobj); Index: jsinterp.h =================================================================== RCS file: /cvsroot/mozilla/js/src/jsinterp.h,v retrieving revision 3.33 diff -p -u -8 -r3.33 jsinterp.h --- jsinterp.h 6 Mar 2003 19:45:17 -0000 3.33 +++ jsinterp.h 12 Oct 2003 19:04:55 -0000 @@ -74,22 +74,24 @@ struct JSStackFrame { typedef struct JSInlineFrame { JSStackFrame frame; /* base struct */ void *mark; /* mark before inline frame */ void *hookData; /* debugger call hook data */ JSVersion callerVersion; /* dynamic version of calling script */ } JSInlineFrame; /* JS stack frame flags. */ -#define JSFRAME_CONSTRUCTING 0x1 /* frame is for a constructor invocation */ -#define JSFRAME_ASSIGNING 0x2 /* a complex (not simplex JOF_ASSIGNING) op +#define JSFRAME_CONSTRUCTING 0x01 /* frame is for a constructor invocation */ +#define JSFRAME_INTERNAL 0x02 +#define JSFRAME_ASSIGNING 0x04 /* a complex (not simplex JOF_ASSIGNING) op is currently assigning to a property */ -#define JSFRAME_DEBUGGER 0x4 /* frame for JS_EvaluateInStackFrame */ -#define JSFRAME_EVAL 0x8 /* frame for obj_eval */ -#define JSFRAME_SPECIAL 0xc /* special evaluation frame flags */ +#define JSFRAME_DEBUGGER 0x10 /* frame for JS_EvaluateInStackFrame */ +#define JSFRAME_EVAL 0x20 /* frame for obj_eval */ +#define JSFRAME_SPECIAL 0x30 /* special evaluation frame flags */ + #define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */ #define JSFRAME_OVERRIDE_BITS 8 /* * Property cache for quickened get/set property opcodes. */ #define PROPERTY_CACHE_LOG2 10 #define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2) @@ -238,22 +240,20 @@ js_SetLocalVariable(JSContext *cx, JSObj /* * NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp * is non-null). */ extern JS_FRIEND_API(JSBool) js_Invoke(JSContext *cx, uintN argc, uintN flags); /* - * Consolidated js_Invoke flags. NB: JSINVOKE_CONSTRUCT must be the same bit - * as JSFRAME_CONSTRUCTING (see js_Invoke's initialization of frame.flags -- - * there's a #error check to ensure this identity in jsinterp.c). + * Consolidated js_Invoke flags simply rename the low JSFRAME_* flags. */ -#define JSINVOKE_CONSTRUCT 0x1 /* construct object rather than call */ -#define JSINVOKE_INTERNAL 0x2 /* internal call, not from a script */ +#define JSINVOKE_CONSTRUCT JSFRAME_CONSTRUCTING +#define JSINVOKE_INTERNAL JSFRAME_INTERNAL /* * "Internal" calls may come from C or C++ code using a JSContext on which no * JS is running (!cx->fp), so they may need to push a dummy JSStackFrame. */ #define js_InternalCall(cx,obj,fval,argc,argv,rval) \ js_InternalInvoke(cx, obj, fval, 0, argc, argv, rval) --------------060500060004060304050902-- .