Closed Bug 1169743 Opened 10 years ago Closed 8 years ago

Make classes with extends work in the Jits

Categories

(Core :: JavaScript Engine: JIT, defect, P1)

defect

Tracking

()

RESOLVED FIXED

People

(Reporter: efaust, Assigned: tcampbell)

References

(Blocks 2 open bugs)

Details

(Keywords: perf)

Attachments

(3 files, 3 obsolete files)

No description provided.
Blocks: 1169740
Assignee: nobody → efaustbmo
Status: NEW → ASSIGNED
Attachment #8708570 - Flags: review?(jorendorff)
Comment on attachment 8708572 [details] [diff] [review] Part 2: Implement remaining JSOPs to allow class decls with extends in Baseline. Review of attachment 8708572 [details] [diff] [review]: ----------------------------------------------------------------- ::: js/src/jit/BaselineCompiler.cpp @@ +4365,5 @@ > +BaselineCompiler::emit_JSOP_FUNWITHPROTO() > +{ > + frame.syncStack(0); > + > + masm.extractObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg()); This makes no sense. It worked by serendipity for me, as I test on x64. This should be |masm.unboxObject|, as written, though probably frame.popRegsAndSync(1); Register proto = masm.extractObject(R0, R2,scratchReg()); with the pop() below removed or so is better.
Comment on attachment 8708572 [details] [diff] [review] Part 2: Implement remaining JSOPs to allow class decls with extends in Baseline. Review of attachment 8708572 [details] [diff] [review]: ----------------------------------------------------------------- Nice. ::: js/src/jit/BaselineCompiler.cpp @@ +4366,5 @@ > +{ > + frame.syncStack(0); > + > + masm.extractObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg()); > + masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg()); Yeah I think popRegsAndSync instead of syncStack(0) makes sense.
Attachment #8708572 - Flags: review?(jdemooij) → review+
Comment on attachment 8708570 [details] [diff] [review] Part 1: Rework JSOP_CLASSHERITAGE to be jit-friendly. Review of attachment 8708570 [details] [diff] [review]: ----------------------------------------------------------------- r=me, and this was fine! From our conversation I felt I should expect something much worse. But geez, have you *seen* our frontend? This is nothing... :) ::: js/src/frontend/BytecodeEmitter.cpp @@ +8458,5 @@ > + // throw if heritage isn't either null or a non-generator constructor > + if (!emit1(JSOP_CHECKCLASSHERITAGE)) > + return false; > + > + if (!emit1(JSOP_DUP)) A little comment here showing the JS pseudocode for what we're doing here wouldn't suck. I think it's: base !== null ? <base, base.prototype> : <%FunctionPrototype%, null> @@ +8471,5 @@ > + if (!newSrcNote(SRC_IF_ELSE, &noteIndex)) > + return false; > + > + ptrdiff_t nullOffset; > + if (!emitJump(JSOP_IFNE, 0, &nullOffset)) `if` statements and ternary expressions use JSOP_IFEQ, so just for uniformity I'd probably emit STRICTNEQ IFEQ instead of STRICTEQ IFNE. But if that seems stupid to you, never mind. :) @@ +8486,5 @@ > + > + // Our stack depth calculations are not smart enough to understand branches, > + // so decrement the stackDepth to account for the value pushed above. > + this->stackDepth--; > + MOZ_ASSERT(this->stackDepth == ifDepth); Two things. 1. To my mind, this adjustment belongs after the emitJump(JSOP_GOTO). That's how emitConditionalExpression does it. 2. The comment could maybe point out that emitConditionalExpression does the same thing, and explain why we're only adjusting by 1 instead of 2, even though our if-expression produces 2 values. (It's because we are also consuming the value just below us on the stack.) ::: js/src/js.msg @@ +106,5 @@ > MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|") > MSG_DEF(JSMSG_UNINITIALIZED_THIS, 1, JSEXN_REFERENCEERR, "|this| used uninitialized in {0} class constructor") > MSG_DEF(JSMSG_BAD_DERIVED_RETURN, 1, JSEXN_TYPEERR, "derived class constructor returned invalid value {0}") > MSG_DEF(JSMSG_NOT_SELFHOSTED, 1, JSEXN_TYPEERR, "callFunction() used on non self-hosted builtin {0}") > +MSG_DEF(JSMSG_BAD_HERITAGE, 2, JSEXN_TYPEERR, "class heritage {0} is {1}") "heritage" is spec-jargon. consider using "superclass" or "base class"?
Attachment #8708570 - Flags: review?(jorendorff) → review+
uhm...why didn't this land? ni? me until I figure out where I dropped this on the floor.
Flags: needinfo?(efaustbmo)
Blocks: sm-js-perf
Priority: -- → P2
Keywords: perf
Assignee: efaustbmo → nobody
Status: ASSIGNED → NEW
Flags: needinfo?(efaustbmo)
Priority: P2 → P1
Realistically this will be for next release.
Priority: P1 → P2
Flags: needinfo?(hv1989)
Flags: needinfo?(hv1989)
Priority: P2 → P1
Assignee: nobody → tcampbell
Attachment #8708570 - Attachment is obsolete: true
Attachment #8708572 - Attachment is obsolete: true
I've cleaned up these patches and brought them up to date. Requesting re-reviews since a number of APIs have changed.
Attachment #8871011 - Flags: review?(jdemooij)
Comment on attachment 8871011 [details] Bug 1169743 - Implement class decls with extends in Baseline https://reviewboard.mozilla.org/r/142578/#review147890 Looks good, sorry for the delay.
Attachment #8871011 - Flags: review?(jdemooij) → review+
Attachment #8871010 - Flags: review?(shu)
Comment on attachment 8871010 [details] Bug 1169743 - Rework JSOP_CLASSHERITAGE to be jit-friendly. https://reviewboard.mozilla.org/r/142576/#review149854 Looks good generally. Would like to see new version with stack comments for the BCE codegen. ::: js/src/frontend/BytecodeEmitter.cpp:10680 (Diff revision 2) > + IfThenElseEmitter ifThenElse(this); > + > if (!emitTree(heritageExpression)) > return false; > - if (!emit1(JSOP_CLASSHERITAGE)) > + > + // throw if heritage isn't either null or a non-generator constructor Awkward sentence, just "Heritage must be null or a non-generator constructor" would be clearer. ::: js/src/frontend/BytecodeEmitter.cpp:10684 (Diff revision 2) > - if (!emit1(JSOP_CLASSHERITAGE)) > + > + // throw if heritage isn't either null or a non-generator constructor > + if (!emit1(JSOP_CHECKCLASSHERITAGE)) > return false; > - if (!emit1(JSOP_OBJWITHPROTO)) > + > + // [IF] (heritage !== null) The convention in BCE is to list the pseudo-code algorithm in a block comment above the emitted code, and for each emitted bytecode, document the stack state to the right. See something like emitDestructuringOpsArray for a thorough example. ::: js/src/vm/Interpreter.cpp:975 (Diff revision 2) > MOZ_ASSERT(v.isSymbol()); > return JSTYPE_SYMBOL; > } > > +bool > +js::CheckClassHeritage(JSContext* cx, HandleValue heritage) Because of the error reporting behavior where it tries to decompile an on-stack value, please name this CheckClassHeritageOperation. ::: js/src/vm/Interpreter.cpp:978 (Diff revision 2) > > +bool > +js::CheckClassHeritage(JSContext* cx, HandleValue heritage) > +{ > + if (heritage.isObject()) { > + if (!heritage.toObject().isConstructor()) { !IsConstructor(heritage) is nicer. ::: js/src/vm/Interpreter.cpp:4139 (Diff revision 2) > } > END_CASE(JSOP_ARRAYPUSH) > > -CASE(JSOP_CLASSHERITAGE) > +CASE(JSOP_CHECKCLASSHERITAGE) > { > - ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]); > + ReservedRooted<Value> heritage(&rootValue0, REGS.sp[-1]); stackHandleAt ::: js/src/vm/Interpreter.cpp:4150 (Diff revision 2) > > - funcProto = &val.toObject(); > - > - if (!GetProperty(cx, funcProto, funcProto, cx->names().prototype, &objProto)) > - goto error; > - > +CASE(JSOP_BUILTINPROTO) > +{ > + ReservedRooted<JSObject*> builtin(&rootObject0); > + JSProtoKey key = static_cast<JSProtoKey>(GET_UINT8(REGS.pc)); > + MOZ_ASSERT(key < JSProto_LIMIT); I admit I'm not clear on the C++ enum semantics here. Should this assert be checked on the bare uint8 argument with JSProto_LIMIT cast to uint8? That is -- I'm worried by casting to JSProtoKey first, if the C++ standard permits the compiler to clamp to values <= JSProto_LIMIT.
Attachment #8871010 - Flags: review?(shu)
Comment on attachment 8871010 [details] Bug 1169743 - Rework JSOP_CLASSHERITAGE to be jit-friendly. https://reviewboard.mozilla.org/r/142576/#review150400 ::: js/src/frontend/BytecodeEmitter.cpp:10706 (Diff revision 4) > + // if defined <BaseExpression> { > + // cons = DefaultDerivedConstructor(proto=homeObject, funProto=funProto); > + // } else { > + // cons = DefaultConstructor(proto=homeObject); > + // } > + // } Awesome comment. ::: js/src/frontend/BytecodeEmitter.cpp:10802 (Diff revision 4) > - if (!emitAtomOp(name, JSOP_CLASSCONSTRUCTOR)) > + if (!emitAtomOp(name, JSOP_CLASSCONSTRUCTOR)) // ... HOMEOBJ CONSTRUCTOR > return false; > } > } > > - if (!emit1(JSOP_SWAP)) > + if (!emit1(JSOP_SWAP)) // ... CONS HOBJ Consistency trumps staying within the 100 column limits here imo. Please keep using CONSTRUCTOR and HOMEOBJ and just go over the max width. ::: js/src/vm/Interpreter.cpp:977 (Diff revision 4) > } > > +bool > +js::CheckClassHeritageOperation(JSContext* cx, HandleValue heritage) > +{ > + if (heritage.isObject()) { This would return true for non-constructor objects. if (heritage.isNull()) return true; if (IsConstructor(heritage)) return true; report(...); return false; ::: js/src/vm/Opcodes.h:494 (Diff revision 4) > * Operands: > * Stack: callee, this, args => rval > */ \ > macro(JSOP_STRICTSPREADEVAL, 50, "strict-spreadeval", NULL, 1, 3, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET|JOF_CHECKSTRICT) \ > /* > - * Writes the [[Prototype]] objects for both a class and its .prototype to > + * Ensure the result of a class's heritage expression is either null or a constructor. Nit: Ensures
Attachment #8871010 - Flags: review?(shu) → review+
Comment on attachment 8871010 [details] Bug 1169743 - Rework JSOP_CLASSHERITAGE to be jit-friendly. https://reviewboard.mozilla.org/r/142576/#review150406 Great comments, thanks for adding the stack state comments to parts that didn't have them before. r=me with the logic in CheckHeritageOperation fixed.
Pushed by tcampbell@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/bc64157bced9 Rework JSOP_CLASSHERITAGE to be jit-friendly. r=shu https://hg.mozilla.org/integration/autoland/rev/c1ae34baf77a Implement class decls with extends in Baseline r=jandem
Keywords: leave-open
This patch adds three more opcodes needed to support derived classes (and default constructors) in Baseline. With this, top-level code that defines classes is JIT-able. Individual methods that use |super| will be supported in other bugs.
Attachment #8875450 - Flags: review?(jdemooij)
Some tests still fail. Will look into them tomorrow.
Respin of patch with missing write barriers in Baseline INITHOMEOBJECT. Try: https://treeherder.mozilla.org/#/jobs?repo=try&revision=eab95d04774eec4e65f08784cbc012bdd3b2b622
Attachment #8875450 - Attachment is obsolete: true
Attachment #8875450 - Flags: review?(jdemooij)
Attachment #8875578 - Flags: review?(jdemooij)
Comment on attachment 8875578 [details] [diff] [review] 0001-Bug-1169743-Implement-class-decls-with-extends-in-Ba.patch Review of attachment 8875578 [details] [diff] [review]: ----------------------------------------------------------------- Great to have these ops finally implemented in Baseline. ::: js/src/jit/BaselineCompiler.cpp @@ +4729,5 @@ > + masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), func); > + > + // Set HOMEOBJECT_SLOT > + Address addr(func, FunctionExtended::offsetOfMethodHomeObjectSlot()); > + masm.guardedCallPreBarrier(addr, MIRType::Value); Is HOMEOBJECT_SLOT always undefined at this point? If yes we don't need a pre-barrier and could assert this in debug builds.
Attachment #8875578 - Flags: review?(jdemooij) → review+
Pushed by tcampbell@mozilla.com: https://hg.mozilla.org/integration/mozilla-inbound/rev/24191914f43b Implement class decls with extends in Baseline (cont.) r=jandem
Closing bug as this is fixed for Baseline and seems stable in nightly. I'll open a new bug to discuss Ion support of classes.
Status: NEW → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Removing leave-open keyword from resolved bugs, per :sylvestre.
Keywords: leave-open
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: