Open Bug 720316 Opened 8 years ago Updated 6 months ago

Remove indexbase support

Categories

(Core :: JavaScript Engine, defect)

defect
Not set

Tracking

()

ASSIGNED
mozilla13

People

(Reporter: Waldo, Assigned: Waldo)

References

Details

Attachments

(5 files, 2 obsolete files)

Currently, any script which has more functions, objects, atoms, etc. than UINT16_MAX uses a complicated encoding scheme to store larger indexes.  It's fairly messy complexity, and it makes life trickier for the interpreter, JITs, and so on.  We should just use 32-bit indexes instead for simplicity.

I've started on patches to implement this, converting over minimal sets of opcodes from 16-bit indexes + indexbase to 32-bit indexes.  I don't have it all done yet, but I've got a few patches for some portions of this work to post.  Remaining bits should follow over the next couple days.
Just noticed in passing, seems better to be clean about this...
Attachment #590834 - Flags: review?(luke)
It's unused.
Attachment #590835 - Flags: review?(luke)
This is probably the easiest of the indexes to make 32 bits, because nothing else (no other opcodes, methods, etc.) implicitly or explicitly depends on this.
Attachment #590836 - Flags: review?(luke)
Let's spread the review love around a bit.

Still to go are double indexes and atom indexes.  There might be more splitup to do here, not clear -- doubles used to be encoded as atoms, so there may be some intertwinedness that'll require fixing both at once.
Attachment #590838 - Flags: review?(jorendorff)
Comment on attachment 590834 [details] [diff] [review]
Introduce GET_UINT8/SET_UINT8 helpers

Review of attachment 590834 [details] [diff] [review]:
-----------------------------------------------------------------

::: js/src/jsinterp.cpp
@@ +2125,5 @@
>  BEGIN_CASE(JSOP_PICK)
>  {
> +    uint8_t i = GET_UINT8(regs.pc);
> +    JS_ASSERT(regs.sp - (i + 1) >= regs.fp()->base());
> +    Value lval = regs.sp[-int8_t(i + 1)];

EmitDestructingOpsHelper emits uint8's up to jsbytecode(-1) (should be changed to UINT8_MAX) which I think breaks this.  Thus even uint8_t would be the wrong type here.  I'd prefer 'i' to be 'unsigned' and then this expression to be 'regs.sp[-int(i + 1)]'.
Attachment #590834 - Flags: review?(luke) → review+
Attachment #590835 - Flags: review?(luke) → review+
Attachment #590836 - Flags: review?(luke) → review+
Comment on attachment 590838 [details] [diff] [review]
Make object and function indexes 32 bits

All right. Finish it!
Attachment #590838 - Flags: review?(jorendorff) → review+
dvander, the object/function index patch here breaks these tests:

http://hg.mozilla.org/mozilla-central/file/default/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js
http://hg.mozilla.org/mozilla-central/file/default/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js

Both claim the number being trapped is the JSOP_STOP in main.  Right now, tho, they're hitting the JSOP_POP right before JSOP_STOP in main.  Should I repoint them at JSOP_STOP when I land that patch?

(Also, good grief is trap fragile.  We should have a function which takes the index, the bytecode at that location, and perhaps the surrounding two bytecodes to verify that bytecode changes don't end up silently making trap-using tests not test what they were intended to test.)
(In reply to Jeff Walden (remove +bmo to email) from comment #9)
> Both claim the number being trapped is the JSOP_STOP in main.  Right now,
> tho, they're hitting the JSOP_POP right before JSOP_STOP in main.  Should I
> repoint them at JSOP_STOP when I land that patch?
> 
> (Also, good grief is trap fragile.  We should have a function which takes
> the index, the bytecode at that location, and perhaps the surrounding two
> bytecodes to verify that bytecode changes don't end up silently making
> trap-using tests not test what they were intended to test.)

Yeah, they are very fragile. Ideally they would specify a line number or something. I'm not sure what opcode they're supposed to be pointing at, usually I just +/- 1 or so until they work again, but recently I had to fix these as well and I think I landed on the JSOP_POP.
https://hg.mozilla.org/integration/mozilla-inbound/rev/08f4fc94e27b

Still don't close this, more to come...
Sorry, had to back this out on inbound because it (or something it landed with) had some jsreftest issues:
https://hg.mozilla.org/integration/mozilla-inbound/rev/a22cb315b248
https://hg.mozilla.org/integration/mozilla-inbound/rev/551dcf40a209

with the Windows-specific bustage fix attempted yesterday (successfully, but other stuff was broken from different commits).

Still more to come.
This passes every test but regress-634472.js.  Reduced and with some jit-args futzing, it comes to this:

[jwalden@wheres-wally src]$ cat /tmp/test.js 
var x = [];
var cases = [{q:1}, {q:2}];

for (let i = 0; i < 2; i++)
  cases[i].z;
[jwalden@wheres-wally src]$ dbg/js -m -a -f /tmp/test.js 
/tmp/test.js:5: TypeError: cases[i] is undefined

Here's a variant that also has a weird failure mode:

[jwalden@wheres-wally src]$ cat /tmp/experiment.js 
var x = [];
var cases = [{z:1}, {z:2}];

Array.prototype[1] = { z: "foo" };

var q;
for (let i = 0; i < 2; i++)
  q = cases[i].z;

print(q);
[jwalden@wheres-wally src]$ dbg/js -m -a -f /tmp/experiment.js 
1
[jwalden@wheres-wally src]$ ~/moz/mfbt/js/src/dbg/js -m -a -f /tmp/experiment.js # the correct result
2

I'm not getting very far figuring out what's wrong with this.  :-\  Stepping a little in a debugger, it appears that js::mjit::stubs::GetElement is being called with the wrong object -- the object |x| (the length-zero array), not the object |cases|.  I'm at a loss to say how this is happening right now.

Anyway, that's the status right now.  I'm still trying to figure out what's wrong here, and why my changes would have triggered this in the first place.
Luke is my hero forever.
Attachment #595085 - Attachment is obsolete: true
Attachment #595110 - Flags: review?(jorendorff)
Wait. What does this patch contain? Does it include all four patches? What part of it hasn't been reviewed already?
Comment on attachment 595110 [details] [diff] [review]
Remove indexbase from all remaining ops

It's separate from the other patches (all of which landed).  Those patches could be done separately, so in the interests of smaller patches and easier debugging I did them separately.  Unfortunately JOF_ATOM for the rest is quite monolithic, so everything in this patch has to be done at once.  (You could extract the JSOP_DOUBLE bits, but those are small enough that it wasn't really worth extracting that out into another patch, after the fact.)
Attachment #595110 - Attachment description: Fully working patch → Remove indexbase from all remaining ops
Comment on attachment 595110 [details] [diff] [review]
Remove indexbase from all remaining ops

>--- a/js/src/jsinfer.cpp
>+++ b/js/src/jsinfer.cpp
>@@ -2035,21 +2035,21 @@ TypeCompartment::newAllocationSiteTypeOb
> static inline jsid
> GetAtomId(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset)
> {
>-    unsigned index = js_GetIndexFromBytecode(script, (jsbytecode*) pc, offset);
>+    unsigned index = js_GetIndexFromBytecode((jsbytecode*) pc, offset);
>     return MakeTypeId(cx, ATOM_TO_JSID(script->getAtom(index)));
> }
> 
> static inline JSObject *
> GetScriptObject(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset)
> {
>-    unsigned index = js_GetIndexFromBytecode(script, (jsbytecode*) pc, offset);
>+    unsigned index = js_GetIndexFromBytecode((jsbytecode*) pc, offset);
>     return script->getObject(index);
> }
> 
> static inline const Value &
> GetScriptConst(JSContext *cx, JSScript *script, const jsbytecode *pc)
> {
>-    unsigned index = js_GetIndexFromBytecode(script, (jsbytecode*) pc, 0);
>+    unsigned index = js_GetIndexFromBytecode((jsbytecode*) pc, 0);
>     return script->getConst(index);
> }
> 

Want to make those explicit const_casts while you're here?
Attached patch RebasedSplinter Review
Attachment #595110 - Attachment is obsolete: true
Attachment #595110 - Flags: review?(jorendorff)
Attachment #597160 - Flags: review?(jorendorff)
Comment on attachment 597160 [details] [diff] [review]
Rebased

You might want to bump JSXDR_BYTECODE_VERSION after this.

In frontend/BytecodeEmitter.cpp, frontend::EmitTree:
>       case PNK_XMLATTR:
>       case PNK_XMLSPACE:
>       case PNK_XMLTEXT:
>-      case PNK_XMLCDATA:
>-      case PNK_XMLCOMMENT:
>-        JS_ASSERT(!bce->inStrictMode());
>         /* FALL THROUGH */
> #endif
>       case PNK_STRING:
>         ok = EmitAtomOp(cx, pn, pn->getOp(), bce);
>         break;
> 
>+#if JS_HAS_XML_SUPPORT
>+      case PNK_XMLCDATA:
>+      case PNK_XMLCOMMENT:
>+        JS_ASSERT(!bce->inStrictMode());
>+        ok = EmitAtomOp(cx, pn, pn->getOp(), bce);
>+        break;
>+#endif

What changed here? Wasn't it OK the way it was?  Didn't you basically
remove an assertion from the PNK_XML{ATTR,SPACE,TEXT} cases?  I'm all
for cloning the EmitAtomOp call instead of FALL THROUGH, if you want.

In jsanalyze.cpp, ScriptAnalysis::checkAliasedName:
>+        atom = script->getAtom(GET_UINT32_INDEX(pc));

A convenience method script->getAtomAt(pc) would be nice.

In jsinterp.cpp, js::Interpret:
> # define END_CASE_LEN4      len = 4; goto advance_pc;
> # define END_CASE_LEN5      len = 5; goto advance_pc;
>+# define END_CASE_LEN6      len = 6; goto advance_pc;
> # define END_CASE_LEN7      len = 7; goto advance_pc;

lol

In jsobj.cpp, Detecting:
>-            /*
>-             * At this point, anything but an extended atom index prefix means
>-             * we're not detecting.
>-             */
>-            if (!(js_CodeSpec[op].format & JOF_INDEXBASE))
>-                return JS_FALSE;
>-            break;
>+            return JS_FALSE;
>         }
>     }
> }

Yay! You can get rid of the loop now. While you're doing that, might as
well switch to C++ true and false.

In jsopcode.h:
>  * A slower version of GET_ATOM when the caller does not want to maintain
>  * the index segment register itself.

This comment already didn't make sense, but now it doesn't make even
more sense. Fix it?

In GetDecomposeLength:
>     /*
>-     * The last byte of a DECOMPOSE op stores the decomposed length. This can
>-     * vary across different instances of an opcode due to INDEXBASE ops.
>+     * The last byte of a DECOMPOSE op stores the decomposed length.  This is a
>+     * constant: perhaps we should just hardcode values instead?
>      */

bhackett, I think you wrote this comment originally. Do you want a
follow-up bug for this?
Attachment #597160 - Flags: review?(jorendorff) → review+
https://hg.mozilla.org/integration/mozilla-inbound/rev/f4e955f78de9

And that finishes off this bug for good now.  \o/  Merge-monkeys may close this bug after this last merge to m-c.

(In reply to Jason Orendorff [:jorendorff] from comment #21)
> You might want to bump JSXDR_BYTECODE_VERSION after this.

Done.  I'm pretty sure I'd been bumping it in every other patch, and either I forgot here or someone else bumped it and rebasing didn't expose it as a conflict at some point.  I'm betting on the latter.  ;-)

