Closed Bug 510300 Opened 15 years ago Closed 15 years ago

TM: remove callee from FrameInfo

Categories

(Core :: JavaScript Engine, defect)

x86
macOS
defect
Not set
normal

Tracking

()

RESOLVED FIXED
Tracking Status
status1.9.2 --- beta1-fixed

People

(Reporter: dvander, Assigned: dvander)

References

Details

(Whiteboard: fixed-in-tracemonkey)

Attachments

(1 file, 3 obsolete files)

FrameInfo::callee is not trace invariant. This is mucking up recursion performance in v8/early-boyer.js because it internalizes frames and guards on their identity.
Attached patch WIP (obsolete) (deleted) — Splinter Review
WIP, gets rid of GetUpvarOnTrace depending on FrameInfo::callee, which has the nice side effect of greatly simplifying the code (assuming it's correct).
Assignee: general → dvander
Status: NEW → ASSIGNED
Attached patch v2 (obsolete) (deleted) — Splinter Review
Fixes bug 510987, removes FrameInfo::callee completely. Waiting for mochitests+tryserver before flagging for review.
Attachment #394624 - Attachment is obsolete: true
Comment on attachment 394935 [details] [diff] [review]
v2

requesting review from dmandelin for upvar changes
Attachment #394935 - Flags: review?(dmandelin)
Comment on attachment 394935 [details] [diff] [review]
v2

Very nice. Definitely simpler. I only have a few spots where I would like to see a bit more explanation in comments (although there's less pressure on that now that it's simpler).

Comment here something like:

// Return the number of values on the native stack, excluding
// the innermost frame.

May want to change the name to reflect that idea as well.

>+static int32
>+GetTopOfNativeStack(InterpState* state, uint32 callDepth)

>@@ -2393,12 +2403,21 @@
>     FrameInfo** fip = state->rp + callDepth;
> 
>     /*
>-     * First search the FrameInfo call stack for an entry containing
>-     * our upvar, namely one with level == upvarLevel.
>-     */
>-    while (--fip >= state->callstackBase) {
>+     * First search the FrameInfo call stack for an entry containing our upvar, namely one with
>+     * level == upvarLevel. Note that the first entry on the callstack is the trace entry, where
>+     * the callee may not exist. To avoid cluttering FrameInfo with this information, just skip
>+     * the entry frame.
>+     */

I don't understand what "Note that" and what follows it, so that probably needs to be clearer.

>+    int32 stackOffset = GetTopOfNativeStack(state, callDepth);
>+    while (--fip > state->callstackBase) {
>         FrameInfo* fi = *fip;
>-        JSFunction* fun = GET_FUNCTION_PRIVATE(cx, fi->callee);
>+        /*
>+         * The loop starts aligned to the top of the stack, so move down to the first meaningful
>+         * callee. Then read the callee directly from the frame.
>+         */

The above comment is very clear.

>diff -r 666ffe2c6938 js/src/jstracer.h
>--- a/js/src/jstracer.h	Mon Aug 17 17:36:36 2009 -0500
>+++ b/js/src/jstracer.h	Mon Aug 17 15:53:37 2009 -0700
>@@ -437,7 +437,6 @@
> };
> 
> struct FrameInfo {
>-    JSObject*       callee;     // callee function object
>     JSObject*       block;      // caller block chain head
>     jsbytecode*     pc;         // caller fp->regs->pc
>     jsbytecode*     imacpc;     // caller fp->imacpc
>@@ -446,19 +445,18 @@
>     /*
>      * Bit  15 (0x8000) is a flag that is set if constructing (called through new).
>      * Bits 0-14 are the actual argument count. This may be less than fun->nargs.
>+     * NB: This is argc for the callee, not the caller.
>      */
>     uint16          argc;
> 
>     /*
>-     * Stack pointer adjustment needed for navigation of native stack in
>-     * js_GetUpvarOnTrace. spoffset is the number of slots in the native
>-     * stack frame for the caller *before* the slots covered by spdist.
>-     * This may be negative if the caller is the top level script.
>-     * The key fact is that if we let 'cpos' be the start of the caller's
>-     * native stack frame, then (cpos + spoffset) points to the first
>-     * non-argument slot in the callee's native stack frame.
>+     * Number of stack slots in the caller, not counting slots pushed when invoking
>+     * the callee. That is, slots after JSOP_CALL completes but without the return value.
>      */

The above is good. But we should also say something like:

// This is also equal to the number of slots between the caller's
// 'fp->callee' and the callee's 'fp->callee'.

But that's kind of confusing wording. :-) The important point to get across is how the number is used to navigate stack frame.
Attachment #394935 - Flags: review?(dmandelin) → review+
Could I look at the next patch once dmandelin's comments are addressed? Thanks,

/be
Attached patch v2, with better comments (obsolete) (deleted) — Splinter Review
(In reply to comment #4)
Good suggestions. I hope this version is more readable.
Attachment #394935 - Attachment is obsolete: true
Attachment #394993 - Flags: review?(brendan)
Attachment #394935 - Flags: review?(brendan)
Comment on attachment 394993 [details] [diff] [review]
v2, with better comments

..12345678901234567890123456789012345678901234567890123456789012345678901234567890

Wondering if comments following a smaller wrap margin is better for readability; up to you.

> /*
>+ * Returns the number of values on the native stack, excluding the innermost frame. This walks all
>+ * FrameInfos on the native frame stack and sums the slot usage of each frame.
>+ */
>+static int32
>+StackDepthFromCallStack(InterpState* state, uint32 callDepth)
>+{
>+    int32 nativeStackFramePos = 0;

Blank line here for readability?

>+    // Duplicate native stack layout computation: see VisitFrameSlots header comment.
>+    for (FrameInfo** fip2 = state->callstackBase; fip2 < state->rp + callDepth; fip2++)
>+        nativeStackFramePos += (*fip2)->stackslots;

s/fip2/fip/g

>+     * First search the FrameInfo call stack for an entry containing our upvar, namely one with
>+     * level == upvarLevel. The first FrameInfo is a transition from the entry frame to some
>+     * callee. However, it is not known (from looking at the FrameInfo) whether the entry frame
>+     * had a callee. Rather than special case this or insert more logic into the loop, instead just
>+     * stop before that FrameInfo (i.e. |> base| instead of |>= base|), and let the code after the
>+     * loop handle it.

Ditto wrap-margin nit, but even if you use a wider margin, the above looks ragged right -- auto-wrap in vim or emacs?

>+     */
>+    int32 stackOffset = StackDepthFromCallStack(state, callDepth);
>+    while (--fip > state->callstackBase) {
>         FrameInfo* fi = *fip;

Blank line here per house style (major comment following non-{).

>@@ -5686,12 +5709,15 @@
> 
>     JS_ARENA_RELEASE(&cx->stackPool, state.stackMark);
>     while (callstack < rp) {
>+        FrameInfo* fi = *callstack;

Blank line.

>+        /* Peek at the callee stored in the yet-unconstructed down frame. */
>+        JSObject* callee = *(JSObject**)&stack[fi->stackslots];

Ditto.

>     for (unsigned n = 0; n < calldepth; ++n) {
>-        calldepth_slots += SynthesizeFrame(cx, *callstack[n]);

Ditto -- a bit too dense here (not that jstracer.cpp doesn't get dense this way elsewhere :-).

>+        /* Peek at the callee in the yet-unconstructed down frame. */
>+        calleeOffset += callstack[n]->stackslots;
>+        JSObject* callee = *(JSObject**)&stack[calleeOffset];
>+
>+        /* Reconstruct the frame. */

Nice blank line before comment ;-).

> struct FrameInfo {
>-    JSObject*       callee;     // callee function object

Yay!

>     JSObject*       block;      // caller block chain head
>     jsbytecode*     pc;         // caller fp->regs->pc
>     jsbytecode*     imacpc;     // caller fp->imacpc
>@@ -446,19 +445,20 @@
>     /*
>      * Bit  15 (0x8000) is a flag that is set if constructing (called through new).
>      * Bits 0-14 are the actual argument count. This may be less than fun->nargs.
>+     * NB: This is argc for the callee, not the caller.
>      */
>     uint16          argc;
> 
>     /*
>-     * Stack pointer adjustment needed for navigation of native stack in
>-     * js_GetUpvarOnTrace. spoffset is the number of slots in the native
>-     * stack frame for the caller *before* the slots covered by spdist.
>-     * This may be negative if the caller is the top level script.
>-     * The key fact is that if we let 'cpos' be the start of the caller's
>-     * native stack frame, then (cpos + spoffset) points to the first
>-     * non-argument slot in the callee's native stack frame.
>+     * Number of stack slots in the caller, not counting slots pushed when invoking
>+     * the callee. That is, slots after JSOP_CALL completes but without the return value.
>+     * This is also equal to the number of slots between fp->down->argv[-2] (calleR fp->callee) and
>+     * fp->argv[-2] (calleE fp->callee).

Ragged right comment. Also overlong lines suggest rewrapping to 80 if you can stand it.

>      */
>-    int32          spoffset;
>+    uint32          stackslots;

Is there a better name? height or frameHeight?

>+
>+    /* argc of the caller */
>+    uint32          callerArgc;

Could be uint16 but there's nothing to pack it with. But couldn't stackslots be uint16 too? We limit the JIT's native stack depth to << 2^16.

> 
>     // Safer accessors for argc.
>     enum { CONSTRUCTING_MASK = 0x8000 };
(In reply to comment #7)
> Is there a better name? height or frameHeight?

Hrm, how about "callerSlots" or "callerHeight", to match callerArgc?


> Could be uint16 but there's nothing to pack it with. But couldn't stackslots be
> uint16 too? We limit the JIT's native stack depth to << 2^16.

Seems okay to use uint16 here because the sum is kept in a uint32 anyway.
Attached patch addresses comments (deleted) — Splinter Review
Attachment #394993 - Attachment is obsolete: true
Attachment #395738 - Flags: review?(brendan)
Attachment #394993 - Flags: review?(brendan)
Comment on attachment 395738 [details] [diff] [review]
addresses comments

>+     * callee. Rather than special case this or insert more logic into the

Nitus maximus: hyphenate special-case.

>+        /*
>+         * The loop starts aligned to the top of the stack, so move down to the first meaningful
>+         * callee. Then read the callee directly from the frame.
>+         */
>+        stackOffset -= fi->callerHeight;
>+        JSObject* callee = *(JSObject**)(&state->stackBase[stackOffset]);
>+        JSFunction* fun = GET_FUNCTION_PRIVATE(cx, callee);
>         uintN calleeLevel = fun->u.i.script->staticLevel;
>         if (calleeLevel == upvarLevel) {
>             /*
>+             * Now find the upvar's value in the native stack. stackOffset is the offset of the
>+             * start of the activation record corresponding to *fip in the native stack.
>+             */

These comments want rewrapping to match the bigger prior one.

>+    #if defined DEBUG

Forgot to request prevailing #ifdef DEBUG, unindented, style. This looks like nanojit style, but it is overlong in using #if defined, and IMHO hard to spot due to indentation. Old C requird # in col. 1 and we keep that memory alive to help readers spot cpp directives more easily.

>+        /* Peek at the callee in the yet-unconstructed down frame. */

Suggest "Peek at the callee native slot in the not-yet-synthesized down frame."

>-    enum { CONSTRUCTING_MASK = 0x8000 };

Pre-existing nit: CONSTRUCTING_FLAG would be a slightly better name.

Is there an assertion static or runtime, or an error check, that needs to be adjusted? Aha, grep spotted it for me:

$ grep -n 'argc >= ' jstracer.cpp
10693:    if (argc >= 0x8000)
...

We don't need any check now, but you could assert that argc < CONSTRUCTING_FLAG.

Fix these and r=me.

/be
Attachment #395738 - Flags: review?(brendan) → review+
http://hg.mozilla.org/mozilla-central/rev/31e363f76eae
Status: ASSIGNED → RESOLVED
Closed: 15 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: