1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* JS bytecode generation. */ 8 9 #ifndef frontend_BytecodeEmitter_h 10 #define frontend_BytecodeEmitter_h 11 12 #include "mozilla/Attributes.h" 13 14 #include "ds/InlineTable.h" 15 #include "frontend/EitherParser.h" 16 #include "frontend/SharedContext.h" 17 #include "frontend/SourceNotes.h" 18 #include "vm/BytecodeUtil.h" 19 #include "vm/Interpreter.h" 20 #include "vm/Iteration.h" 21 #include "vm/JSContext.h" 22 #include "vm/JSScript.h" 23 24 namespace js { 25 namespace frontend { 26 27 class CGConstList { 28 Vector<Value> list; 29 30 public: CGConstList(JSContext * cx)31 explicit CGConstList(JSContext* cx) : list(cx) {} append(const Value & v)32 MOZ_MUST_USE bool append(const Value& v) { 33 MOZ_ASSERT_IF(v.isString(), v.toString()->isAtom()); 34 return list.append(v); 35 } length()36 size_t length() const { return list.length(); } 37 void finish(ConstArray* array); 38 }; 39 40 struct CGObjectList { 41 uint32_t length; /* number of emitted so far objects */ 42 ObjectBox* lastbox; /* last emitted object */ 43 CGObjectListCGObjectList44 CGObjectList() : length(0), lastbox(nullptr) {} 45 46 unsigned add(ObjectBox* objbox); 47 unsigned indexOf(JSObject* obj); 48 void finish(ObjectArray* array); 49 ObjectBox* find(uint32_t index); 50 }; 51 52 struct MOZ_STACK_CLASS CGScopeList { 53 Rooted<GCVector<Scope*>> vector; 54 CGScopeListCGScopeList55 explicit CGScopeList(JSContext* cx) : vector(cx, GCVector<Scope*>(cx)) {} 56 appendCGScopeList57 bool append(Scope* scope) { return vector.append(scope); } lengthCGScopeList58 uint32_t length() const { return vector.length(); } 59 void finish(ScopeArray* array); 60 }; 61 62 struct CGTryNoteList { 63 Vector<JSTryNote> list; CGTryNoteListCGTryNoteList64 explicit CGTryNoteList(JSContext* cx) : list(cx) {} 65 66 MOZ_MUST_USE bool append(JSTryNoteKind kind, uint32_t stackDepth, 67 size_t start, size_t end); lengthCGTryNoteList68 size_t length() const { return list.length(); } 69 void finish(TryNoteArray* array); 70 }; 71 72 struct CGScopeNote : public ScopeNote { 73 // The end offset. Used to compute the length; may need adjusting first if 74 // in the prologue. 75 uint32_t end; 76 77 // Is the start offset in the prologue? 78 bool startInPrologue; 79 80 // Is the end offset in the prologue? 81 bool endInPrologue; 82 }; 83 84 struct CGScopeNoteList { 85 Vector<CGScopeNote> list; CGScopeNoteListCGScopeNoteList86 explicit CGScopeNoteList(JSContext* cx) : list(cx) {} 87 88 MOZ_MUST_USE bool append(uint32_t scopeIndex, uint32_t offset, 89 bool inPrologue, uint32_t parent); 90 void recordEnd(uint32_t index, uint32_t offset, bool inPrologue); lengthCGScopeNoteList91 size_t length() const { return list.length(); } 92 void finish(ScopeNoteArray* array, uint32_t prologueLength); 93 }; 94 95 struct CGYieldAndAwaitOffsetList { 96 Vector<uint32_t> list; 97 uint32_t numYields; 98 uint32_t numAwaits; CGYieldAndAwaitOffsetListCGYieldAndAwaitOffsetList99 explicit CGYieldAndAwaitOffsetList(JSContext* cx) 100 : list(cx), numYields(0), numAwaits(0) {} 101 appendCGYieldAndAwaitOffsetList102 MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); } lengthCGYieldAndAwaitOffsetList103 size_t length() const { return list.length(); } 104 void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength); 105 }; 106 107 static constexpr size_t MaxBytecodeLength = INT32_MAX; 108 static constexpr size_t MaxSrcNotesLength = INT32_MAX; 109 110 // Have a few inline elements, so as to avoid heap allocation for tiny 111 // sequences. See bug 1390526. 112 typedef Vector<jsbytecode, 64> BytecodeVector; 113 typedef Vector<jssrcnote, 64> SrcNotesVector; 114 115 // Linked list of jump instructions that need to be patched. The linked list is 116 // stored in the bytes of the incomplete bytecode that will be patched, so no 117 // extra memory is needed, and patching the instructions destroys the list. 118 // 119 // Example: 120 // 121 // JumpList brList; 122 // if (!emitJump(JSOP_IFEQ, &brList)) 123 // return false; 124 // ... 125 // JumpTarget label; 126 // if (!emitJumpTarget(&label)) 127 // return false; 128 // ... 129 // if (!emitJump(JSOP_GOTO, &brList)) 130 // return false; 131 // ... 132 // patchJumpsToTarget(brList, label); 133 // 134 // +-> -1 135 // | 136 // | 137 // ifeq .. <+ + +-+ ifeq .. 138 // .. | | .. 139 // label: | +-> label: 140 // jumptarget | | jumptarget 141 // .. | | .. 142 // goto .. <+ + +-+ goto .. <+ 143 // | | 144 // | | 145 // + + 146 // brList brList 147 // 148 // | ^ 149 // +------- patchJumpsToTarget -------+ 150 // 151 152 // Offset of a jump target instruction, used for patching jump instructions. 153 struct JumpTarget { 154 ptrdiff_t offset; 155 }; 156 157 struct JumpList { 158 // -1 is used to mark the end of jump lists. JumpListJumpList159 JumpList() : offset(-1) {} 160 ptrdiff_t offset; 161 162 // Add a jump instruction to the list. 163 void push(jsbytecode* code, ptrdiff_t jumpOffset); 164 165 // Patch all jump instructions in this list to jump to `target`. This 166 // clobbers the list. 167 void patchAll(jsbytecode* code, JumpTarget target); 168 }; 169 170 // Used to control whether JSOP_CALL_IGNORES_RV is emitted for function calls. 171 enum class ValueUsage { 172 // Assume the value of the current expression may be used. This is always 173 // correct but prohibits JSOP_CALL_IGNORES_RV. 174 WantValue, 175 176 // Pass this when emitting an expression if the expression's value is 177 // definitely unused by later instructions. You must make sure the next 178 // instruction is JSOP_POP, a jump to a JSOP_POP, or something similar. 179 IgnoreValue 180 }; 181 182 struct MOZ_STACK_CLASS BytecodeEmitter { 183 class TDZCheckCache; 184 class NestableControl; 185 class EmitterScope; 186 187 SharedContext* const 188 sc; /* context shared between parsing and bytecode generation */ 189 190 JSContext* const cx; 191 192 BytecodeEmitter* const parent; /* enclosing function or global context */ 193 194 Rooted<JSScript*> script; /* the JSScript we're ultimately producing */ 195 196 Rooted<LazyScript*> lazyScript; /* the lazy script if mode is LazyFunction, 197 nullptr otherwise. */ 198 199 struct EmitSection { 200 BytecodeVector code; /* bytecode */ 201 SrcNotesVector notes; /* source notes, see below */ 202 ptrdiff_t lastNoteOffset; /* code offset for last source note */ 203 204 // Line number for srcnotes. 205 // 206 // WARNING: If this becomes out of sync with already-emitted srcnotes, 207 // we can get undefined behavior. 208 uint32_t currentLine; 209 210 // Zero-based column index on currentLine of last SRC_COLSPAN-annotated 211 // opcode. 212 // 213 // WARNING: If this becomes out of sync with already-emitted srcnotes, 214 // we can get undefined behavior. 215 uint32_t lastColumn; 216 217 JumpTarget lastTarget; // Last jump target emitted. 218 EmitSectionBytecodeEmitter::EmitSection219 EmitSection(JSContext* cx, uint32_t lineNum) 220 : code(cx), 221 notes(cx), 222 lastNoteOffset(0), 223 currentLine(lineNum), 224 lastColumn(0), 225 lastTarget{-1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH)} {} 226 }; 227 EmitSection prologue, main, *current; 228 229 EitherParser<FullParseHandler> parser; 230 231 PooledMapPtr<AtomIndexMap> atomIndices; /* literals indexed for mapping */ 232 unsigned firstLine; /* first line, for JSScript::initFromEmitter */ 233 234 uint32_t maxFixedSlots; /* maximum number of fixed frame slots so far */ 235 uint32_t maxStackDepth; /* maximum number of expression stack slots so far */ 236 237 int32_t stackDepth; /* current stack depth in script frame */ 238 239 unsigned emitLevel; /* emitTree recursion level */ 240 241 uint32_t bodyScopeIndex; /* index into scopeList of the body scope */ 242 243 EmitterScope* varEmitterScope; 244 NestableControl* innermostNestableControl; 245 EmitterScope* innermostEmitterScope_; 246 TDZCheckCache* innermostTDZCheckCache; 247 248 #ifdef DEBUG 249 bool unstableEmitterScope; 250 251 friend class AutoCheckUnstableEmitterScope; 252 #endif 253 innermostEmitterScopeBytecodeEmitter254 EmitterScope* innermostEmitterScope() const { 255 MOZ_ASSERT(!unstableEmitterScope); 256 return innermostEmitterScopeNoCheck(); 257 } innermostEmitterScopeNoCheckBytecodeEmitter258 EmitterScope* innermostEmitterScopeNoCheck() const { 259 return innermostEmitterScope_; 260 } 261 262 CGConstList constList; /* constants to be included with the script */ 263 CGObjectList objectList; /* list of emitted objects */ 264 CGScopeList scopeList; /* list of emitted scopes */ 265 CGTryNoteList tryNoteList; /* list of emitted try notes */ 266 CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */ 267 268 /* 269 * For each yield or await op, map the yield and await index (stored as 270 * bytecode operand) to the offset of the next op. 271 */ 272 CGYieldAndAwaitOffsetList yieldAndAwaitOffsetList; 273 274 uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */ 275 276 bool 277 hasSingletons : 1; /* script contains singleton initializer JSOP_OBJECT */ 278 279 bool hasTryFinally : 1; /* script contains finally block */ 280 281 bool emittingRunOnceLambda : 1; /* true while emitting a lambda which is only 282 expected to run once. */ 283 284 bool isRunOnceLambda(); 285 286 enum EmitterMode { 287 Normal, 288 289 /* 290 * Emit JSOP_GETINTRINSIC instead of JSOP_GETNAME and assert that 291 * JSOP_GETNAME and JSOP_*GNAME don't ever get emitted. See the comment 292 * for the field |selfHostingMode| in Parser.h for details. 293 */ 294 SelfHosting, 295 296 /* 297 * Check the static scope chain of the root function for resolving free 298 * variable accesses in the script. 299 */ 300 LazyFunction 301 }; 302 303 const EmitterMode emitterMode; 304 305 // The end location of a function body that is being emitted. 306 MOZ_INIT_OUTSIDE_CTOR uint32_t functionBodyEndPos; 307 // Whether functionBodyEndPos was set. 308 bool functionBodyEndPosSet; 309 310 /* 311 * Note that BytecodeEmitters are magic: they own the arena "top-of-stack" 312 * space above their tempMark points. This means that you cannot alloc from 313 * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter 314 * destruction. 315 */ 316 BytecodeEmitter(BytecodeEmitter* parent, 317 const EitherParser<FullParseHandler>& parser, 318 SharedContext* sc, HandleScript script, 319 Handle<LazyScript*> lazyScript, uint32_t lineNum, 320 EmitterMode emitterMode = Normal); 321 322 template <typename CharT> 323 BytecodeEmitter(BytecodeEmitter* parent, 324 Parser<FullParseHandler, CharT>* parser, SharedContext* sc, 325 HandleScript script, Handle<LazyScript*> lazyScript, 326 uint32_t lineNum, EmitterMode emitterMode = Normal) BytecodeEmitterBytecodeEmitter327 : BytecodeEmitter(parent, EitherParser<FullParseHandler>(parser), sc, 328 script, lazyScript, lineNum, emitterMode) {} 329 330 // An alternate constructor that uses a TokenPos for the starting 331 // line and that sets functionBodyEndPos as well. 332 BytecodeEmitter(BytecodeEmitter* parent, 333 const EitherParser<FullParseHandler>& parser, 334 SharedContext* sc, HandleScript script, 335 Handle<LazyScript*> lazyScript, TokenPos bodyPosition, 336 EmitterMode emitterMode = Normal); 337 338 template <typename CharT> 339 BytecodeEmitter(BytecodeEmitter* parent, 340 Parser<FullParseHandler, CharT>* parser, SharedContext* sc, 341 HandleScript script, Handle<LazyScript*> lazyScript, 342 TokenPos bodyPosition, EmitterMode emitterMode = Normal) BytecodeEmitterBytecodeEmitter343 : BytecodeEmitter(parent, EitherParser<FullParseHandler>(parser), sc, 344 script, lazyScript, bodyPosition, emitterMode) {} 345 346 MOZ_MUST_USE bool init(); 347 348 template <typename Predicate /* (NestableControl*) -> bool */> 349 NestableControl* findInnermostNestableControl(Predicate predicate) const; 350 351 template <typename T> 352 T* findInnermostNestableControl() const; 353 354 template <typename T, typename Predicate /* (T*) -> bool */> 355 T* findInnermostNestableControl(Predicate predicate) const; 356 357 NameLocation lookupName(JSAtom* name); 358 359 // To implement Annex B and the formal parameter defaults scope semantics 360 // requires accessing names that would otherwise be shadowed. This method 361 // returns the access location of a name that is known to be bound in a 362 // target scope. 363 mozilla::Maybe<NameLocation> locationOfNameBoundInScope(JSAtom* name, 364 EmitterScope* target); 365 366 // Get the location of a name known to be bound in the function scope, 367 // starting at the source scope. 368 mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope( 369 JSAtom* name, EmitterScope* source); 370 locationOfNameBoundInFunctionScopeBytecodeEmitter371 mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope( 372 JSAtom* name) { 373 return locationOfNameBoundInFunctionScope(name, innermostEmitterScope()); 374 } 375 setVarEmitterScopeBytecodeEmitter376 void setVarEmitterScope(EmitterScope* emitterScope) { 377 MOZ_ASSERT(emitterScope); 378 MOZ_ASSERT(!varEmitterScope); 379 varEmitterScope = emitterScope; 380 } 381 outermostScopeBytecodeEmitter382 Scope* outermostScope() const { return scopeList.vector[0]; } 383 Scope* innermostScope() const; 384 385 MOZ_ALWAYS_INLINE makeAtomIndexBytecodeEmitter386 MOZ_MUST_USE bool makeAtomIndex(JSAtom* atom, uint32_t* indexp) { 387 MOZ_ASSERT(atomIndices); 388 AtomIndexMap::AddPtr p = atomIndices->lookupForAdd(atom); 389 if (p) { 390 *indexp = p->value(); 391 return true; 392 } 393 394 uint32_t index = atomIndices->count(); 395 if (!atomIndices->add(p, atom, index)) return false; 396 397 *indexp = index; 398 return true; 399 } 400 401 bool isInLoop(); 402 MOZ_MUST_USE bool checkSingletonContext(); 403 404 // Check whether our function is in a run-once context (a toplevel 405 // run-one script or a run-once lambda). 406 MOZ_MUST_USE bool checkRunOnceContext(); 407 408 bool needsImplicitThis(); 409 410 MOZ_MUST_USE bool maybeSetDisplayURL(); 411 MOZ_MUST_USE bool maybeSetSourceMap(); 412 void tellDebuggerAboutCompiledScript(JSContext* cx); 413 414 inline TokenStreamAnyChars& tokenStream(); 415 codeBytecodeEmitter416 BytecodeVector& code() const { return current->code; } codeBytecodeEmitter417 jsbytecode* code(ptrdiff_t offset) const { 418 return current->code.begin() + offset; 419 } offsetBytecodeEmitter420 ptrdiff_t offset() const { 421 return current->code.end() - current->code.begin(); 422 } prologueOffsetBytecodeEmitter423 ptrdiff_t prologueOffset() const { 424 return prologue.code.end() - prologue.code.begin(); 425 } switchToMainBytecodeEmitter426 void switchToMain() { current = &main; } switchToPrologueBytecodeEmitter427 void switchToPrologue() { current = &prologue; } inPrologueBytecodeEmitter428 bool inPrologue() const { return current == &prologue; } 429 notesBytecodeEmitter430 SrcNotesVector& notes() const { return current->notes; } lastNoteOffsetBytecodeEmitter431 ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; } currentLineBytecodeEmitter432 unsigned currentLine() const { return current->currentLine; } 433 434 // Check if the last emitted opcode is a jump target. lastOpcodeIsJumpTargetBytecodeEmitter435 bool lastOpcodeIsJumpTarget() const { 436 return offset() - current->lastTarget.offset == 437 ptrdiff_t(JSOP_JUMPTARGET_LENGTH); 438 } 439 440 // JumpTarget should not be part of the emitted statement, as they can be 441 // aliased by multiple statements. If we included the jump target as part of 442 // the statement we might have issues where the enclosing statement might 443 // not contain all the opcodes of the enclosed statements. lastNonJumpTargetOffsetBytecodeEmitter444 ptrdiff_t lastNonJumpTargetOffset() const { 445 return lastOpcodeIsJumpTarget() ? current->lastTarget.offset : offset(); 446 } 447 setFunctionBodyEndPosBytecodeEmitter448 void setFunctionBodyEndPos(TokenPos pos) { 449 functionBodyEndPos = pos.end; 450 functionBodyEndPosSet = true; 451 } 452 453 void reportError(ParseNode* pn, unsigned errorNumber, ...); 454 bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...); 455 456 // If pn contains a useful expression, return true with *answer set to true. 457 // If pn contains a useless expression, return true with *answer set to 458 // false. Return false on error. 459 // 460 // The caller should initialize *answer to false and invoke this function on 461 // an expression statement or similar subtree to decide whether the tree 462 // could produce code that has any side effects. For an expression 463 // statement, we define useless code as code with no side effects, because 464 // the main effect, the value left on the stack after the code executes, 465 // will be discarded by a pop bytecode. 466 MOZ_MUST_USE bool checkSideEffects(ParseNode* pn, bool* answer); 467 468 #ifdef DEBUG 469 MOZ_MUST_USE bool checkStrictOrSloppy(JSOp op); 470 #endif 471 472 // Append a new source note of the given type (and therefore size) to the 473 // notes dynamic array, updating noteCount. Return the new note's index 474 // within the array pointed at by current->notes as outparam. 475 MOZ_MUST_USE bool newSrcNote(SrcNoteType type, unsigned* indexp = nullptr); 476 MOZ_MUST_USE bool newSrcNote2(SrcNoteType type, ptrdiff_t offset, 477 unsigned* indexp = nullptr); 478 MOZ_MUST_USE bool newSrcNote3(SrcNoteType type, ptrdiff_t offset1, 479 ptrdiff_t offset2, unsigned* indexp = nullptr); 480 481 void copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes); 482 MOZ_MUST_USE bool setSrcNoteOffset(unsigned index, unsigned which, 483 ptrdiff_t offset); 484 485 // NB: this function can add at most one extra extended delta note. 486 MOZ_MUST_USE bool addToSrcNoteDelta(jssrcnote* sn, ptrdiff_t delta); 487 488 // Finish taking source notes in cx's notePool. If successful, the final 489 // source note count is stored in the out outparam. 490 MOZ_MUST_USE bool finishTakingSrcNotes(uint32_t* out); 491 492 // Control whether emitTree emits a line number note. 493 enum EmitLineNumberNote { EMIT_LINENOTE, SUPPRESS_LINENOTE }; 494 495 // Emit code for the tree rooted at pn. 496 MOZ_MUST_USE bool emitTree(ParseNode* pn, 497 ValueUsage valueUsage = ValueUsage::WantValue, 498 EmitLineNumberNote emitLineNote = EMIT_LINENOTE); 499 500 // Emit code for the tree rooted at pn with its own TDZ cache. 501 MOZ_MUST_USE bool emitTreeInBranch( 502 ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); 503 504 // Emit global, eval, or module code for tree rooted at body. Always 505 // encompasses the entire source. 506 MOZ_MUST_USE bool emitScript(ParseNode* body); 507 508 // Emit function code for the tree rooted at body. 509 MOZ_MUST_USE bool emitFunctionScript(ParseNode* body); 510 511 // If op is JOF_TYPESET (see the type barriers comment in TypeInference.h), 512 // reserve a type set to store its result. 513 void checkTypeSet(JSOp op); 514 515 void updateDepth(ptrdiff_t target); 516 MOZ_MUST_USE bool updateLineNumberNotes(uint32_t offset); 517 MOZ_MUST_USE bool updateSourceCoordNotes(uint32_t offset); 518 519 JSOp strictifySetNameOp(JSOp op); 520 521 MOZ_MUST_USE bool emitCheck(ptrdiff_t delta, ptrdiff_t* offset); 522 523 // Emit one bytecode. 524 MOZ_MUST_USE bool emit1(JSOp op); 525 526 // Emit two bytecodes, an opcode (op) with a byte of immediate operand 527 // (op1). 528 MOZ_MUST_USE bool emit2(JSOp op, uint8_t op1); 529 530 // Emit three bytecodes, an opcode with two bytes of immediate operands. 531 MOZ_MUST_USE bool emit3(JSOp op, jsbytecode op1, jsbytecode op2); 532 533 // Helper to emit JSOP_DUPAT. The argument is the value's depth on the 534 // JS stack, as measured from the top. 535 MOZ_MUST_USE bool emitDupAt(unsigned slotFromTop); 536 537 // Helper to emit JSOP_POP or JSOP_POPN. 538 MOZ_MUST_USE bool emitPopN(unsigned n); 539 540 // Helper to emit JSOP_CHECKISOBJ. 541 MOZ_MUST_USE bool emitCheckIsObj(CheckIsObjectKind kind); 542 543 // Helper to emit JSOP_CHECKISCALLABLE. 544 MOZ_MUST_USE bool emitCheckIsCallable(CheckIsCallableKind kind); 545 546 // Push whether the value atop of the stack is non-undefined and non-null. 547 MOZ_MUST_USE bool emitPushNotUndefinedOrNull(); 548 549 // Emit a bytecode followed by an uint16 immediate operand stored in 550 // big-endian order. 551 MOZ_MUST_USE bool emitUint16Operand(JSOp op, uint32_t operand); 552 553 // Emit a bytecode followed by an uint32 immediate operand. 554 MOZ_MUST_USE bool emitUint32Operand(JSOp op, uint32_t operand); 555 556 // Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand. 557 MOZ_MUST_USE bool emitN(JSOp op, size_t extra, ptrdiff_t* offset = nullptr); 558 559 MOZ_MUST_USE bool emitNumberOp(double dval); 560 561 MOZ_MUST_USE bool emitThisLiteral(ParseNode* pn); 562 MOZ_MUST_USE bool emitGetFunctionThis(ParseNode* pn); 563 MOZ_MUST_USE bool emitGetThisForSuperBase(ParseNode* pn); 564 MOZ_MUST_USE bool emitSetThis(ParseNode* pn); 565 MOZ_MUST_USE bool emitCheckDerivedClassConstructorReturn(); 566 567 // Handle jump opcodes and jump targets. 568 MOZ_MUST_USE bool emitJumpTarget(JumpTarget* target); 569 MOZ_MUST_USE bool emitJumpNoFallthrough(JSOp op, JumpList* jump); 570 MOZ_MUST_USE bool emitJump(JSOp op, JumpList* jump); 571 MOZ_MUST_USE bool emitBackwardJump(JSOp op, JumpTarget target, JumpList* jump, 572 JumpTarget* fallthrough); 573 void patchJumpsToTarget(JumpList jump, JumpTarget target); 574 MOZ_MUST_USE bool emitJumpTargetAndPatch(JumpList jump); 575 576 MOZ_MUST_USE bool emitCall(JSOp op, uint16_t argc, ParseNode* pn = nullptr); 577 MOZ_MUST_USE bool emitCallIncDec(ParseNode* incDec); 578 579 MOZ_MUST_USE bool emitLoopHead(ParseNode* nextpn, JumpTarget* top); 580 MOZ_MUST_USE bool emitLoopEntry(ParseNode* nextpn, JumpList entryJump); 581 582 MOZ_MUST_USE bool emitGoto(NestableControl* target, JumpList* jumplist, 583 SrcNoteType noteType = SRC_NULL); 584 585 MOZ_MUST_USE bool emitIndex32(JSOp op, uint32_t index); 586 MOZ_MUST_USE bool emitIndexOp(JSOp op, uint32_t index); 587 588 MOZ_MUST_USE bool emitAtomOp(JSAtom* atom, JSOp op); 589 MOZ_MUST_USE bool emitAtomOp(ParseNode* pn, JSOp op); 590 591 MOZ_MUST_USE bool emitArrayLiteral(ParseNode* pn); 592 MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count); 593 594 MOZ_MUST_USE bool emitInternedScopeOp(uint32_t index, JSOp op); 595 MOZ_MUST_USE bool emitInternedObjectOp(uint32_t index, JSOp op); 596 MOZ_MUST_USE bool emitObjectOp(ObjectBox* objbox, JSOp op); 597 MOZ_MUST_USE bool emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, 598 JSOp op); 599 MOZ_MUST_USE bool emitRegExp(uint32_t index); 600 601 MOZ_NEVER_INLINE MOZ_MUST_USE bool emitFunction(ParseNode* pn, 602 bool needsProto = false); 603 MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ParseNode* pn); 604 605 MOZ_MUST_USE bool replaceNewInitWithNewObject(JSObject* obj, 606 ptrdiff_t offset); 607 608 MOZ_MUST_USE bool emitHoistedFunctionsInList(ParseNode* pn); 609 610 MOZ_MUST_USE bool emitPropertyList(ParseNode* pn, 611 MutableHandlePlainObject objp, 612 PropListType type); 613 614 // To catch accidental misuse, emitUint16Operand/emit3 assert that they are 615 // not used to unconditionally emit JSOP_GETLOCAL. Variable access should 616 // instead be emitted using EmitVarOp. In special cases, when the caller 617 // definitely knows that a given local slot is unaliased, this function may be 618 // used as a non-asserting version of emitUint16Operand. 619 MOZ_MUST_USE bool emitLocalOp(JSOp op, uint32_t slot); 620 621 MOZ_MUST_USE bool emitArgOp(JSOp op, uint16_t slot); 622 MOZ_MUST_USE bool emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec); 623 624 MOZ_MUST_USE bool emitGetNameAtLocation(JSAtom* name, const NameLocation& loc, 625 bool callContext = false); 626 MOZ_MUST_USE bool emitGetNameAtLocationForCompoundAssignment( 627 JSAtom* name, const NameLocation& loc); 628 MOZ_MUST_USE bool emitGetName(JSAtom* name, bool callContext = false) { 629 return emitGetNameAtLocation(name, lookupName(name), callContext); 630 } 631 MOZ_MUST_USE bool emitGetName(ParseNode* pn, bool callContext = false); 632 633 template <typename RHSEmitter> 634 MOZ_MUST_USE bool emitSetOrInitializeNameAtLocation(HandleAtom name, 635 const NameLocation& loc, 636 RHSEmitter emitRhs, 637 bool initialize); 638 template <typename RHSEmitter> emitSetOrInitializeNameBytecodeEmitter639 MOZ_MUST_USE bool emitSetOrInitializeName(HandleAtom name, RHSEmitter emitRhs, 640 bool initialize) { 641 return emitSetOrInitializeNameAtLocation(name, lookupName(name), emitRhs, 642 initialize); 643 } 644 template <typename RHSEmitter> emitSetNameBytecodeEmitter645 MOZ_MUST_USE bool emitSetName(ParseNode* pn, RHSEmitter emitRhs) { 646 RootedAtom name(cx, pn->name()); 647 return emitSetName(name, emitRhs); 648 } 649 template <typename RHSEmitter> emitSetNameBytecodeEmitter650 MOZ_MUST_USE bool emitSetName(HandleAtom name, RHSEmitter emitRhs) { 651 return emitSetOrInitializeName(name, emitRhs, false); 652 } 653 template <typename RHSEmitter> emitInitializeNameBytecodeEmitter654 MOZ_MUST_USE bool emitInitializeName(ParseNode* pn, RHSEmitter emitRhs) { 655 RootedAtom name(cx, pn->name()); 656 return emitInitializeName(name, emitRhs); 657 } 658 template <typename RHSEmitter> emitInitializeNameBytecodeEmitter659 MOZ_MUST_USE bool emitInitializeName(HandleAtom name, RHSEmitter emitRhs) { 660 return emitSetOrInitializeName(name, emitRhs, true); 661 } 662 663 MOZ_MUST_USE bool emitTDZCheckIfNeeded(JSAtom* name, const NameLocation& loc); 664 665 MOZ_MUST_USE bool emitNameIncDec(ParseNode* pn); 666 667 MOZ_MUST_USE bool emitDeclarationList(ParseNode* decls); 668 MOZ_MUST_USE bool emitSingleDeclaration(ParseNode* decls, ParseNode* decl, 669 ParseNode* initializer); 670 671 MOZ_MUST_USE bool emitNewInit(JSProtoKey key); 672 MOZ_MUST_USE bool emitSingletonInitialiser(ParseNode* pn); 673 674 MOZ_MUST_USE bool emitPrepareIteratorResult(); 675 MOZ_MUST_USE bool emitFinishIteratorResult(bool done); 676 MOZ_MUST_USE bool iteratorResultShape(unsigned* shape); 677 emitGetDotGeneratorInInnermostScopeBytecodeEmitter678 MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() { 679 return emitGetDotGeneratorInScope(*innermostEmitterScope()); 680 } 681 MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope); 682 683 MOZ_MUST_USE bool emitInitialYield(ParseNode* pn); 684 MOZ_MUST_USE bool emitYield(ParseNode* pn); 685 MOZ_MUST_USE bool emitYieldOp(JSOp op); 686 MOZ_MUST_USE bool emitYieldStar(ParseNode* iter); emitAwaitInInnermostScopeBytecodeEmitter687 MOZ_MUST_USE bool emitAwaitInInnermostScope() { 688 return emitAwaitInScope(*innermostEmitterScope()); 689 } 690 MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn); 691 MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope); 692 693 MOZ_MUST_USE bool emitPropLHS(ParseNode* pn); 694 MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op); 695 MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn); 696 697 MOZ_MUST_USE bool emitAsyncWrapperLambda(unsigned index, bool isArrow); 698 MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, 699 bool isArrow, bool isGenerator); 700 701 MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName); 702 703 // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM 704 // opcode onto the stack in the right order. In the case of SETELEM, the 705 // value to be assigned must already be pushed. 706 enum class EmitElemOption { Get, Set, Call, IncDec, CompoundAssign, Ref }; 707 MOZ_MUST_USE bool emitElemOperands(ParseNode* pn, EmitElemOption opts); 708 709 MOZ_MUST_USE bool emitElemOpBase(JSOp op); 710 MOZ_MUST_USE bool emitElemOp(ParseNode* pn, JSOp op); 711 MOZ_MUST_USE bool emitElemIncDec(ParseNode* pn); 712 713 MOZ_MUST_USE bool emitCatch(ParseNode* pn); 714 MOZ_MUST_USE bool emitIf(ParseNode* pn); 715 MOZ_MUST_USE bool emitWith(ParseNode* pn); 716 717 MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLabeledStatement( 718 const LabeledStatement* pn); 719 MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(ParseNode* pn); 720 MOZ_MUST_USE bool emitLexicalScopeBody( 721 ParseNode* body, EmitLineNumberNote emitLineNote = EMIT_LINENOTE); 722 MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(ParseNode* pn); 723 MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(ParseNode* pn); 724 725 enum DestructuringFlavor { 726 // Destructuring into a declaration. 727 DestructuringDeclaration, 728 729 // Destructuring into a formal parameter, when the formal parameters 730 // contain an expression that might be evaluated, and thus require 731 // this destructuring to assign not into the innermost scope that 732 // contains the function body's vars, but into its enclosing scope for 733 // parameter expressions. 734 DestructuringFormalParameterInVarScope, 735 736 // Destructuring as part of an AssignmentExpression. 737 DestructuringAssignment 738 }; 739 740 // emitDestructuringLHSRef emits the lhs expression's reference. 741 // If the lhs expression is object property |OBJ.prop|, it emits |OBJ|. 742 // If it's object element |OBJ[ELEM]|, it emits |OBJ| and |ELEM|. 743 // If there's nothing to evaluate for the reference, it emits nothing. 744 // |emitted| parameter receives the number of values pushed onto the stack. 745 MOZ_MUST_USE bool emitDestructuringLHSRef(ParseNode* target, size_t* emitted); 746 747 // emitSetOrInitializeDestructuring assumes the lhs expression's reference 748 // and the to-be-destructured value has been pushed on the stack. It emits 749 // code to destructure a single lhs expression (either a name or a compound 750 // []/{} expression). 751 MOZ_MUST_USE bool emitSetOrInitializeDestructuring(ParseNode* target, 752 DestructuringFlavor flav); 753 754 // emitDestructuringObjRestExclusionSet emits the property exclusion set 755 // for the rest-property in an object pattern. 756 MOZ_MUST_USE bool emitDestructuringObjRestExclusionSet(ParseNode* pattern); 757 758 // emitDestructuringOps assumes the to-be-destructured value has been 759 // pushed on the stack and emits code to destructure each part of a [] or 760 // {} lhs expression. 761 MOZ_MUST_USE bool emitDestructuringOps(ParseNode* pattern, 762 DestructuringFlavor flav); 763 MOZ_MUST_USE bool emitDestructuringOpsArray(ParseNode* pattern, 764 DestructuringFlavor flav); 765 MOZ_MUST_USE bool emitDestructuringOpsObject(ParseNode* pattern, 766 DestructuringFlavor flav); 767 768 typedef bool (*DestructuringDeclEmitter)(BytecodeEmitter* bce, ParseNode* pn); 769 770 template <typename NameEmitter> 771 MOZ_MUST_USE bool emitDestructuringDeclsWithEmitter(ParseNode* pattern, 772 NameEmitter emitName); 773 774 enum class CopyOption { Filtered, Unfiltered }; 775 776 // Calls either the |CopyDataProperties| or the 777 // |CopyDataPropertiesUnfiltered| intrinsic function, consumes three (or 778 // two in the latter case) elements from the stack. 779 MOZ_MUST_USE bool emitCopyDataProperties(CopyOption option); 780 781 // emitIterator expects the iterable to already be on the stack. 782 // It will replace that stack value with the corresponding iterator 783 MOZ_MUST_USE bool emitIterator(); 784 785 MOZ_MUST_USE bool emitAsyncIterator(); 786 787 // Pops iterator from the top of the stack. Pushes the result of |.next()| 788 // onto the stack. 789 MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, 790 IteratorKind kind = IteratorKind::Sync, 791 bool allowSelfHosted = false); 792 MOZ_MUST_USE bool emitIteratorCloseInScope( 793 EmitterScope& currentScope, IteratorKind iterKind = IteratorKind::Sync, 794 CompletionKind completionKind = CompletionKind::Normal, 795 bool allowSelfHosted = false); 796 MOZ_MUST_USE bool emitIteratorCloseInInnermostScope( 797 IteratorKind iterKind = IteratorKind::Sync, 798 CompletionKind completionKind = CompletionKind::Normal, 799 bool allowSelfHosted = false) { 800 return emitIteratorCloseInScope(*innermostEmitterScope(), iterKind, 801 completionKind, allowSelfHosted); 802 } 803 804 template <typename InnerEmitter> 805 MOZ_MUST_USE bool wrapWithDestructuringIteratorCloseTryNote( 806 int32_t iterDepth, InnerEmitter emitter); 807 808 // Check if the value on top of the stack is "undefined". If so, replace 809 // that value on the stack with the value defined by |defaultExpr|. 810 // |pattern| is a lhs node of the default expression. If it's an 811 // identifier and |defaultExpr| is an anonymous function, |SetFunctionName| 812 // is called at compile time. 813 MOZ_MUST_USE bool emitDefault(ParseNode* defaultExpr, ParseNode* pattern); 814 815 MOZ_MUST_USE bool setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name, 816 FunctionPrefixKind prefixKind); 817 818 MOZ_MUST_USE bool emitInitializer(ParseNode* initializer, ParseNode* pattern); 819 MOZ_MUST_USE bool emitInitializerInBranch(ParseNode* initializer, 820 ParseNode* pattern); 821 822 MOZ_MUST_USE bool emitCallSiteObject(ParseNode* pn); 823 MOZ_MUST_USE bool emitTemplateString(ParseNode* pn); 824 MOZ_MUST_USE bool emitAssignment(ParseNode* lhs, ParseNodeKind pnk, 825 ParseNode* rhs); 826 827 MOZ_MUST_USE bool emitReturn(ParseNode* pn); 828 MOZ_MUST_USE bool emitExpressionStatement(ParseNode* pn); 829 MOZ_MUST_USE bool emitStatementList(ParseNode* pn); 830 831 MOZ_MUST_USE bool emitDeleteName(ParseNode* pn); 832 MOZ_MUST_USE bool emitDeleteProperty(ParseNode* pn); 833 MOZ_MUST_USE bool emitDeleteElement(ParseNode* pn); 834 MOZ_MUST_USE bool emitDeleteExpression(ParseNode* pn); 835 836 // |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR. 837 MOZ_MUST_USE bool emitTypeof(ParseNode* node, JSOp op); 838 839 MOZ_MUST_USE bool emitUnary(ParseNode* pn); 840 MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn); 841 MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn); 842 MOZ_MUST_USE bool emitLogical(ParseNode* pn); 843 MOZ_MUST_USE bool emitSequenceExpr( 844 ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); 845 846 MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn); 847 848 MOZ_MUST_USE bool emitConditionalExpression( 849 ConditionalExpression& conditional, 850 ValueUsage valueUsage = ValueUsage::WantValue); 851 852 bool isRestParameter(ParseNode* pn); 853 854 MOZ_MUST_USE bool emitCallOrNew( 855 ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); 856 MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn); 857 MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn); 858 MOZ_MUST_USE bool emitSelfHostedForceInterpreter(); 859 MOZ_MUST_USE bool emitSelfHostedAllowContentIter(ParseNode* pn); 860 MOZ_MUST_USE bool emitSelfHostedDefineDataProperty(ParseNode* pn); 861 MOZ_MUST_USE bool emitSelfHostedGetPropertySuper(ParseNode* pn); 862 MOZ_MUST_USE bool emitSelfHostedHasOwn(ParseNode* pn); 863 864 MOZ_MUST_USE bool emitDo(ParseNode* pn); 865 MOZ_MUST_USE bool emitWhile(ParseNode* pn); 866 867 MOZ_MUST_USE bool emitFor(ParseNode* pn, 868 EmitterScope* headLexicalEmitterScope = nullptr); 869 MOZ_MUST_USE bool emitCStyleFor(ParseNode* pn, 870 EmitterScope* headLexicalEmitterScope); 871 MOZ_MUST_USE bool emitForIn(ParseNode* pn, 872 EmitterScope* headLexicalEmitterScope); 873 MOZ_MUST_USE bool emitForOf(ParseNode* pn, 874 EmitterScope* headLexicalEmitterScope); 875 876 MOZ_MUST_USE bool emitInitializeForInOrOfTarget(ParseNode* forHead); 877 878 MOZ_MUST_USE bool emitBreak(PropertyName* label); 879 MOZ_MUST_USE bool emitContinue(PropertyName* label); 880 881 MOZ_MUST_USE bool emitFunctionFormalParametersAndBody(ParseNode* pn); 882 MOZ_MUST_USE bool emitFunctionFormalParameters(ParseNode* pn); 883 MOZ_MUST_USE bool emitInitializeFunctionSpecialNames(); 884 MOZ_MUST_USE bool emitFunctionBody(ParseNode* pn); 885 MOZ_MUST_USE bool emitLexicalInitialization(ParseNode* pn); 886 887 // Emit bytecode for the spread operator. 888 // 889 // emitSpread expects the current index (I) of the array, the array itself 890 // and the iterator to be on the stack in that order (iterator on the bottom). 891 // It will pop the iterator and I, then iterate over the iterator by calling 892 // |.next()| and put the results into the I-th element of array with 893 // incrementing I, then push the result I (it will be original I + 894 // iteration count). The stack after iteration will look like |ARRAY INDEX|. 895 MOZ_MUST_USE bool emitSpread(bool allowSelfHosted = false); 896 897 MOZ_MUST_USE bool emitClass(ParseNode* pn); 898 MOZ_MUST_USE bool emitSuperPropLHS(ParseNode* superBase, bool isCall = false); 899 MOZ_MUST_USE bool emitSuperPropOp(ParseNode* pn, JSOp op, 900 bool isCall = false); 901 MOZ_MUST_USE bool emitSuperElemOperands( 902 ParseNode* pn, EmitElemOption opts = EmitElemOption::Get); 903 MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, 904 bool isCall = false); 905 906 MOZ_MUST_USE bool emitCallee(ParseNode* callee, ParseNode* call, 907 bool* callop); 908 909 MOZ_MUST_USE bool emitPipeline(ParseNode* pn); 910 911 MOZ_MUST_USE bool emitExportDefault(ParseNode* pn); 912 }; 913 914 class MOZ_RAII AutoCheckUnstableEmitterScope { 915 #ifdef DEBUG 916 bool prev_; 917 BytecodeEmitter* bce_; 918 #endif 919 920 public: 921 AutoCheckUnstableEmitterScope() = delete; AutoCheckUnstableEmitterScope(BytecodeEmitter * bce)922 explicit AutoCheckUnstableEmitterScope(BytecodeEmitter* bce) 923 #ifdef DEBUG 924 : bce_(bce) 925 #endif 926 { 927 #ifdef DEBUG 928 prev_ = bce_->unstableEmitterScope; 929 bce_->unstableEmitterScope = true; 930 #endif 931 } ~AutoCheckUnstableEmitterScope()932 ~AutoCheckUnstableEmitterScope() { 933 #ifdef DEBUG 934 bce_->unstableEmitterScope = prev_; 935 #endif 936 } 937 }; 938 939 } /* namespace frontend */ 940 } /* namespace js */ 941 942 #endif /* frontend_BytecodeEmitter_h */ 943