> What changed here? Wasn't it OK the way it was?  Didn't you basically
> remove an assertion from the PNK_XML{ATTR,SPACE,TEXT} cases?  I'm all
> for cloning the EmitAtomOp call instead of FALL THROUGH, if you want.

Hmm.  I remember making a change here (or starting to make one) out of necessity, but I don't remember what that was, and now it's not obvious why I was making it.  Reverted this bit, don't feel strongly about removing fallthrough here.

> In jsanalyze.cpp, ScriptAnalysis::checkAliasedName:
> >+        atom = script->getAtom(GET_UINT32_INDEX(pc));
> 
> A convenience method script->getAtomAt(pc) would be nice.

Luke and I discussed this briefly and agreed that we really should make bytecode streams some sort of abstract, class-y view of the underlying bytes -- no jsbytecode* that gets abused horribly in every use.  I guess that doesn't really conflict with this, but I kind of think it'd be nice to solve all these convenience methods in one coherent whole rather than pick off pieces at a time possibly inconsistently.  I'll file a bug on making a nicer bytecode sequence interface that can sweep this up.

> In jsinterp.cpp, js::Interpret:
> > # define END_CASE_LEN4      len = 4; goto advance_pc;
> > # define END_CASE_LEN5      len = 5; goto advance_pc;
> >+# define END_CASE_LEN6      len = 6; goto advance_pc;
> > # define END_CASE_LEN7      len = 7; goto advance_pc;
> 
> lol

...yeah.  I broke Windows because of this in one of the previous patches here, I think.  :-\  We probably should just remove the threaded-interpreter code rather than have to treat Windows specially like this.

> In jsopcode.h:
> >  * A slower version of GET_ATOM when the caller does not want to maintain
> >  * the index segment register itself.
> 
> This comment already didn't make sense, but now it doesn't make even
> more sense. Fix it?

I removed it entirely -- I can't think of a way to fix it that doesn't just make it mostly a nullity.

> In GetDecomposeLength:
> >     /*
> >-     * The last byte of a DECOMPOSE op stores the decomposed length. This can
> >-     * vary across different instances of an opcode due to INDEXBASE ops.
> >+     * The last byte of a DECOMPOSE op stores the decomposed length.  This is a
> >+     * constant: perhaps we should just hardcode values instead?
> >      */
> 
> bhackett, I think you wrote this comment originally. Do you want a
> follow-up bug for this?

CCing in case he doesn't watch the component (I don't know one way or the other)...
(In reply to Jeff Walden (:Waldo) (remove +bmo to email) from comment #22)
> > In GetDecomposeLength:
> > >     /*
> > >-     * The last byte of a DECOMPOSE op stores the decomposed length. This can
> > >-     * vary across different instances of an opcode due to INDEXBASE ops.
> > >+     * The last byte of a DECOMPOSE op stores the decomposed length.  This is a
> > >+     * constant: perhaps we should just hardcode values instead?
> > >      */
> > 
> > bhackett, I think you wrote this comment originally. Do you want a
> > follow-up bug for this?
> 
> CCing in case he doesn't watch the component (I don't know one way or the
> other)...

Sure, it would be good to simplify the decompose stuff.  Until I hit the INDEXBASE problem, earlier patches in that bug hardcoded things.  (I watch NEW bugs in JS, but not other activity).
There's a claim that something in the overall push that included this last change caused a heap-size regression:

https://bugzilla.mozilla.org/show_bug.cgi?id=728411#c18

This seems the most likely candidate, but even still I'd be a bit surprised about this.  A 2% increase seems way higher than I'd expect for any change from this.

As far as diagnosing the actual cause...um.  Maybe I have time tomorrow to back everything out and land stuff piecemeal, or something.
Before doing anything drastic, why don't you run membuster (http://gregor-wagner.com/tmp/mem) and compare overall explicit change as well as script bytes.
Depends on: 730810
Depends on: 732759
Depends on: 743876
Depends on: 770089
No longer depends on: 770089
You need to log in before you can comment on or make changes to this bug.