diff options
author | Martok <martok@martoks-place.de> | 2023-03-12 22:19:39 +0100 |
---|---|---|
committer | Martok <martok@martoks-place.de> | 2023-03-13 00:37:53 +0100 |
commit | c7dff3002f1d136838b3ba4de7d25c824ff70dc0 (patch) | |
tree | 6b3622c2494ea763ce1bc8415b480062c5af77e9 /js/src/frontend/BytecodeEmitter.cpp | |
parent | 9f009467d86fec76c9d909b5283121a35d220f19 (diff) | |
download | uxp-c7dff3002f1d136838b3ba4de7d25c824ff70dc0.tar.gz |
Issue #2155 - Split TDZCheckCache, IfEmitter/InternalIfEmitter, JumpList from BytecodeEmitter
Diffstat (limited to 'js/src/frontend/BytecodeEmitter.cpp')
-rw-r--r-- | js/src/frontend/BytecodeEmitter.cpp | 320 |
1 files changed, 43 insertions, 277 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index e21ab72407..13ba7c45cd 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -27,7 +27,9 @@ #include "jstypes.h" #include "jsutil.h" +#include "frontend/IfEmitter.h" #include "frontend/Parser.h" +#include "frontend/TDZCheckCache.h" #include "frontend/TokenStream.h" #include "vm/Debugger.h" #include "vm/GeneratorObject.h" @@ -67,28 +69,6 @@ ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn) return pn->getKind() == PNK_WHILE || pn->getKind() == PNK_FOR; } -// A cache that tracks superfluous TDZ checks. -// -// Each basic block should have a TDZCheckCache in scope. Some NestableControl -// subclasses contain a TDZCheckCache. -class BytecodeEmitter::TDZCheckCache : public Nestable<BytecodeEmitter::TDZCheckCache> -{ - PooledMapPtr<CheckTDZMap> cache_; - - MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) { - return cache_ || cache_.acquire(bce->cx); - } - - public: - explicit TDZCheckCache(BytecodeEmitter* bce) - : Nestable<TDZCheckCache>(&bce->innermostTDZCheckCache), - cache_(bce->cx->frontendCollectionPool()) - { } - - Maybe<MaybeCheckTDZ> needsTDZCheck(BytecodeEmitter* bce, JSAtom* name); - MOZ_MUST_USE bool noteTDZCheck(BytecodeEmitter* bce, JSAtom* name, MaybeCheckTDZ check); -}; - class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl> { StatementKind kind_; @@ -212,7 +192,7 @@ class LoopControl : public BreakableControl { // Loops' children are emitted in dominance order, so they can always // have a TDZCheckCache. - BytecodeEmitter::TDZCheckCache tdzCache_; + TDZCheckCache tdzCache_; // Stack depth when this loop was pushed on the control stack. int32_t stackDepth_; @@ -1461,53 +1441,6 @@ BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal) return true; } -Maybe<MaybeCheckTDZ> -BytecodeEmitter::TDZCheckCache::needsTDZCheck(BytecodeEmitter* bce, JSAtom* name) -{ - if (!ensureCache(bce)) - return Nothing(); - - CheckTDZMap::AddPtr p = cache_->lookupForAdd(name); - if (p) - return Some(p->value().wrapped); - - MaybeCheckTDZ rv = CheckTDZ; - for (TDZCheckCache* it = enclosing(); it; it = it->enclosing()) { - if (it->cache_) { - if (CheckTDZMap::Ptr p2 = it->cache_->lookup(name)) { - rv = p2->value(); - break; - } - } - } - - if (!cache_->add(p, name, rv)) { - ReportOutOfMemory(bce->cx); - return Nothing(); - } - - return Some(rv); -} - -bool -BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name, - MaybeCheckTDZ check) -{ - if (!ensureCache(bce)) - return false; - - CheckTDZMap::AddPtr p = cache_->lookupForAdd(name); - if (p) { - MOZ_ASSERT(!check, "TDZ only needs to be checked once per binding per basic block."); - p->value() = check; - } else { - if (!cache_->add(p, name, check)) - return false; - } - - return true; -} - class MOZ_STACK_CLASS TryEmitter { public: @@ -1836,156 +1769,6 @@ class MOZ_STACK_CLASS TryEmitter } }; -class MOZ_STACK_CLASS IfThenElseEmitter -{ - BytecodeEmitter* bce_; - JumpList jumpAroundThen_; - JumpList jumpsAroundElse_; - unsigned noteIndex_; - int32_t thenDepth_; -#ifdef DEBUG - int32_t pushed_; - bool calculatedPushed_; -#endif - enum State { - Start, - If, - Cond, - IfElse, - Else, - End - }; - State state_; - - public: - explicit IfThenElseEmitter(BytecodeEmitter* bce) - : bce_(bce), - noteIndex_(-1), - thenDepth_(0), -#ifdef DEBUG - pushed_(0), - calculatedPushed_(false), -#endif - state_(Start) - {} - - ~IfThenElseEmitter() - {} - - private: - bool emitIf(State nextState) { - MOZ_ASSERT(state_ == Start || state_ == Else); - MOZ_ASSERT(nextState == If || nextState == IfElse || nextState == Cond); - - // Clear jumpAroundThen_ offset that points previous JSOP_IFEQ. - if (state_ == Else) - jumpAroundThen_ = JumpList(); - - // Emit an annotated branch-if-false around the then part. - SrcNoteType type = nextState == If ? SRC_IF : nextState == IfElse ? SRC_IF_ELSE : SRC_COND; - if (!bce_->newSrcNote(type, ¬eIndex_)) - return false; - if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_)) - return false; - - // To restore stack depth in else part, save depth of the then part. -#ifdef DEBUG - // If DEBUG, this is also necessary to calculate |pushed_|. - thenDepth_ = bce_->stackDepth; -#else - if (nextState == IfElse || nextState == Cond) - thenDepth_ = bce_->stackDepth; -#endif - state_ = nextState; - return true; - } - - public: - bool emitIf() { - return emitIf(If); - } - - bool emitCond() { - return emitIf(Cond); - } - - bool emitIfElse() { - return emitIf(IfElse); - } - - bool emitElse() { - MOZ_ASSERT(state_ == IfElse || state_ == Cond); - - calculateOrCheckPushed(); - - // Emit a jump from the end of our then part around the else part. The - // patchJumpsToTarget call at the bottom of this function will fix up - // the offset with jumpsAroundElse value. - if (!bce_->emitJump(JSOP_GOTO, &jumpsAroundElse_)) - return false; - - // Ensure the branch-if-false comes here, then emit the else. - if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_)) - return false; - - // Annotate SRC_IF_ELSE or SRC_COND with the offset from branch to - // jump, for IonMonkey's benefit. We can't just "back up" from the pc - // of the else clause, because we don't know whether an extended - // jump was required to leap from the end of the then clause over - // the else clause. - if (!bce_->setSrcNoteOffset(noteIndex_, 0, - jumpsAroundElse_.offset - jumpAroundThen_.offset)) - { - return false; - } - - // Restore stack depth of the then part. - bce_->stackDepth = thenDepth_; - state_ = Else; - return true; - } - - bool emitEnd() { - MOZ_ASSERT(state_ == If || state_ == Else); - - calculateOrCheckPushed(); - - if (state_ == If) { - // No else part, fixup the branch-if-false to come here. - if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_)) - return false; - } - - // Patch all the jumps around else parts. - if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_)) - return false; - - state_ = End; - return true; - } - - void calculateOrCheckPushed() { -#ifdef DEBUG - if (!calculatedPushed_) { - pushed_ = bce_->stackDepth - thenDepth_; - calculatedPushed_ = true; - } else { - MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_); - } -#endif - } - -#ifdef DEBUG - int32_t pushed() const { - return pushed_; - } - - int32_t popped() const { - return -pushed_; - } -#endif -}; - // Class for emitting bytecode for optional expressions. class MOZ_RAII OptionalEmitter { @@ -1995,7 +1778,7 @@ class MOZ_RAII OptionalEmitter private: BytecodeEmitter* bce_; - BytecodeEmitter::TDZCheckCache tdzCache_; + TDZCheckCache tdzCache_; // Jump target for short circuiting code, which has null or undefined values. JumpList jumpShortCircuit_; @@ -2150,8 +1933,8 @@ class ForOfLoopControl : public LoopControl if (!bce->emit1(JSOP_STRICTNE)) // ITER ... EXCEPTION NE return false; - IfThenElseEmitter ifIteratorIsNotClosed(bce); - if (!ifIteratorIsNotClosed.emitIf()) // ITER ... EXCEPTION + InternalIfEmitter ifIteratorIsNotClosed(bce); + if (!ifIteratorIsNotClosed.emitThen()) // ITER ... EXCEPTION return false; MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_)); @@ -2174,10 +1957,10 @@ class ForOfLoopControl : public LoopControl if (!tryCatch_->emitFinally()) return false; - IfThenElseEmitter ifGeneratorClosing(bce); + InternalIfEmitter ifGeneratorClosing(bce); if (!bce->emit1(JSOP_ISGENCLOSING)) // ITER ... FTYPE FVALUE CLOSING return false; - if (!ifGeneratorClosing.emitIf()) // ITER ... FTYPE FVALUE + if (!ifGeneratorClosing.emitThen()) // ITER ... FTYPE FVALUE return false; if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER return false; @@ -2498,27 +2281,6 @@ BytecodeEmitter::emitJumpTarget(JumpTarget* target) return true; } -void -JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset) -{ - SET_JUMP_OFFSET(&code[jumpOffset], offset - jumpOffset); - offset = jumpOffset; -} - -void -JumpList::patchAll(jsbytecode* code, JumpTarget target) -{ - ptrdiff_t delta; - for (ptrdiff_t jumpOffset = offset; jumpOffset != -1; jumpOffset += delta) { - jsbytecode* pc = &code[jumpOffset]; - MOZ_ASSERT(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL); - delta = GET_JUMP_OFFSET(pc); - MOZ_ASSERT(delta < 0); - ptrdiff_t span = target.offset - jumpOffset; - SET_JUMP_OFFSET(pc, span); - } -} - bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) { @@ -5467,14 +5229,14 @@ BytecodeEmitter::emitIteratorCloseInScope(EmitterScope& currentScope, // Step 4. // // Do nothing if "return" is null or undefined. - IfThenElseEmitter ifReturnMethodIsDefined(this); + InternalIfEmitter ifReturnMethodIsDefined(this); if (!emit1(JSOP_DUP)) // ... ITER RET RET return false; if (!emit1(JSOP_UNDEFINED)) // ... ITER RET RET UNDEFINED return false; if (!emit1(JSOP_NE)) // ... ITER RET ?NEQL return false; - if (!ifReturnMethodIsDefined.emitIfElse()) + if (!ifReturnMethodIsDefined.emitThenElse()) return false; if (completionKind == CompletionKind::Throw) { @@ -5847,12 +5609,12 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav } if (member->isKind(PNK_SPREAD)) { - IfThenElseEmitter ifThenElse(this); + InternalIfEmitter ifThenElse(this); if (!isFirst) { // If spread is not the first element of the pattern, // iterator can already be completed. // ... OBJ ITER *LREF DONE - if (!ifThenElse.emitIfElse()) // ... OBJ ITER *LREF + if (!ifThenElse.emitThenElse()) // ... OBJ ITER *LREF return false; if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ ITER *LREF ARRAY @@ -5902,10 +5664,10 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav MOZ_ASSERT(!member->isKind(PNK_SPREAD)); - IfThenElseEmitter ifAlreadyDone(this); + InternalIfEmitter ifAlreadyDone(this); if (!isFirst) { // ... OBJ ITER *LREF DONE - if (!ifAlreadyDone.emitIfElse()) // ... OBJ ITER *LREF + if (!ifAlreadyDone.emitThenElse()) // ... OBJ ITER *LREF return false; if (!emit1(JSOP_UNDEFINED)) // ... OBJ ITER *LREF UNDEF @@ -5942,8 +5704,8 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav if (!emit2(JSOP_UNPICK, emitted + 2)) // ... OBJ ITER DONE *LREF RESULT DONE return false; - IfThenElseEmitter ifDone(this); - if (!ifDone.emitIfElse()) // ... OBJ ITER DONE *LREF RESULT + InternalIfEmitter ifDone(this); + if (!ifDone.emitThenElse()) // ... OBJ ITER DONE *LREF RESULT return false; if (!emit1(JSOP_POP)) // ... OBJ ITER DONE *LREF @@ -5994,8 +5756,8 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav // The last DONE value is on top of the stack. If not DONE, call // IteratorClose. // ... OBJ ITER DONE - IfThenElseEmitter ifDone(this); - if (!ifDone.emitIfElse()) // ... OBJ ITER + InternalIfEmitter ifDone(this); + if (!ifDone.emitThenElse()) // ... OBJ ITER return false; if (!emit1(JSOP_POP)) // ... OBJ return false; @@ -6931,7 +6693,7 @@ BytecodeEmitter::emitTry(ParseNode* pn) bool BytecodeEmitter::emitIf(ParseNode* pn) { - IfThenElseEmitter ifThenElse(this); + IfEmitter ifThenElse(this); if_again: /* Emit code for the condition before pushing stmtInfo. */ @@ -6940,10 +6702,10 @@ BytecodeEmitter::emitIf(ParseNode* pn) ParseNode* elseNode = pn->pn_kid3; if (elseNode) { - if (!ifThenElse.emitIfElse()) + if (!ifThenElse.emitThenElse()) return false; } else { - if (!ifThenElse.emitIf()) + if (!ifThenElse.emitThen()) return false; } @@ -6952,14 +6714,18 @@ BytecodeEmitter::emitIf(ParseNode* pn) return false; if (elseNode) { - if (!ifThenElse.emitElse()) - return false; - if (elseNode->isKind(PNK_IF)) { pn = elseNode; + + if (!ifThenElse.emitElseIf()) + return false; + goto if_again; } + if (!ifThenElse.emitElse()) + return false; + /* Emit code for the else part. */ if (!emitTreeInBranch(elseNode)) return false; @@ -7198,14 +6964,14 @@ BytecodeEmitter::emitAsyncIterator() if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN return false; - IfThenElseEmitter ifAsyncIterIsUndefined(this); + InternalIfEmitter ifAsyncIterIsUndefined(this); if (!emit1(JSOP_DUP)) // OBJ ITERFN ITERFN return false; if (!emit1(JSOP_UNDEFINED)) // OBJ ITERFN ITERFN UNDEF return false; if (!emit1(JSOP_EQ)) // OBJ ITERFN EQ return false; - if (!ifAsyncIterIsUndefined.emitIfElse()) // OBJ ITERFN + if (!ifAsyncIterIsUndefined.emitThenElse()) // OBJ ITERFN return false; if (!emit1(JSOP_POP)) // OBJ @@ -8983,8 +8749,8 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) if (!emit1(JSOP_EQ)) // ITER RESULT EXCEPTION ITER THROW ?EQL return false; - IfThenElseEmitter ifThrowMethodIsNotDefined(this); - if (!ifThrowMethodIsNotDefined.emitIf()) // ITER RESULT EXCEPTION ITER THROW + InternalIfEmitter ifThrowMethodIsNotDefined(this); + if (!ifThrowMethodIsNotDefined.emitThen()) // ITER RESULT EXCEPTION ITER THROW return false; savedDepthTemp = stackDepth; if (!emit1(JSOP_POP)) // ITER RESULT EXCEPTION ITER @@ -9039,10 +8805,10 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) // Call iterator.return() for receiving a "forced return" completion from // the generator. - IfThenElseEmitter ifGeneratorClosing(this); + InternalIfEmitter ifGeneratorClosing(this); if (!emit1(JSOP_ISGENCLOSING)) // ITER RESULT FTYPE FVALUE CLOSING return false; - if (!ifGeneratorClosing.emitIf()) // ITER RESULT FTYPE FVALUE + if (!ifGeneratorClosing.emitThen()) // ITER RESULT FTYPE FVALUE return false; // Step ii. @@ -9058,7 +8824,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) // Step iii. // // Do nothing if "return" is undefined. - IfThenElseEmitter ifReturnMethodIsDefined(this); + InternalIfEmitter ifReturnMethodIsDefined(this); if (!emit1(JSOP_DUP)) // ITER RESULT FTYPE FVALUE ITER RET RET return false; if (!emit1(JSOP_UNDEFINED)) // ITER RESULT FTYPE FVALUE ITER RET RET UNDEFINED @@ -9070,7 +8836,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) // // Call "return" with the argument passed to Generator.prototype.return, // which is currently in rval.value. - if (!ifReturnMethodIsDefined.emitIfElse()) // ITER OLDRESULT FTYPE FVALUE ITER RET + if (!ifReturnMethodIsDefined.emitThenElse()) // ITER OLDRESULT FTYPE FVALUE ITER RET return false; if (!emit1(JSOP_SWAP)) // ITER OLDRESULT FTYPE FVALUE RET ITER return false; @@ -9095,12 +8861,12 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) // // Check if the returned object from iterator.return() is done. If not, // continuing yielding. - IfThenElseEmitter ifReturnDone(this); + InternalIfEmitter ifReturnDone(this); if (!emit1(JSOP_DUP)) // ITER OLDRESULT FTYPE FVALUE RESULT RESULT return false; if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER OLDRESULT FTYPE FVALUE RESULT DONE return false; - if (!ifReturnDone.emitIfElse()) // ITER OLDRESULT FTYPE FVALUE RESULT + if (!ifReturnDone.emitThenElse()) // ITER OLDRESULT FTYPE FVALUE RESULT return false; if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER OLDRESULT FTYPE FVALUE VALUE return false; @@ -10288,7 +10054,7 @@ BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional, if (!emitTree(&conditional.condition())) return false; - IfThenElseEmitter ifThenElse(this); + IfEmitter ifThenElse(this); if (!ifThenElse.emitCond()) return false; @@ -12159,7 +11925,7 @@ OptionalEmitter::emitJumpShortCircuit() { state_ == State::ShortCircuitForCall); MOZ_ASSERT(initialDepth_ + 1 == bce_->stackDepth); - IfThenElseEmitter ifEmitter(bce_); + InternalIfEmitter ifEmitter(bce_); if (!bce_->emitPushNotUndefinedOrNull()) { // [stack] OBJ NOT-UNDEFINED-OR-NULL return false; @@ -12170,7 +11936,7 @@ OptionalEmitter::emitJumpShortCircuit() { return false; } - if (!ifEmitter.emitIf() /* emitThen() */) { + if (!ifEmitter.emitThen()) { return false; } @@ -12204,7 +11970,7 @@ OptionalEmitter::emitJumpShortCircuitForCall() { return false; } - IfThenElseEmitter ifEmitter(bce_); + InternalIfEmitter ifEmitter(bce_); if (!bce_->emitPushNotUndefinedOrNull()) { // [stack] THIS CALLEE NOT-UNDEFINED-OR-NULL return false; @@ -12215,7 +11981,7 @@ OptionalEmitter::emitJumpShortCircuitForCall() { return false; } - if (!ifEmitter.emitIf() /* emitThen() */) { + if (!ifEmitter.emitThen()) { return false; } |