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 /*
8 * JS bytecode generation.
9 */
10
11 #include "frontend/BytecodeEmitter.h"
12
13 #include "mozilla/ArrayUtils.h"
14 #include "mozilla/DebugOnly.h"
15 #include "mozilla/FloatingPoint.h"
16 #include "mozilla/Maybe.h"
17 #include "mozilla/PodOperations.h"
18
19 #include <string.h>
20
21 #include "jsapi.h"
22 #include "jsnum.h"
23 #include "jstypes.h"
24 #include "jsutil.h"
25
26 #include "ds/Nestable.h"
27 #include "frontend/Parser.h"
28 #include "frontend/TokenStream.h"
29 #include "vm/BytecodeUtil.h"
30 #include "vm/Debugger.h"
31 #include "vm/GeneratorObject.h"
32 #include "vm/JSAtom.h"
33 #include "vm/JSContext.h"
34 #include "vm/JSFunction.h"
35 #include "vm/JSScript.h"
36 #include "vm/Stack.h"
37 #include "wasm/AsmJS.h"
38
39 #include "frontend/ParseNode-inl.h"
40 #include "vm/EnvironmentObject-inl.h"
41 #include "vm/JSAtom-inl.h"
42 #include "vm/JSScript-inl.h"
43 #include "vm/NativeObject-inl.h"
44
45 using namespace js;
46 using namespace js::gc;
47 using namespace js::frontend;
48
49 using mozilla::AssertedCast;
50 using mozilla::DebugOnly;
51 using mozilla::Maybe;
52 using mozilla::Nothing;
53 using mozilla::NumberIsInt32;
54 using mozilla::PodCopy;
55 using mozilla::Some;
56 using mozilla::Unused;
57
58 class BreakableControl;
59 class LabelControl;
60 class LoopControl;
61 class ForOfLoopControl;
62 class TryFinallyControl;
63
ParseNodeRequiresSpecialLineNumberNotes(ParseNode * pn)64 static bool ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn) {
65 // The few node types listed below are exceptions to the usual
66 // location-source-note-emitting code in BytecodeEmitter::emitTree().
67 // Single-line `while` loops and C-style `for` loops require careful
68 // handling to avoid strange stepping behavior.
69 // Functions usually shouldn't have location information (bug 1431202).
70
71 ParseNodeKind kind = pn->getKind();
72 return kind == ParseNodeKind::While || kind == ParseNodeKind::For ||
73 kind == ParseNodeKind::Function;
74 }
75
76 // A cache that tracks superfluous TDZ checks.
77 //
78 // Each basic block should have a TDZCheckCache in scope. Some NestableControl
79 // subclasses contain a TDZCheckCache.
80 class BytecodeEmitter::TDZCheckCache
81 : public Nestable<BytecodeEmitter::TDZCheckCache> {
82 PooledMapPtr<CheckTDZMap> cache_;
83
ensureCache(BytecodeEmitter * bce)84 MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
85 return cache_ || cache_.acquire(bce->cx);
86 }
87
88 public:
TDZCheckCache(BytecodeEmitter * bce)89 explicit TDZCheckCache(BytecodeEmitter* bce)
90 : Nestable<TDZCheckCache>(&bce->innermostTDZCheckCache),
91 cache_(bce->cx->frontendCollectionPool()) {}
92
93 Maybe<MaybeCheckTDZ> needsTDZCheck(BytecodeEmitter* bce, JSAtom* name);
94 MOZ_MUST_USE bool noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
95 MaybeCheckTDZ check);
96 };
97
98 class BytecodeEmitter::NestableControl
99 : public Nestable<BytecodeEmitter::NestableControl> {
100 StatementKind kind_;
101
102 // The innermost scope when this was pushed.
103 EmitterScope* emitterScope_;
104
105 protected:
NestableControl(BytecodeEmitter * bce,StatementKind kind)106 NestableControl(BytecodeEmitter* bce, StatementKind kind)
107 : Nestable<NestableControl>(&bce->innermostNestableControl),
108 kind_(kind),
109 emitterScope_(bce->innermostEmitterScopeNoCheck()) {}
110
111 public:
112 using Nestable<NestableControl>::enclosing;
113 using Nestable<NestableControl>::findNearest;
114
kind() const115 StatementKind kind() const { return kind_; }
116
emitterScope() const117 EmitterScope* emitterScope() const { return emitterScope_; }
118
119 template <typename T>
120 bool is() const;
121
122 template <typename T>
as()123 T& as() {
124 MOZ_ASSERT(this->is<T>());
125 return static_cast<T&>(*this);
126 }
127 };
128
129 // Template specializations are disallowed in different namespaces; specialize
130 // all the NestableControl subtypes up front.
131 namespace js {
132 namespace frontend {
133
134 template <>
is() const135 bool BytecodeEmitter::NestableControl::is<BreakableControl>() const {
136 return StatementKindIsUnlabeledBreakTarget(kind_) ||
137 kind_ == StatementKind::Label;
138 }
139
140 template <>
is() const141 bool BytecodeEmitter::NestableControl::is<LabelControl>() const {
142 return kind_ == StatementKind::Label;
143 }
144
145 template <>
is() const146 bool BytecodeEmitter::NestableControl::is<LoopControl>() const {
147 return StatementKindIsLoop(kind_);
148 }
149
150 template <>
is() const151 bool BytecodeEmitter::NestableControl::is<ForOfLoopControl>() const {
152 return kind_ == StatementKind::ForOfLoop;
153 }
154
155 template <>
is() const156 bool BytecodeEmitter::NestableControl::is<TryFinallyControl>() const {
157 return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
158 }
159
160 } // namespace frontend
161 } // namespace js
162
163 class BreakableControl : public BytecodeEmitter::NestableControl {
164 public:
165 // Offset of the last break.
166 JumpList breaks;
167
BreakableControl(BytecodeEmitter * bce,StatementKind kind)168 BreakableControl(BytecodeEmitter* bce, StatementKind kind)
169 : NestableControl(bce, kind) {
170 MOZ_ASSERT(is<BreakableControl>());
171 }
172
patchBreaks(BytecodeEmitter * bce)173 MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce) {
174 return bce->emitJumpTargetAndPatch(breaks);
175 }
176 };
177
178 class LabelControl : public BreakableControl {
179 RootedAtom label_;
180
181 // The code offset when this was pushed. Used for effectfulness checking.
182 ptrdiff_t startOffset_;
183
184 public:
LabelControl(BytecodeEmitter * bce,JSAtom * label,ptrdiff_t startOffset)185 LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
186 : BreakableControl(bce, StatementKind::Label),
187 label_(bce->cx, label),
188 startOffset_(startOffset) {}
189
label() const190 HandleAtom label() const { return label_; }
191
startOffset() const192 ptrdiff_t startOffset() const { return startOffset_; }
193 };
194
195 class LoopControl : public BreakableControl {
196 // Loops' children are emitted in dominance order, so they can always
197 // have a TDZCheckCache.
198 BytecodeEmitter::TDZCheckCache tdzCache_;
199
200 // Stack depth when this loop was pushed on the control stack.
201 int32_t stackDepth_;
202
203 // The loop nesting depth. Used as a hint to Ion.
204 uint32_t loopDepth_;
205
206 // Can we OSR into Ion from here? True unless there is non-loop state on the
207 // stack.
208 bool canIonOsr_;
209
210 public:
211 // The target of continue statement jumps, e.g., the update portion of a
212 // for(;;) loop.
213 JumpTarget continueTarget;
214
215 // Offset of the last continue in the loop.
216 JumpList continues;
217
LoopControl(BytecodeEmitter * bce,StatementKind loopKind)218 LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
219 : BreakableControl(bce, loopKind), tdzCache_(bce), continueTarget({-1}) {
220 MOZ_ASSERT(is<LoopControl>());
221
222 LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
223
224 stackDepth_ = bce->stackDepth;
225 loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
226
227 int loopSlots;
228 if (loopKind == StatementKind::Spread) {
229 // The iterator next method, the iterator, the result array, and
230 // the current array index are on the stack.
231 loopSlots = 4;
232 } else if (loopKind == StatementKind::ForOfLoop) {
233 // The iterator next method, the iterator, and the current value
234 // are on the stack.
235 loopSlots = 3;
236 } else if (loopKind == StatementKind::ForInLoop) {
237 // The iterator and the current value are on the stack.
238 loopSlots = 2;
239 } else {
240 // No additional loop values are on the stack.
241 loopSlots = 0;
242 }
243
244 MOZ_ASSERT(loopSlots <= stackDepth_);
245
246 if (enclosingLoop) {
247 canIonOsr_ = (enclosingLoop->canIonOsr_ &&
248 stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
249 } else {
250 canIonOsr_ = stackDepth_ == loopSlots;
251 }
252 }
253
loopDepth() const254 uint32_t loopDepth() const { return loopDepth_; }
255
canIonOsr() const256 bool canIonOsr() const { return canIonOsr_; }
257
emitSpecialBreakForDone(BytecodeEmitter * bce)258 MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce) {
259 // This doesn't pop stack values, nor handle any other controls.
260 // Should be called on the toplevel of the loop.
261 MOZ_ASSERT(bce->stackDepth == stackDepth_);
262 MOZ_ASSERT(bce->innermostNestableControl == this);
263
264 if (!bce->newSrcNote(SRC_BREAK)) return false;
265 if (!bce->emitJump(JSOP_GOTO, &breaks)) return false;
266
267 return true;
268 }
269
patchBreaksAndContinues(BytecodeEmitter * bce)270 MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce) {
271 MOZ_ASSERT(continueTarget.offset != -1);
272 if (!patchBreaks(bce)) return false;
273 bce->patchJumpsToTarget(continues, continueTarget);
274 return true;
275 }
276 };
277
278 class TryFinallyControl : public BytecodeEmitter::NestableControl {
279 bool emittingSubroutine_;
280
281 public:
282 // The subroutine when emitting a finally block.
283 JumpList gosubs;
284
TryFinallyControl(BytecodeEmitter * bce,StatementKind kind)285 TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
286 : NestableControl(bce, kind), emittingSubroutine_(false) {
287 MOZ_ASSERT(is<TryFinallyControl>());
288 }
289
setEmittingSubroutine()290 void setEmittingSubroutine() { emittingSubroutine_ = true; }
291
emittingSubroutine() const292 bool emittingSubroutine() const { return emittingSubroutine_; }
293 };
294
MarkAllBindingsClosedOver(LexicalScope::Data & data)295 static inline void MarkAllBindingsClosedOver(LexicalScope::Data& data) {
296 BindingName* names = data.names;
297 for (uint32_t i = 0; i < data.length; i++)
298 names[i] = BindingName(names[i].name(), true);
299 }
300
301 // A scope that introduces bindings.
302 class BytecodeEmitter::EmitterScope
303 : public Nestable<BytecodeEmitter::EmitterScope> {
304 // The cache of bound names that may be looked up in the
305 // scope. Initially populated as the set of names this scope binds. As
306 // names are looked up in enclosing scopes, they are cached on the
307 // current scope.
308 PooledMapPtr<NameLocationMap> nameCache_;
309
310 // If this scope's cache does not include free names, such as the
311 // global scope, the NameLocation to return.
312 Maybe<NameLocation> fallbackFreeNameLocation_;
313
314 // True if there is a corresponding EnvironmentObject on the environment
315 // chain, false if all bindings are stored in frame slots on the stack.
316 bool hasEnvironment_;
317
318 // The number of enclosing environments. Used for error checking.
319 uint8_t environmentChainLength_;
320
321 // The next usable slot on the frame for not-closed over bindings.
322 //
323 // The initial frame slot when assigning slots to bindings is the
324 // enclosing scope's nextFrameSlot. For the first scope in a frame,
325 // the initial frame slot is 0.
326 uint32_t nextFrameSlot_;
327
328 // The index in the BytecodeEmitter's interned scope vector, otherwise
329 // ScopeNote::NoScopeIndex.
330 uint32_t scopeIndex_;
331
332 // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
333 // block scope note list. Otherwise ScopeNote::NoScopeNote.
334 uint32_t noteIndex_;
335
ensureCache(BytecodeEmitter * bce)336 MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
337 return nameCache_.acquire(bce->cx);
338 }
339
340 template <typename BindingIter>
checkSlotLimits(BytecodeEmitter * bce,const BindingIter & bi)341 MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce,
342 const BindingIter& bi) {
343 if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
344 bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT) {
345 bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
346 return false;
347 }
348 return true;
349 }
350
checkEnvironmentChainLength(BytecodeEmitter * bce)351 MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce) {
352 uint32_t hops;
353 if (EmitterScope* emitterScope = enclosing(&bce))
354 hops = emitterScope->environmentChainLength_;
355 else
356 hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
357
358 if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
359 bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
360 return false;
361 }
362
363 environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
364 return true;
365 }
366
updateFrameFixedSlots(BytecodeEmitter * bce,const BindingIter & bi)367 void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi) {
368 nextFrameSlot_ = bi.nextFrameSlot();
369 if (nextFrameSlot_ > bce->maxFixedSlots)
370 bce->maxFixedSlots = nextFrameSlot_;
371 MOZ_ASSERT_IF(
372 bce->sc->isFunctionBox() && (bce->sc->asFunctionBox()->isGenerator() ||
373 bce->sc->asFunctionBox()->isAsync()),
374 bce->maxFixedSlots == 0);
375 }
376
putNameInCache(BytecodeEmitter * bce,JSAtom * name,NameLocation loc)377 MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, JSAtom* name,
378 NameLocation loc) {
379 NameLocationMap& cache = *nameCache_;
380 NameLocationMap::AddPtr p = cache.lookupForAdd(name);
381 MOZ_ASSERT(!p);
382 if (!cache.add(p, name, loc)) {
383 ReportOutOfMemory(bce->cx);
384 return false;
385 }
386 return true;
387 }
388
lookupInCache(BytecodeEmitter * bce,JSAtom * name)389 Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce, JSAtom* name) {
390 if (NameLocationMap::Ptr p = nameCache_->lookup(name))
391 return Some(p->value().wrapped);
392 if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name))
393 return fallbackFreeNameLocation_;
394 return Nothing();
395 }
396
397 friend bool BytecodeEmitter::needsImplicitThis();
398
enclosing(BytecodeEmitter ** bce) const399 EmitterScope* enclosing(BytecodeEmitter** bce) const {
400 // There is an enclosing scope with access to the same frame.
401 if (EmitterScope* inFrame = enclosingInFrame()) return inFrame;
402
403 // We are currently compiling the enclosing script, look in the
404 // enclosing BCE.
405 if ((*bce)->parent) {
406 *bce = (*bce)->parent;
407 return (*bce)->innermostEmitterScopeNoCheck();
408 }
409
410 return nullptr;
411 }
412
enclosingScope(BytecodeEmitter * bce) const413 Scope* enclosingScope(BytecodeEmitter* bce) const {
414 if (EmitterScope* es = enclosing(&bce)) return es->scope(bce);
415
416 // The enclosing script is already compiled or the current script is the
417 // global script.
418 return bce->sc->compilationEnclosingScope();
419 }
420
nameCanBeFree(BytecodeEmitter * bce,JSAtom * name)421 static bool nameCanBeFree(BytecodeEmitter* bce, JSAtom* name) {
422 // '.generator' cannot be accessed by name.
423 return name != bce->cx->names().dotGenerator;
424 }
425
426 static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope,
427 uint8_t hops);
428 NameLocation searchAndCache(BytecodeEmitter* bce, JSAtom* name);
429
430 template <typename ScopeCreator>
431 MOZ_MUST_USE bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
432 template <typename ScopeCreator>
433 MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce,
434 ScopeCreator createScope);
435 MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
436
437 MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce,
438 uint32_t slotStart,
439 uint32_t slotEnd);
440
441 public:
EmitterScope(BytecodeEmitter * bce)442 explicit EmitterScope(BytecodeEmitter* bce)
443 : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
444 nameCache_(bce->cx->frontendCollectionPool()),
445 hasEnvironment_(false),
446 environmentChainLength_(0),
447 nextFrameSlot_(0),
448 scopeIndex_(ScopeNote::NoScopeIndex),
449 noteIndex_(ScopeNote::NoScopeNoteIndex) {}
450
451 void dump(BytecodeEmitter* bce);
452
453 MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
454 Handle<LexicalScope::Data*> bindings);
455 MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
456 MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
457 MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce,
458 FunctionBox* funbox);
459 MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
460 MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce,
461 GlobalSharedContext* globalsc);
462 MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
463 MOZ_MUST_USE bool enterModule(BytecodeEmitter* module,
464 ModuleSharedContext* modulesc);
465 MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce);
466 MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce);
467
468 MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false);
469
index() const470 uint32_t index() const {
471 MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex,
472 "Did you forget to intern a Scope?");
473 return scopeIndex_;
474 }
475
noteIndex() const476 uint32_t noteIndex() const { return noteIndex_; }
477
scope(const BytecodeEmitter * bce) const478 Scope* scope(const BytecodeEmitter* bce) const {
479 return bce->scopeList.vector[index()];
480 }
481
hasEnvironment() const482 bool hasEnvironment() const { return hasEnvironment_; }
483
484 // The first frame slot used.
frameSlotStart() const485 uint32_t frameSlotStart() const {
486 if (EmitterScope* inFrame = enclosingInFrame())
487 return inFrame->nextFrameSlot_;
488 return 0;
489 }
490
491 // The last frame slot used + 1.
frameSlotEnd() const492 uint32_t frameSlotEnd() const { return nextFrameSlot_; }
493
numFrameSlots() const494 uint32_t numFrameSlots() const { return frameSlotEnd() - frameSlotStart(); }
495
enclosingInFrame() const496 EmitterScope* enclosingInFrame() const {
497 return Nestable<EmitterScope>::enclosing();
498 }
499
lookup(BytecodeEmitter * bce,JSAtom * name)500 NameLocation lookup(BytecodeEmitter* bce, JSAtom* name) {
501 if (Maybe<NameLocation> loc = lookupInCache(bce, name)) return *loc;
502 return searchAndCache(bce, name);
503 }
504
505 Maybe<NameLocation> locationBoundInScope(JSAtom* name, EmitterScope* target);
506 };
507
dump(BytecodeEmitter * bce)508 void BytecodeEmitter::EmitterScope::dump(BytecodeEmitter* bce) {
509 fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce)->kind()),
510 this);
511
512 for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
513 const NameLocation& l = r.front().value();
514
515 JSAutoByteString bytes;
516 if (!AtomToPrintableString(bce->cx, r.front().key(), &bytes)) return;
517 if (l.kind() != NameLocation::Kind::Dynamic)
518 fprintf(stdout, " %s %s ", BindingKindString(l.bindingKind()),
519 bytes.ptr());
520 else
521 fprintf(stdout, " %s ", bytes.ptr());
522
523 switch (l.kind()) {
524 case NameLocation::Kind::Dynamic:
525 fprintf(stdout, "dynamic\n");
526 break;
527 case NameLocation::Kind::Global:
528 fprintf(stdout, "global\n");
529 break;
530 case NameLocation::Kind::Intrinsic:
531 fprintf(stdout, "intrinsic\n");
532 break;
533 case NameLocation::Kind::NamedLambdaCallee:
534 fprintf(stdout, "named lambda callee\n");
535 break;
536 case NameLocation::Kind::Import:
537 fprintf(stdout, "import\n");
538 break;
539 case NameLocation::Kind::ArgumentSlot:
540 fprintf(stdout, "arg slot=%u\n", l.argumentSlot());
541 break;
542 case NameLocation::Kind::FrameSlot:
543 fprintf(stdout, "frame slot=%u\n", l.frameSlot());
544 break;
545 case NameLocation::Kind::EnvironmentCoordinate:
546 fprintf(stdout, "environment hops=%u slot=%u\n",
547 l.environmentCoordinate().hops(),
548 l.environmentCoordinate().slot());
549 break;
550 case NameLocation::Kind::DynamicAnnexBVar:
551 fprintf(stdout, "dynamic annex b var\n");
552 break;
553 }
554 }
555
556 fprintf(stdout, "\n");
557 }
558
559 template <typename ScopeCreator>
internScope(BytecodeEmitter * bce,ScopeCreator createScope)560 bool BytecodeEmitter::EmitterScope::internScope(BytecodeEmitter* bce,
561 ScopeCreator createScope) {
562 RootedScope enclosing(bce->cx, enclosingScope(bce));
563 Scope* scope = createScope(bce->cx, enclosing);
564 if (!scope) return false;
565 hasEnvironment_ = scope->hasEnvironment();
566 scopeIndex_ = bce->scopeList.length();
567 return bce->scopeList.append(scope);
568 }
569
570 template <typename ScopeCreator>
internBodyScope(BytecodeEmitter * bce,ScopeCreator createScope)571 bool BytecodeEmitter::EmitterScope::internBodyScope(BytecodeEmitter* bce,
572 ScopeCreator createScope) {
573 MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX,
574 "There can be only one body scope");
575 bce->bodyScopeIndex = bce->scopeList.length();
576 return internScope(bce, createScope);
577 }
578
appendScopeNote(BytecodeEmitter * bce)579 bool BytecodeEmitter::EmitterScope::appendScopeNote(BytecodeEmitter* bce) {
580 MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),
581 "Scope notes are not needed for body-level scopes.");
582 noteIndex_ = bce->scopeNoteList.length();
583 return bce->scopeNoteList.append(index(), bce->offset(), bce->inPrologue(),
584 enclosingInFrame()
585 ? enclosingInFrame()->noteIndex()
586 : ScopeNote::NoScopeNoteIndex);
587 }
588
589 #ifdef DEBUG
NameIsOnEnvironment(Scope * scope,JSAtom * name)590 static bool NameIsOnEnvironment(Scope* scope, JSAtom* name) {
591 for (BindingIter bi(scope); bi; bi++) {
592 // If found, the name must already be on the environment or an import,
593 // or else there is a bug in the closed-over name analysis in the
594 // Parser.
595 if (bi.name() == name) {
596 BindingLocation::Kind kind = bi.location().kind();
597
598 if (bi.hasArgumentSlot()) {
599 JSScript* script = scope->as<FunctionScope>().script();
600 if (!script->strict() && !script->functionHasParameterExprs()) {
601 // Check for duplicate positional formal parameters.
602 for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
603 if (bi2.name() == name) kind = bi2.location().kind();
604 }
605 }
606 }
607
608 return kind == BindingLocation::Kind::Global ||
609 kind == BindingLocation::Kind::Environment ||
610 kind == BindingLocation::Kind::Import;
611 }
612 }
613
614 // If not found, assume it's on the global or dynamically accessed.
615 return true;
616 }
617 #endif
618
searchInEnclosingScope(JSAtom * name,Scope * scope,uint8_t hops)619 /* static */ NameLocation BytecodeEmitter::EmitterScope::searchInEnclosingScope(
620 JSAtom* name, Scope* scope, uint8_t hops) {
621 for (ScopeIter si(scope); si; si++) {
622 MOZ_ASSERT(NameIsOnEnvironment(si.scope(), name));
623
624 bool hasEnv = si.hasSyntacticEnvironment();
625
626 switch (si.kind()) {
627 case ScopeKind::Function:
628 if (hasEnv) {
629 JSScript* script = si.scope()->as<FunctionScope>().script();
630 if (script->funHasExtensibleScope()) return NameLocation::Dynamic();
631
632 for (BindingIter bi(si.scope()); bi; bi++) {
633 if (bi.name() != name) continue;
634
635 BindingLocation bindLoc = bi.location();
636 if (bi.hasArgumentSlot() && !script->strict() &&
637 !script->functionHasParameterExprs()) {
638 // Check for duplicate positional formal parameters.
639 for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
640 if (bi2.name() == name) bindLoc = bi2.location();
641 }
642 }
643
644 MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
645 return NameLocation::EnvironmentCoordinate(bi.kind(), hops,
646 bindLoc.slot());
647 }
648 }
649 break;
650
651 case ScopeKind::FunctionBodyVar:
652 case ScopeKind::ParameterExpressionVar:
653 case ScopeKind::Lexical:
654 case ScopeKind::NamedLambda:
655 case ScopeKind::StrictNamedLambda:
656 case ScopeKind::SimpleCatch:
657 case ScopeKind::Catch:
658 if (hasEnv) {
659 for (BindingIter bi(si.scope()); bi; bi++) {
660 if (bi.name() != name) continue;
661
662 // The name must already have been marked as closed
663 // over. If this assertion is hit, there is a bug in the
664 // name analysis.
665 BindingLocation bindLoc = bi.location();
666 MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
667 return NameLocation::EnvironmentCoordinate(bi.kind(), hops,
668 bindLoc.slot());
669 }
670 }
671 break;
672
673 case ScopeKind::Module:
674 if (hasEnv) {
675 for (BindingIter bi(si.scope()); bi; bi++) {
676 if (bi.name() != name) continue;
677
678 BindingLocation bindLoc = bi.location();
679
680 // Imports are on the environment but are indirect
681 // bindings and must be accessed dynamically instead of
682 // using an EnvironmentCoordinate.
683 if (bindLoc.kind() == BindingLocation::Kind::Import) {
684 MOZ_ASSERT(si.kind() == ScopeKind::Module);
685 return NameLocation::Import();
686 }
687
688 MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
689 return NameLocation::EnvironmentCoordinate(bi.kind(), hops,
690 bindLoc.slot());
691 }
692 }
693 break;
694
695 case ScopeKind::Eval:
696 case ScopeKind::StrictEval:
697 // As an optimization, if the eval doesn't have its own var
698 // environment and its immediate enclosing scope is a global
699 // scope, all accesses are global.
700 if (!hasEnv && si.scope()->enclosing()->is<GlobalScope>())
701 return NameLocation::Global(BindingKind::Var);
702 return NameLocation::Dynamic();
703
704 case ScopeKind::Global:
705 return NameLocation::Global(BindingKind::Var);
706
707 case ScopeKind::With:
708 case ScopeKind::NonSyntactic:
709 return NameLocation::Dynamic();
710
711 case ScopeKind::WasmInstance:
712 case ScopeKind::WasmFunction:
713 MOZ_CRASH("No direct eval inside wasm functions");
714 }
715
716 if (hasEnv) {
717 MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
718 hops++;
719 }
720 }
721
722 MOZ_CRASH("Malformed scope chain");
723 }
724
searchAndCache(BytecodeEmitter * bce,JSAtom * name)725 NameLocation BytecodeEmitter::EmitterScope::searchAndCache(BytecodeEmitter* bce,
726 JSAtom* name) {
727 Maybe<NameLocation> loc;
728 uint8_t hops = hasEnvironment() ? 1 : 0;
729 DebugOnly<bool> inCurrentScript = enclosingInFrame();
730
731 // Start searching in the current compilation.
732 for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) {
733 loc = es->lookupInCache(bce, name);
734 if (loc) {
735 if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate)
736 *loc = loc->addHops(hops);
737 break;
738 }
739
740 if (es->hasEnvironment()) hops++;
741
742 #ifdef DEBUG
743 if (!es->enclosingInFrame()) inCurrentScript = false;
744 #endif
745 }
746
747 // If the name is not found in the current compilation, walk the Scope
748 // chain encompassing the compilation.
749 if (!loc) {
750 inCurrentScript = false;
751 loc = Some(searchInEnclosingScope(
752 name, bce->sc->compilationEnclosingScope(), hops));
753 }
754
755 // Each script has its own frame. A free name that is accessed
756 // from an inner script must not be a frame slot access. If this
757 // assertion is hit, it is a bug in the free name analysis in the
758 // parser.
759 MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot);
760
761 // It is always correct to not cache the location. Ignore OOMs to make
762 // lookups infallible.
763 if (!putNameInCache(bce, name, *loc)) bce->cx->recoverFromOutOfMemory();
764
765 return *loc;
766 }
767
locationBoundInScope(JSAtom * name,EmitterScope * target)768 Maybe<NameLocation> BytecodeEmitter::EmitterScope::locationBoundInScope(
769 JSAtom* name, EmitterScope* target) {
770 // The target scope must be an intra-frame enclosing scope of this
771 // one. Count the number of extra hops to reach it.
772 uint8_t extraHops = 0;
773 for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
774 if (es->hasEnvironment()) extraHops++;
775 }
776
777 // Caches are prepopulated with bound names. So if the name is bound in a
778 // particular scope, it must already be in the cache. Furthermore, don't
779 // consult the fallback location as we only care about binding names.
780 Maybe<NameLocation> loc;
781 if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) {
782 NameLocation l = p->value().wrapped;
783 if (l.kind() == NameLocation::Kind::EnvironmentCoordinate)
784 loc = Some(l.addHops(extraHops));
785 else
786 loc = Some(l);
787 }
788 return loc;
789 }
790
deadZoneFrameSlotRange(BytecodeEmitter * bce,uint32_t slotStart,uint32_t slotEnd)791 bool BytecodeEmitter::EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce,
792 uint32_t slotStart,
793 uint32_t slotEnd) {
794 // Lexical bindings throw ReferenceErrors if they are used before
795 // initialization. See ES6 8.1.1.1.6.
796 //
797 // For completeness, lexical bindings are initialized in ES6 by calling
798 // InitializeBinding, after which touching the binding will no longer
799 // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
800 // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
801 if (slotStart != slotEnd) {
802 if (!bce->emit1(JSOP_UNINITIALIZED)) return false;
803 for (uint32_t slot = slotStart; slot < slotEnd; slot++) {
804 if (!bce->emitLocalOp(JSOP_INITLEXICAL, slot)) return false;
805 }
806 if (!bce->emit1(JSOP_POP)) return false;
807 }
808
809 return true;
810 }
811
deadZoneFrameSlots(BytecodeEmitter * bce)812 bool BytecodeEmitter::EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce) {
813 return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
814 }
815
enterLexical(BytecodeEmitter * bce,ScopeKind kind,Handle<LexicalScope::Data * > bindings)816 bool BytecodeEmitter::EmitterScope::enterLexical(
817 BytecodeEmitter* bce, ScopeKind kind,
818 Handle<LexicalScope::Data*> bindings) {
819 MOZ_ASSERT(kind != ScopeKind::NamedLambda &&
820 kind != ScopeKind::StrictNamedLambda);
821 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
822
823 if (!ensureCache(bce)) return false;
824
825 // Marks all names as closed over if the context requires it. This
826 // cannot be done in the Parser as we may not know if the context requires
827 // all bindings to be closed over until after parsing is finished. For
828 // example, legacy generators require all bindings to be closed over but
829 // it is unknown if a function is a legacy generator until the first
830 // 'yield' expression is parsed.
831 //
832 // This is not a problem with other scopes, as all other scopes with
833 // bindings are body-level. At the time of their creation, whether or not
834 // the context requires all bindings to be closed over is already known.
835 if (bce->sc->allBindingsClosedOver()) MarkAllBindingsClosedOver(*bindings);
836
837 // Resolve bindings.
838 TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
839 uint32_t firstFrameSlot = frameSlotStart();
840 BindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false);
841 for (; bi; bi++) {
842 if (!checkSlotLimits(bce, bi)) return false;
843
844 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
845 if (!putNameInCache(bce, bi.name(), loc)) return false;
846
847 if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ)) return false;
848 }
849
850 updateFrameFixedSlots(bce, bi);
851
852 // Create and intern the VM scope.
853 auto createScope = [kind, bindings, firstFrameSlot](JSContext* cx,
854 HandleScope enclosing) {
855 return LexicalScope::create(cx, kind, bindings, firstFrameSlot, enclosing);
856 };
857 if (!internScope(bce, createScope)) return false;
858
859 if (ScopeKindIsInBody(kind) && hasEnvironment()) {
860 // After interning the VM scope we can get the scope index.
861 if (!bce->emitInternedScopeOp(index(), JSOP_PUSHLEXICALENV)) return false;
862 }
863
864 // Lexical scopes need notes to be mapped from a pc.
865 if (!appendScopeNote(bce)) return false;
866
867 // Put frame slots in TDZ. Environment slots are poisoned during
868 // environment creation.
869 //
870 // This must be done after appendScopeNote to be considered in the extent
871 // of the scope.
872 if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd()))
873 return false;
874
875 return checkEnvironmentChainLength(bce);
876 }
877
enterNamedLambda(BytecodeEmitter * bce,FunctionBox * funbox)878 bool BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce,
879 FunctionBox* funbox) {
880 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
881 MOZ_ASSERT(funbox->namedLambdaBindings());
882
883 if (!ensureCache(bce)) return false;
884
885 // See comment in enterLexical about allBindingsClosedOver.
886 if (funbox->allBindingsClosedOver())
887 MarkAllBindingsClosedOver(*funbox->namedLambdaBindings());
888
889 BindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT,
890 /* isNamedLambda = */ true);
891 MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee);
892
893 // The lambda name, if not closed over, is accessed via JSOP_CALLEE and
894 // not a frame slot. Do not update frame slot information.
895 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
896 if (!putNameInCache(bce, bi.name(), loc)) return false;
897
898 bi++;
899 MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope");
900
901 auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
902 ScopeKind scopeKind = funbox->strict() ? ScopeKind::StrictNamedLambda
903 : ScopeKind::NamedLambda;
904 return LexicalScope::create(cx, scopeKind, funbox->namedLambdaBindings(),
905 LOCALNO_LIMIT, enclosing);
906 };
907 if (!internScope(bce, createScope)) return false;
908
909 return checkEnvironmentChainLength(bce);
910 }
911
enterParameterExpressionVar(BytecodeEmitter * bce)912 bool BytecodeEmitter::EmitterScope::enterParameterExpressionVar(
913 BytecodeEmitter* bce) {
914 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
915
916 if (!ensureCache(bce)) return false;
917
918 // Parameter expressions var scopes have no pre-set bindings and are
919 // always extensible, as they are needed for eval.
920 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
921
922 // Create and intern the VM scope.
923 uint32_t firstFrameSlot = frameSlotStart();
924 auto createScope = [firstFrameSlot](JSContext* cx, HandleScope enclosing) {
925 return VarScope::create(cx, ScopeKind::ParameterExpressionVar,
926 /* data = */ nullptr, firstFrameSlot,
927 /* needsEnvironment = */ true, enclosing);
928 };
929 if (!internScope(bce, createScope)) return false;
930
931 MOZ_ASSERT(hasEnvironment());
932 if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV)) return false;
933
934 // The extra var scope needs a note to be mapped from a pc.
935 if (!appendScopeNote(bce)) return false;
936
937 return checkEnvironmentChainLength(bce);
938 }
939
enterFunction(BytecodeEmitter * bce,FunctionBox * funbox)940 bool BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce,
941 FunctionBox* funbox) {
942 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
943
944 // If there are parameter expressions, there is an extra var scope.
945 if (!funbox->hasExtraBodyVarScope()) bce->setVarEmitterScope(this);
946
947 if (!ensureCache(bce)) return false;
948
949 // Resolve body-level bindings, if there are any.
950 auto bindings = funbox->functionScopeBindings();
951 Maybe<uint32_t> lastLexicalSlot;
952 if (bindings) {
953 NameLocationMap& cache = *nameCache_;
954
955 BindingIter bi(*bindings, funbox->hasParameterExprs);
956 for (; bi; bi++) {
957 if (!checkSlotLimits(bce, bi)) return false;
958
959 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
960 NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
961
962 // The only duplicate bindings that occur are simple formal
963 // parameters, in which case the last position counts, so update the
964 // location.
965 if (p) {
966 MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
967 MOZ_ASSERT(!funbox->hasDestructuringArgs);
968 MOZ_ASSERT(!funbox->hasRest());
969 p->value() = loc;
970 continue;
971 }
972
973 if (!cache.add(p, bi.name(), loc)) {
974 ReportOutOfMemory(bce->cx);
975 return false;
976 }
977 }
978
979 updateFrameFixedSlots(bce, bi);
980 } else {
981 nextFrameSlot_ = 0;
982 }
983
984 // If the function's scope may be extended at runtime due to sloppy direct
985 // eval and there is no extra var scope, any names beyond the function
986 // scope must be accessed dynamically as we don't know if the name will
987 // become a 'var' binding due to direct eval.
988 if (!funbox->hasParameterExprs && funbox->hasExtensibleScope())
989 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
990
991 // In case of parameter expressions, the parameters are lexical
992 // bindings and have TDZ.
993 if (funbox->hasParameterExprs && nextFrameSlot_) {
994 uint32_t paramFrameSlotEnd = 0;
995 for (BindingIter bi(*bindings, true); bi; bi++) {
996 if (!BindingKindIsLexical(bi.kind())) break;
997
998 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
999 if (loc.kind() == NameLocation::Kind::FrameSlot) {
1000 MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot());
1001 paramFrameSlotEnd = loc.frameSlot() + 1;
1002 }
1003 }
1004
1005 if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd)) return false;
1006 }
1007
1008 // Create and intern the VM scope.
1009 auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
1010 RootedFunction fun(cx, funbox->function());
1011 return FunctionScope::create(
1012 cx, funbox->functionScopeBindings(), funbox->hasParameterExprs,
1013 funbox->needsCallObjectRegardlessOfBindings(), fun, enclosing);
1014 };
1015 if (!internBodyScope(bce, createScope)) return false;
1016
1017 return checkEnvironmentChainLength(bce);
1018 }
1019
enterFunctionExtraBodyVar(BytecodeEmitter * bce,FunctionBox * funbox)1020 bool BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(
1021 BytecodeEmitter* bce, FunctionBox* funbox) {
1022 MOZ_ASSERT(funbox->hasParameterExprs);
1023 MOZ_ASSERT(funbox->extraVarScopeBindings() ||
1024 funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
1025 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1026
1027 // The extra var scope is never popped once it's entered. It replaces the
1028 // function scope as the var emitter scope.
1029 bce->setVarEmitterScope(this);
1030
1031 if (!ensureCache(bce)) return false;
1032
1033 // Resolve body-level bindings, if there are any.
1034 uint32_t firstFrameSlot = frameSlotStart();
1035 if (auto bindings = funbox->extraVarScopeBindings()) {
1036 BindingIter bi(*bindings, firstFrameSlot);
1037 for (; bi; bi++) {
1038 if (!checkSlotLimits(bce, bi)) return false;
1039
1040 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1041 if (!putNameInCache(bce, bi.name(), loc)) return false;
1042 }
1043
1044 updateFrameFixedSlots(bce, bi);
1045 } else {
1046 nextFrameSlot_ = firstFrameSlot;
1047 }
1048
1049 // If the extra var scope may be extended at runtime due to sloppy
1050 // direct eval, any names beyond the var scope must be accessed
1051 // dynamically as we don't know if the name will become a 'var' binding
1052 // due to direct eval.
1053 if (funbox->hasExtensibleScope())
1054 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1055
1056 // Create and intern the VM scope.
1057 auto createScope = [funbox, firstFrameSlot](JSContext* cx,
1058 HandleScope enclosing) {
1059 return VarScope::create(
1060 cx, ScopeKind::FunctionBodyVar, funbox->extraVarScopeBindings(),
1061 firstFrameSlot,
1062 funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(), enclosing);
1063 };
1064 if (!internScope(bce, createScope)) return false;
1065
1066 if (hasEnvironment()) {
1067 if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV)) return false;
1068 }
1069
1070 // The extra var scope needs a note to be mapped from a pc.
1071 if (!appendScopeNote(bce)) return false;
1072
1073 return checkEnvironmentChainLength(bce);
1074 }
1075
1076 class DynamicBindingIter : public BindingIter {
1077 public:
DynamicBindingIter(GlobalSharedContext * sc)1078 explicit DynamicBindingIter(GlobalSharedContext* sc)
1079 : BindingIter(*sc->bindings) {}
1080
DynamicBindingIter(EvalSharedContext * sc)1081 explicit DynamicBindingIter(EvalSharedContext* sc)
1082 : BindingIter(*sc->bindings, /* strict = */ false) {
1083 MOZ_ASSERT(!sc->strict());
1084 }
1085
bindingOp() const1086 JSOp bindingOp() const {
1087 switch (kind()) {
1088 case BindingKind::Var:
1089 return JSOP_DEFVAR;
1090 case BindingKind::Let:
1091 return JSOP_DEFLET;
1092 case BindingKind::Const:
1093 return JSOP_DEFCONST;
1094 default:
1095 MOZ_CRASH("Bad BindingKind");
1096 }
1097 }
1098 };
1099
enterGlobal(BytecodeEmitter * bce,GlobalSharedContext * globalsc)1100 bool BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce,
1101 GlobalSharedContext* globalsc) {
1102 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1103
1104 bce->setVarEmitterScope(this);
1105
1106 if (!ensureCache(bce)) return false;
1107
1108 if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
1109 // In self-hosting, it is incorrect to consult the global scope because
1110 // self-hosted scripts are cloned into their target compartments before
1111 // they are run. Instead of Global, Intrinsic is used for all names.
1112 //
1113 // Intrinsic lookups are redirected to the special intrinsics holder
1114 // in the global object, into which any missing values are cloned
1115 // lazily upon first access.
1116 fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic());
1117
1118 auto createScope = [](JSContext* cx, HandleScope enclosing) {
1119 MOZ_ASSERT(!enclosing);
1120 return &cx->global()->emptyGlobalScope();
1121 };
1122 return internBodyScope(bce, createScope);
1123 }
1124
1125 // Resolve binding names and emit DEF{VAR,LET,CONST} prologue ops.
1126 if (globalsc->bindings) {
1127 for (DynamicBindingIter bi(globalsc); bi; bi++) {
1128 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1129 JSAtom* name = bi.name();
1130 if (!putNameInCache(bce, name, loc)) return false;
1131
1132 // Define the name in the prologue. Do not emit DEFVAR for
1133 // functions that we'll emit DEFFUN for.
1134 if (bi.isTopLevelFunction()) continue;
1135
1136 if (!bce->emitAtomOp(name, bi.bindingOp())) return false;
1137 }
1138 }
1139
1140 // Note that to save space, we don't add free names to the cache for
1141 // global scopes. They are assumed to be global vars in the syntactic
1142 // global scope, dynamic accesses under non-syntactic global scope.
1143 if (globalsc->scopeKind() == ScopeKind::Global)
1144 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1145 else
1146 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1147
1148 auto createScope = [globalsc](JSContext* cx, HandleScope enclosing) {
1149 MOZ_ASSERT(!enclosing);
1150 return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
1151 };
1152 return internBodyScope(bce, createScope);
1153 }
1154
enterEval(BytecodeEmitter * bce,EvalSharedContext * evalsc)1155 bool BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce,
1156 EvalSharedContext* evalsc) {
1157 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1158
1159 bce->setVarEmitterScope(this);
1160
1161 if (!ensureCache(bce)) return false;
1162
1163 // For simplicity, treat all free name lookups in eval scripts as dynamic.
1164 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1165
1166 // Create the `var` scope. Note that there is also a lexical scope, created
1167 // separately in emitScript().
1168 auto createScope = [evalsc](JSContext* cx, HandleScope enclosing) {
1169 ScopeKind scopeKind =
1170 evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval;
1171 return EvalScope::create(cx, scopeKind, evalsc->bindings, enclosing);
1172 };
1173 if (!internBodyScope(bce, createScope)) return false;
1174
1175 if (hasEnvironment()) {
1176 if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV)) return false;
1177 } else {
1178 // Resolve binding names and emit DEFVAR prologue ops if we don't have
1179 // an environment (i.e., a sloppy eval not in a parameter expression).
1180 // Eval scripts always have their own lexical scope, but non-strict
1181 // scopes may introduce 'var' bindings to the nearest var scope.
1182 //
1183 // TODO: We may optimize strict eval bindings in the future to be on
1184 // the frame. For now, handle everything dynamically.
1185 if (!hasEnvironment() && evalsc->bindings) {
1186 for (DynamicBindingIter bi(evalsc); bi; bi++) {
1187 MOZ_ASSERT(bi.bindingOp() == JSOP_DEFVAR);
1188
1189 if (bi.isTopLevelFunction()) continue;
1190
1191 if (!bce->emitAtomOp(bi.name(), JSOP_DEFVAR)) return false;
1192 }
1193 }
1194
1195 // As an optimization, if the eval does not have its own var
1196 // environment and is directly enclosed in a global scope, then all
1197 // free name lookups are global.
1198 if (scope(bce)->enclosing()->is<GlobalScope>())
1199 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1200 }
1201
1202 return true;
1203 }
1204
enterModule(BytecodeEmitter * bce,ModuleSharedContext * modulesc)1205 bool BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce,
1206 ModuleSharedContext* modulesc) {
1207 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1208
1209 bce->setVarEmitterScope(this);
1210
1211 if (!ensureCache(bce)) return false;
1212
1213 // Resolve body-level bindings, if there are any.
1214 TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
1215 Maybe<uint32_t> firstLexicalFrameSlot;
1216 if (ModuleScope::Data* bindings = modulesc->bindings) {
1217 BindingIter bi(*bindings);
1218 for (; bi; bi++) {
1219 if (!checkSlotLimits(bce, bi)) return false;
1220
1221 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1222 if (!putNameInCache(bce, bi.name(), loc)) return false;
1223
1224 if (BindingKindIsLexical(bi.kind())) {
1225 if (loc.kind() == NameLocation::Kind::FrameSlot &&
1226 !firstLexicalFrameSlot)
1227 firstLexicalFrameSlot = Some(loc.frameSlot());
1228
1229 if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ)) return false;
1230 }
1231 }
1232
1233 updateFrameFixedSlots(bce, bi);
1234 } else {
1235 nextFrameSlot_ = 0;
1236 }
1237
1238 // Modules are toplevel, so any free names are global.
1239 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1240
1241 // Put lexical frame slots in TDZ. Environment slots are poisoned during
1242 // environment creation.
1243 if (firstLexicalFrameSlot) {
1244 if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd()))
1245 return false;
1246 }
1247
1248 // Create and intern the VM scope.
1249 auto createScope = [modulesc](JSContext* cx, HandleScope enclosing) {
1250 return ModuleScope::create(cx, modulesc->bindings, modulesc->module(),
1251 enclosing);
1252 };
1253 if (!internBodyScope(bce, createScope)) return false;
1254
1255 return checkEnvironmentChainLength(bce);
1256 }
1257
enterWith(BytecodeEmitter * bce)1258 bool BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce) {
1259 MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1260
1261 if (!ensureCache(bce)) return false;
1262
1263 // 'with' make all accesses dynamic and unanalyzable.
1264 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1265
1266 auto createScope = [](JSContext* cx, HandleScope enclosing) {
1267 return WithScope::create(cx, enclosing);
1268 };
1269 if (!internScope(bce, createScope)) return false;
1270
1271 if (!bce->emitInternedScopeOp(index(), JSOP_ENTERWITH)) return false;
1272
1273 if (!appendScopeNote(bce)) return false;
1274
1275 return checkEnvironmentChainLength(bce);
1276 }
1277
leave(BytecodeEmitter * bce,bool nonLocal)1278 bool BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal) {
1279 // If we aren't leaving the scope due to a non-local jump (e.g., break),
1280 // we must be the innermost scope.
1281 MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
1282
1283 ScopeKind kind = scope(bce)->kind();
1284 switch (kind) {
1285 case ScopeKind::Lexical:
1286 case ScopeKind::SimpleCatch:
1287 case ScopeKind::Catch:
1288 if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV
1289 : JSOP_DEBUGLEAVELEXICALENV))
1290 return false;
1291 break;
1292
1293 case ScopeKind::With:
1294 if (!bce->emit1(JSOP_LEAVEWITH)) return false;
1295 break;
1296
1297 case ScopeKind::ParameterExpressionVar:
1298 MOZ_ASSERT(hasEnvironment());
1299 if (!bce->emit1(JSOP_POPVARENV)) return false;
1300 break;
1301
1302 case ScopeKind::Function:
1303 case ScopeKind::FunctionBodyVar:
1304 case ScopeKind::NamedLambda:
1305 case ScopeKind::StrictNamedLambda:
1306 case ScopeKind::Eval:
1307 case ScopeKind::StrictEval:
1308 case ScopeKind::Global:
1309 case ScopeKind::NonSyntactic:
1310 case ScopeKind::Module:
1311 break;
1312
1313 case ScopeKind::WasmInstance:
1314 case ScopeKind::WasmFunction:
1315 MOZ_CRASH("No wasm function scopes in JS");
1316 }
1317
1318 // Finish up the scope if we are leaving it in LIFO fashion.
1319 if (!nonLocal) {
1320 // Popping scopes due to non-local jumps generate additional scope
1321 // notes. See NonLocalExitControl::prepareForNonLocalJump.
1322 if (ScopeKindIsInBody(kind)) {
1323 // The extra function var scope is never popped once it's pushed,
1324 // so its scope note extends until the end of any possible code.
1325 uint32_t offset =
1326 kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
1327 bce->scopeNoteList.recordEnd(noteIndex_, offset, bce->inPrologue());
1328 }
1329 }
1330
1331 return true;
1332 }
1333
needsTDZCheck(BytecodeEmitter * bce,JSAtom * name)1334 Maybe<MaybeCheckTDZ> BytecodeEmitter::TDZCheckCache::needsTDZCheck(
1335 BytecodeEmitter* bce, JSAtom* name) {
1336 if (!ensureCache(bce)) return Nothing();
1337
1338 CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
1339 if (p) return Some(p->value().wrapped);
1340
1341 MaybeCheckTDZ rv = CheckTDZ;
1342 for (TDZCheckCache* it = enclosing(); it; it = it->enclosing()) {
1343 if (it->cache_) {
1344 if (CheckTDZMap::Ptr p2 = it->cache_->lookup(name)) {
1345 rv = p2->value();
1346 break;
1347 }
1348 }
1349 }
1350
1351 if (!cache_->add(p, name, rv)) {
1352 ReportOutOfMemory(bce->cx);
1353 return Nothing();
1354 }
1355
1356 return Some(rv);
1357 }
1358
noteTDZCheck(BytecodeEmitter * bce,JSAtom * name,MaybeCheckTDZ check)1359 bool BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce,
1360 JSAtom* name,
1361 MaybeCheckTDZ check) {
1362 if (!ensureCache(bce)) return false;
1363
1364 CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
1365 if (p) {
1366 MOZ_ASSERT(
1367 !check,
1368 "TDZ only needs to be checked once per binding per basic block.");
1369 p->value() = check;
1370 } else {
1371 if (!cache_->add(p, name, check)) return false;
1372 }
1373
1374 return true;
1375 }
1376
1377 class MOZ_STACK_CLASS TryEmitter {
1378 public:
1379 enum Kind { TryCatch, TryCatchFinally, TryFinally };
1380 enum ShouldUseRetVal { UseRetVal, DontUseRetVal };
1381 enum ShouldUseControl {
1382 UseControl,
1383 DontUseControl,
1384 };
1385
1386 private:
1387 BytecodeEmitter* bce_;
1388 Kind kind_;
1389 ShouldUseRetVal retValKind_;
1390
1391 // Track jumps-over-catches and gosubs-to-finally for later fixup.
1392 //
1393 // When a finally block is active, non-local jumps (including
1394 // jumps-over-catches) result in a GOSUB being written into the bytecode
1395 // stream and fixed-up later.
1396 //
1397 // If ShouldUseControl is DontUseControl, all that handling is skipped.
1398 // DontUseControl is used by yield* and the internal try-catch around
1399 // IteratorClose. These internal uses must:
1400 // * have only one catch block
1401 // * have JSOP_GOTO at the end of catch-block
1402 // * have no non-local-jump
1403 // * don't use finally block for normal completion of try-block and
1404 // catch-block
1405 //
1406 // Additionally, a finally block may be emitted when ShouldUseControl is
1407 // DontUseControl, even if the kind is not TryCatchFinally or TryFinally,
1408 // because GOSUBs are not emitted. This internal use shares the
1409 // requirements as above.
1410 Maybe<TryFinallyControl> controlInfo_;
1411
1412 int depth_;
1413 unsigned noteIndex_;
1414 ptrdiff_t tryStart_;
1415 JumpList catchAndFinallyJump_;
1416 JumpTarget tryEnd_;
1417 JumpTarget finallyStart_;
1418
1419 enum State { Start, Try, TryEnd, Catch, CatchEnd, Finally, FinallyEnd, End };
1420 State state_;
1421
hasCatch() const1422 bool hasCatch() const {
1423 return kind_ == TryCatch || kind_ == TryCatchFinally;
1424 }
hasFinally() const1425 bool hasFinally() const {
1426 return kind_ == TryCatchFinally || kind_ == TryFinally;
1427 }
1428
1429 public:
TryEmitter(BytecodeEmitter * bce,Kind kind,ShouldUseRetVal retValKind=UseRetVal,ShouldUseControl controlKind=UseControl)1430 TryEmitter(BytecodeEmitter* bce, Kind kind,
1431 ShouldUseRetVal retValKind = UseRetVal,
1432 ShouldUseControl controlKind = UseControl)
1433 : bce_(bce),
1434 kind_(kind),
1435 retValKind_(retValKind),
1436 depth_(0),
1437 noteIndex_(0),
1438 tryStart_(0),
1439 state_(Start) {
1440 if (controlKind == UseControl)
1441 controlInfo_.emplace(
1442 bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
1443 finallyStart_.offset = 0;
1444 }
1445
emitJumpOverCatchAndFinally()1446 bool emitJumpOverCatchAndFinally() {
1447 if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_)) return false;
1448 return true;
1449 }
1450
emitTry()1451 bool emitTry() {
1452 MOZ_ASSERT(state_ == Start);
1453
1454 // Since an exception can be thrown at any place inside the try block,
1455 // we need to restore the stack and the scope chain before we transfer
1456 // the control to the exception handler.
1457 //
1458 // For that we store in a try note associated with the catch or
1459 // finally block the stack depth upon the try entry. The interpreter
1460 // uses this depth to properly unwind the stack and the scope chain.
1461 depth_ = bce_->stackDepth;
1462
1463 // Record the try location, then emit the try block.
1464 if (!bce_->newSrcNote(SRC_TRY, ¬eIndex_)) return false;
1465 if (!bce_->emit1(JSOP_TRY)) return false;
1466 tryStart_ = bce_->offset();
1467
1468 state_ = Try;
1469 return true;
1470 }
1471
1472 private:
emitTryEnd()1473 bool emitTryEnd() {
1474 MOZ_ASSERT(state_ == Try);
1475 MOZ_ASSERT(depth_ == bce_->stackDepth);
1476
1477 // GOSUB to finally, if present.
1478 if (hasFinally() && controlInfo_) {
1479 if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs)) return false;
1480 }
1481
1482 // Source note points to the jump at the end of the try block.
1483 if (!bce_->setSrcNoteOffset(noteIndex_, 0,
1484 bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
1485 return false;
1486
1487 // Emit jump over catch and/or finally.
1488 if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_)) return false;
1489
1490 if (!bce_->emitJumpTarget(&tryEnd_)) return false;
1491
1492 return true;
1493 }
1494
1495 public:
emitCatch()1496 bool emitCatch() {
1497 MOZ_ASSERT(state_ == Try);
1498 if (!emitTryEnd()) return false;
1499
1500 MOZ_ASSERT(bce_->stackDepth == depth_);
1501
1502 if (retValKind_ == UseRetVal) {
1503 // Clear the frame's return value that might have been set by the
1504 // try block:
1505 //
1506 // eval("try { 1; throw 2 } catch(e) {}"); // undefined, not 1
1507 if (!bce_->emit1(JSOP_UNDEFINED)) return false;
1508 if (!bce_->emit1(JSOP_SETRVAL)) return false;
1509 }
1510
1511 state_ = Catch;
1512 return true;
1513 }
1514
1515 private:
emitCatchEnd()1516 bool emitCatchEnd() {
1517 MOZ_ASSERT(state_ == Catch);
1518
1519 if (!controlInfo_) return true;
1520
1521 // gosub <finally>, if required.
1522 if (hasFinally()) {
1523 if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs)) return false;
1524 MOZ_ASSERT(bce_->stackDepth == depth_);
1525
1526 // Jump over the finally block.
1527 if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_)) return false;
1528 }
1529
1530 return true;
1531 }
1532
1533 public:
emitFinally(const Maybe<uint32_t> & finallyPos=Nothing ())1534 bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
1535 // If we are using controlInfo_ (i.e., emitting a syntactic try
1536 // blocks), we must have specified up front if there will be a finally
1537 // close. For internal try blocks, like those emitted for yield* and
1538 // IteratorClose inside for-of loops, we can emitFinally even without
1539 // specifying up front, since the internal try blocks emit no GOSUBs.
1540 if (!controlInfo_) {
1541 if (kind_ == TryCatch) kind_ = TryCatchFinally;
1542 } else {
1543 MOZ_ASSERT(hasFinally());
1544 }
1545
1546 if (state_ == Try) {
1547 if (!emitTryEnd()) return false;
1548 } else {
1549 MOZ_ASSERT(state_ == Catch);
1550 if (!emitCatchEnd()) return false;
1551 }
1552
1553 MOZ_ASSERT(bce_->stackDepth == depth_);
1554
1555 if (!bce_->emitJumpTarget(&finallyStart_)) return false;
1556
1557 if (controlInfo_) {
1558 // Fix up the gosubs that might have been emitted before non-local
1559 // jumps to the finally code.
1560 bce_->patchJumpsToTarget(controlInfo_->gosubs, finallyStart_);
1561
1562 // Indicate that we're emitting a subroutine body.
1563 controlInfo_->setEmittingSubroutine();
1564 }
1565 if (finallyPos) {
1566 if (!bce_->updateSourceCoordNotes(finallyPos.value())) return false;
1567 }
1568 if (!bce_->emit1(JSOP_FINALLY)) return false;
1569
1570 if (retValKind_ == UseRetVal) {
1571 if (!bce_->emit1(JSOP_GETRVAL)) return false;
1572
1573 // Clear the frame's return value to make break/continue return
1574 // correct value even if there's no other statement before them:
1575 //
1576 // eval("x: try { 1 } finally { break x; }"); // undefined, not 1
1577 if (!bce_->emit1(JSOP_UNDEFINED)) return false;
1578 if (!bce_->emit1(JSOP_SETRVAL)) return false;
1579 }
1580
1581 state_ = Finally;
1582 return true;
1583 }
1584
1585 private:
emitFinallyEnd()1586 bool emitFinallyEnd() {
1587 MOZ_ASSERT(state_ == Finally);
1588
1589 if (retValKind_ == UseRetVal) {
1590 if (!bce_->emit1(JSOP_SETRVAL)) return false;
1591 }
1592
1593 if (!bce_->emit1(JSOP_RETSUB)) return false;
1594
1595 bce_->hasTryFinally = true;
1596 return true;
1597 }
1598
1599 public:
emitEnd()1600 bool emitEnd() {
1601 if (state_ == Catch) {
1602 MOZ_ASSERT(!hasFinally());
1603 if (!emitCatchEnd()) return false;
1604 } else {
1605 MOZ_ASSERT(state_ == Finally);
1606 MOZ_ASSERT(hasFinally());
1607 if (!emitFinallyEnd()) return false;
1608 }
1609
1610 MOZ_ASSERT(bce_->stackDepth == depth_);
1611
1612 // ReconstructPCStack needs a NOP here to mark the end of the last
1613 // catch block.
1614 if (!bce_->emit1(JSOP_NOP)) return false;
1615
1616 // Fix up the end-of-try/catch jumps to come here.
1617 if (!bce_->emitJumpTargetAndPatch(catchAndFinallyJump_)) return false;
1618
1619 // Add the try note last, to let post-order give us the right ordering
1620 // (first to last for a given nesting level, inner to outer by level).
1621 if (hasCatch()) {
1622 if (!bce_->tryNoteList.append(JSTRY_CATCH, depth_, tryStart_,
1623 tryEnd_.offset))
1624 return false;
1625 }
1626
1627 // If we've got a finally, mark try+catch region with additional
1628 // trynote to catch exceptions (re)thrown from a catch block or
1629 // for the try{}finally{} case.
1630 if (hasFinally()) {
1631 if (!bce_->tryNoteList.append(JSTRY_FINALLY, depth_, tryStart_,
1632 finallyStart_.offset))
1633 return false;
1634 }
1635
1636 state_ = End;
1637 return true;
1638 }
1639 };
1640
1641 class MOZ_STACK_CLASS IfThenElseEmitter {
1642 BytecodeEmitter* bce_;
1643 JumpList jumpAroundThen_;
1644 JumpList jumpsAroundElse_;
1645 unsigned noteIndex_;
1646 int32_t thenDepth_;
1647 #ifdef DEBUG
1648 int32_t pushed_;
1649 bool calculatedPushed_;
1650 #endif
1651 enum State { Start, If, Cond, IfElse, Else, End };
1652 State state_;
1653
1654 public:
IfThenElseEmitter(BytecodeEmitter * bce)1655 explicit IfThenElseEmitter(BytecodeEmitter* bce)
1656 : bce_(bce),
1657 noteIndex_(-1),
1658 thenDepth_(0),
1659 #ifdef DEBUG
1660 pushed_(0),
1661 calculatedPushed_(false),
1662 #endif
1663 state_(Start) {
1664 }
1665
~IfThenElseEmitter()1666 ~IfThenElseEmitter() {}
1667
1668 private:
emitIf(State nextState)1669 bool emitIf(State nextState) {
1670 MOZ_ASSERT(state_ == Start || state_ == Else);
1671 MOZ_ASSERT(nextState == If || nextState == IfElse || nextState == Cond);
1672
1673 // Clear jumpAroundThen_ offset that points previous JSOP_IFEQ.
1674 if (state_ == Else) jumpAroundThen_ = JumpList();
1675
1676 // Emit an annotated branch-if-false around the then part.
1677 SrcNoteType type =
1678 nextState == If ? SRC_IF : nextState == IfElse ? SRC_IF_ELSE : SRC_COND;
1679 if (!bce_->newSrcNote(type, ¬eIndex_)) return false;
1680 if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_)) return false;
1681
1682 // To restore stack depth in else part, save depth of the then part.
1683 #ifdef DEBUG
1684 // If DEBUG, this is also necessary to calculate |pushed_|.
1685 thenDepth_ = bce_->stackDepth;
1686 #else
1687 if (nextState == IfElse || nextState == Cond) thenDepth_ = bce_->stackDepth;
1688 #endif
1689 state_ = nextState;
1690 return true;
1691 }
1692
1693 public:
emitIf()1694 bool emitIf() { return emitIf(If); }
1695
emitCond()1696 bool emitCond() { return emitIf(Cond); }
1697
emitIfElse()1698 bool emitIfElse() { return emitIf(IfElse); }
1699
emitElse()1700 bool emitElse() {
1701 MOZ_ASSERT(state_ == IfElse || state_ == Cond);
1702
1703 calculateOrCheckPushed();
1704
1705 // Emit a jump from the end of our then part around the else part. The
1706 // patchJumpsToTarget call at the bottom of this function will fix up
1707 // the offset with jumpsAroundElse value.
1708 if (!bce_->emitJump(JSOP_GOTO, &jumpsAroundElse_)) return false;
1709
1710 // Ensure the branch-if-false comes here, then emit the else.
1711 if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_)) return false;
1712
1713 // Annotate SRC_IF_ELSE or SRC_COND with the offset from branch to
1714 // jump, for IonMonkey's benefit. We can't just "back up" from the pc
1715 // of the else clause, because we don't know whether an extended
1716 // jump was required to leap from the end of the then clause over
1717 // the else clause.
1718 if (!bce_->setSrcNoteOffset(
1719 noteIndex_, 0, jumpsAroundElse_.offset - jumpAroundThen_.offset)) {
1720 return false;
1721 }
1722
1723 // Restore stack depth of the then part.
1724 bce_->stackDepth = thenDepth_;
1725 state_ = Else;
1726 return true;
1727 }
1728
emitEnd()1729 bool emitEnd() {
1730 MOZ_ASSERT(state_ == If || state_ == Else);
1731
1732 calculateOrCheckPushed();
1733
1734 if (state_ == If) {
1735 // No else part, fixup the branch-if-false to come here.
1736 if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_)) return false;
1737 }
1738
1739 // Patch all the jumps around else parts.
1740 if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_)) return false;
1741
1742 state_ = End;
1743 return true;
1744 }
1745
calculateOrCheckPushed()1746 void calculateOrCheckPushed() {
1747 #ifdef DEBUG
1748 if (!calculatedPushed_) {
1749 pushed_ = bce_->stackDepth - thenDepth_;
1750 calculatedPushed_ = true;
1751 } else {
1752 MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_);
1753 }
1754 #endif
1755 }
1756
1757 #ifdef DEBUG
pushed() const1758 int32_t pushed() const { return pushed_; }
1759
popped() const1760 int32_t popped() const { return -pushed_; }
1761 #endif
1762 };
1763
1764 class ForOfLoopControl : public LoopControl {
1765 using EmitterScope = BytecodeEmitter::EmitterScope;
1766
1767 // The stack depth of the iterator.
1768 int32_t iterDepth_;
1769
1770 // for-of loops, when throwing from non-iterator code (i.e. from the body
1771 // or from evaluating the LHS of the loop condition), need to call
1772 // IteratorClose. This is done by enclosing non-iterator code with
1773 // try-catch and call IteratorClose in `catch` block.
1774 // If IteratorClose itself throws, we must not re-call IteratorClose. Since
1775 // non-local jumps like break and return call IteratorClose, whenever a
1776 // non-local jump is emitted, we must tell catch block not to perform
1777 // IteratorClose.
1778 //
1779 // for (x of y) {
1780 // // Operations for iterator (IteratorNext etc) are outside of
1781 // // try-block.
1782 // try {
1783 // ...
1784 // if (...) {
1785 // // Before non-local jump, clear iterator on the stack to tell
1786 // // catch block not to perform IteratorClose.
1787 // tmpIterator = iterator;
1788 // iterator = undefined;
1789 // IteratorClose(tmpIterator, { break });
1790 // break;
1791 // }
1792 // ...
1793 // } catch (e) {
1794 // // Just throw again when iterator is cleared by non-local jump.
1795 // if (iterator === undefined)
1796 // throw e;
1797 // IteratorClose(iterator, { throw, e });
1798 // }
1799 // }
1800 Maybe<TryEmitter> tryCatch_;
1801
1802 // Used to track if any yields were emitted between calls to to
1803 // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
1804 uint32_t numYieldsAtBeginCodeNeedingIterClose_;
1805
1806 bool allowSelfHosted_;
1807
1808 IteratorKind iterKind_;
1809
1810 public:
ForOfLoopControl(BytecodeEmitter * bce,int32_t iterDepth,bool allowSelfHosted,IteratorKind iterKind)1811 ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth,
1812 bool allowSelfHosted, IteratorKind iterKind)
1813 : LoopControl(bce, StatementKind::ForOfLoop),
1814 iterDepth_(iterDepth),
1815 numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
1816 allowSelfHosted_(allowSelfHosted),
1817 iterKind_(iterKind) {}
1818
emitBeginCodeNeedingIteratorClose(BytecodeEmitter * bce)1819 bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
1820 tryCatch_.emplace(bce, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
1821 TryEmitter::DontUseControl);
1822
1823 if (!tryCatch_->emitTry()) return false;
1824
1825 MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
1826 numYieldsAtBeginCodeNeedingIterClose_ =
1827 bce->yieldAndAwaitOffsetList.numYields;
1828
1829 return true;
1830 }
1831
emitEndCodeNeedingIteratorClose(BytecodeEmitter * bce)1832 bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
1833 if (!tryCatch_->emitCatch()) // ITER ...
1834 return false;
1835
1836 if (!bce->emit1(JSOP_EXCEPTION)) // ITER ... EXCEPTION
1837 return false;
1838 unsigned slotFromTop = bce->stackDepth - iterDepth_;
1839 if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
1840 return false;
1841
1842 // If ITER is undefined, it means the exception is thrown by
1843 // IteratorClose for non-local jump, and we should't perform
1844 // IteratorClose again here.
1845 if (!bce->emit1(JSOP_UNDEFINED)) // ITER ... EXCEPTION ITER UNDEF
1846 return false;
1847 if (!bce->emit1(JSOP_STRICTNE)) // ITER ... EXCEPTION NE
1848 return false;
1849
1850 IfThenElseEmitter ifIteratorIsNotClosed(bce);
1851 if (!ifIteratorIsNotClosed.emitIf()) // ITER ... EXCEPTION
1852 return false;
1853
1854 MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
1855 if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
1856 return false;
1857 if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Throw))
1858 return false; // ITER ... EXCEPTION
1859
1860 if (!ifIteratorIsNotClosed.emitEnd()) // ITER ... EXCEPTION
1861 return false;
1862
1863 if (!bce->emit1(JSOP_THROW)) // ITER ...
1864 return false;
1865
1866 // If any yields were emitted, then this for-of loop is inside a star
1867 // generator and must handle the case of Generator.return. Like in
1868 // yield*, it is handled with a finally block.
1869 uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
1870 if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
1871 if (!tryCatch_->emitFinally()) return false;
1872
1873 IfThenElseEmitter ifGeneratorClosing(bce);
1874 if (!bce->emit1(JSOP_ISGENCLOSING)) // ITER ... FTYPE FVALUE CLOSING
1875 return false;
1876 if (!ifGeneratorClosing.emitIf()) // ITER ... FTYPE FVALUE
1877 return false;
1878 if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
1879 return false;
1880 if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Normal))
1881 return false; // ITER ... FTYPE FVALUE
1882 if (!ifGeneratorClosing.emitEnd()) // ITER ... FTYPE FVALUE
1883 return false;
1884 }
1885
1886 if (!tryCatch_->emitEnd()) return false;
1887
1888 tryCatch_.reset();
1889 numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
1890
1891 return true;
1892 }
1893
emitIteratorCloseInInnermostScope(BytecodeEmitter * bce,CompletionKind completionKind=CompletionKind::Normal)1894 bool emitIteratorCloseInInnermostScope(
1895 BytecodeEmitter* bce,
1896 CompletionKind completionKind = CompletionKind::Normal) {
1897 return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(),
1898 completionKind);
1899 }
1900
emitIteratorCloseInScope(BytecodeEmitter * bce,EmitterScope & currentScope,CompletionKind completionKind=CompletionKind::Normal)1901 bool emitIteratorCloseInScope(
1902 BytecodeEmitter* bce, EmitterScope& currentScope,
1903 CompletionKind completionKind = CompletionKind::Normal) {
1904 ptrdiff_t start = bce->offset();
1905 if (!bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
1906 allowSelfHosted_)) {
1907 return false;
1908 }
1909 ptrdiff_t end = bce->offset();
1910 return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
1911 }
1912
emitPrepareForNonLocalJumpFromScope(BytecodeEmitter * bce,EmitterScope & currentScope,bool isTarget)1913 bool emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
1914 EmitterScope& currentScope,
1915 bool isTarget) {
1916 // Pop unnecessary value from the stack. Effectively this means
1917 // leaving try-catch block. However, the performing IteratorClose can
1918 // reach the depth for try-catch, and effectively re-enter the
1919 // try-catch block.
1920 if (!bce->emit1(JSOP_POP)) // NEXT ITER
1921 return false;
1922
1923 // Pop the iterator's next method.
1924 if (!bce->emit1(JSOP_SWAP)) // ITER NEXT
1925 return false;
1926 if (!bce->emit1(JSOP_POP)) // ITER
1927 return false;
1928
1929 // Clear ITER slot on the stack to tell catch block to avoid performing
1930 // IteratorClose again.
1931 if (!bce->emit1(JSOP_UNDEFINED)) // ITER UNDEF
1932 return false;
1933 if (!bce->emit1(JSOP_SWAP)) // UNDEF ITER
1934 return false;
1935
1936 if (!emitIteratorCloseInScope(bce, currentScope,
1937 CompletionKind::Normal)) // UNDEF
1938 return false;
1939
1940 if (isTarget) {
1941 // At the level of the target block, there's bytecode after the
1942 // loop that will pop the next method, the iterator, and the
1943 // value, so push two undefineds to balance the stack.
1944 if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF
1945 return false;
1946 if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF UNDEF
1947 return false;
1948 } else {
1949 if (!bce->emit1(JSOP_POP)) //
1950 return false;
1951 }
1952
1953 return true;
1954 }
1955 };
1956
BytecodeEmitter(BytecodeEmitter * parent,const EitherParser<FullParseHandler> & parser,SharedContext * sc,HandleScript script,Handle<LazyScript * > lazyScript,uint32_t lineNum,EmitterMode emitterMode)1957 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
1958 const EitherParser<FullParseHandler>& parser,
1959 SharedContext* sc, HandleScript script,
1960 Handle<LazyScript*> lazyScript,
1961 uint32_t lineNum, EmitterMode emitterMode)
1962 : sc(sc),
1963 cx(sc->context),
1964 parent(parent),
1965 script(cx, script),
1966 lazyScript(cx, lazyScript),
1967 prologue(cx, lineNum),
1968 main(cx, lineNum),
1969 current(&main),
1970 parser(parser),
1971 atomIndices(cx->frontendCollectionPool()),
1972 firstLine(lineNum),
1973 maxFixedSlots(0),
1974 maxStackDepth(0),
1975 stackDepth(0),
1976 emitLevel(0),
1977 bodyScopeIndex(UINT32_MAX),
1978 varEmitterScope(nullptr),
1979 innermostNestableControl(nullptr),
1980 innermostEmitterScope_(nullptr),
1981 innermostTDZCheckCache(nullptr),
1982 #ifdef DEBUG
1983 unstableEmitterScope(false),
1984 #endif
1985 constList(cx),
1986 scopeList(cx),
1987 tryNoteList(cx),
1988 scopeNoteList(cx),
1989 yieldAndAwaitOffsetList(cx),
1990 typesetCount(0),
1991 hasSingletons(false),
1992 hasTryFinally(false),
1993 emittingRunOnceLambda(false),
1994 emitterMode(emitterMode),
1995 functionBodyEndPosSet(false) {
1996 MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
1997 }
1998
BytecodeEmitter(BytecodeEmitter * parent,const EitherParser<FullParseHandler> & parser,SharedContext * sc,HandleScript script,Handle<LazyScript * > lazyScript,TokenPos bodyPosition,EmitterMode emitterMode)1999 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
2000 const EitherParser<FullParseHandler>& parser,
2001 SharedContext* sc, HandleScript script,
2002 Handle<LazyScript*> lazyScript,
2003 TokenPos bodyPosition, EmitterMode emitterMode)
2004 : BytecodeEmitter(
2005 parent, parser, sc, script, lazyScript,
2006 parser.tokenStream().srcCoords.lineNum(bodyPosition.begin),
2007 emitterMode) {
2008 setFunctionBodyEndPos(bodyPosition);
2009 }
2010
init()2011 bool BytecodeEmitter::init() { return atomIndices.acquire(cx); }
2012
2013 template <typename Predicate /* (NestableControl*) -> bool */>
findInnermostNestableControl(Predicate predicate) const2014 BytecodeEmitter::NestableControl* BytecodeEmitter::findInnermostNestableControl(
2015 Predicate predicate) const {
2016 return NestableControl::findNearest(innermostNestableControl, predicate);
2017 }
2018
2019 template <typename T>
findInnermostNestableControl() const2020 T* BytecodeEmitter::findInnermostNestableControl() const {
2021 return NestableControl::findNearest<T>(innermostNestableControl);
2022 }
2023
2024 template <typename T, typename Predicate /* (T*) -> bool */>
2025 T* BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const {
2026 return NestableControl::findNearest<T>(innermostNestableControl, predicate);
2027 }
2028
lookupName(JSAtom * name)2029 NameLocation BytecodeEmitter::lookupName(JSAtom* name) {
2030 return innermostEmitterScope()->lookup(this, name);
2031 }
2032
locationOfNameBoundInScope(JSAtom * name,EmitterScope * target)2033 Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScope(
2034 JSAtom* name, EmitterScope* target) {
2035 return innermostEmitterScope()->locationBoundInScope(name, target);
2036 }
2037
locationOfNameBoundInFunctionScope(JSAtom * name,EmitterScope * source)2038 Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInFunctionScope(
2039 JSAtom* name, EmitterScope* source) {
2040 EmitterScope* funScope = source;
2041 while (!funScope->scope(this)->is<FunctionScope>())
2042 funScope = funScope->enclosingInFrame();
2043 return source->locationBoundInScope(name, funScope);
2044 }
2045
emitCheck(ptrdiff_t delta,ptrdiff_t * offset)2046 bool BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset) {
2047 size_t oldLength = code().length();
2048 *offset = ptrdiff_t(oldLength);
2049
2050 size_t newLength = oldLength + size_t(delta);
2051 if (MOZ_UNLIKELY(newLength > MaxBytecodeLength)) {
2052 ReportAllocationOverflow(cx);
2053 return false;
2054 }
2055
2056 if (!code().growBy(delta)) {
2057 return false;
2058 }
2059 return true;
2060 }
2061
updateDepth(ptrdiff_t target)2062 void BytecodeEmitter::updateDepth(ptrdiff_t target) {
2063 jsbytecode* pc = code(target);
2064
2065 int nuses = StackUses(pc);
2066 int ndefs = StackDefs(pc);
2067
2068 stackDepth -= nuses;
2069 MOZ_ASSERT(stackDepth >= 0);
2070 stackDepth += ndefs;
2071
2072 if ((uint32_t)stackDepth > maxStackDepth) maxStackDepth = stackDepth;
2073 }
2074
2075 #ifdef DEBUG
checkStrictOrSloppy(JSOp op)2076 bool BytecodeEmitter::checkStrictOrSloppy(JSOp op) {
2077 if (IsCheckStrictOp(op) && !sc->strict()) return false;
2078 if (IsCheckSloppyOp(op) && sc->strict()) return false;
2079 return true;
2080 }
2081 #endif
2082
emit1(JSOp op)2083 bool BytecodeEmitter::emit1(JSOp op) {
2084 MOZ_ASSERT(checkStrictOrSloppy(op));
2085
2086 ptrdiff_t offset;
2087 if (!emitCheck(1, &offset)) return false;
2088
2089 jsbytecode* code = this->code(offset);
2090 code[0] = jsbytecode(op);
2091 updateDepth(offset);
2092 return true;
2093 }
2094
emit2(JSOp op,uint8_t op1)2095 bool BytecodeEmitter::emit2(JSOp op, uint8_t op1) {
2096 MOZ_ASSERT(checkStrictOrSloppy(op));
2097
2098 ptrdiff_t offset;
2099 if (!emitCheck(2, &offset)) return false;
2100
2101 jsbytecode* code = this->code(offset);
2102 code[0] = jsbytecode(op);
2103 code[1] = jsbytecode(op1);
2104 updateDepth(offset);
2105 return true;
2106 }
2107
emit3(JSOp op,jsbytecode op1,jsbytecode op2)2108 bool BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) {
2109 MOZ_ASSERT(checkStrictOrSloppy(op));
2110
2111 /* These should filter through emitVarOp. */
2112 MOZ_ASSERT(!IsArgOp(op));
2113 MOZ_ASSERT(!IsLocalOp(op));
2114
2115 ptrdiff_t offset;
2116 if (!emitCheck(3, &offset)) return false;
2117
2118 jsbytecode* code = this->code(offset);
2119 code[0] = jsbytecode(op);
2120 code[1] = op1;
2121 code[2] = op2;
2122 updateDepth(offset);
2123 return true;
2124 }
2125
emitN(JSOp op,size_t extra,ptrdiff_t * offset)2126 bool BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset) {
2127 MOZ_ASSERT(checkStrictOrSloppy(op));
2128 ptrdiff_t length = 1 + ptrdiff_t(extra);
2129
2130 ptrdiff_t off;
2131 if (!emitCheck(length, &off)) return false;
2132
2133 jsbytecode* code = this->code(off);
2134 code[0] = jsbytecode(op);
2135 /* The remaining |extra| bytes are set by the caller */
2136
2137 /*
2138 * Don't updateDepth if op's use-count comes from the immediate
2139 * operand yet to be stored in the extra bytes after op.
2140 */
2141 if (CodeSpec[op].nuses >= 0) updateDepth(off);
2142
2143 if (offset) *offset = off;
2144 return true;
2145 }
2146
emitJumpTarget(JumpTarget * target)2147 bool BytecodeEmitter::emitJumpTarget(JumpTarget* target) {
2148 ptrdiff_t off = offset();
2149
2150 // Alias consecutive jump targets.
2151 if (off == current->lastTarget.offset + ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
2152 target->offset = current->lastTarget.offset;
2153 return true;
2154 }
2155
2156 target->offset = off;
2157 current->lastTarget.offset = off;
2158 if (!emit1(JSOP_JUMPTARGET)) return false;
2159 return true;
2160 }
2161
push(jsbytecode * code,ptrdiff_t jumpOffset)2162 void JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset) {
2163 SET_JUMP_OFFSET(&code[jumpOffset], offset - jumpOffset);
2164 offset = jumpOffset;
2165 }
2166
patchAll(jsbytecode * code,JumpTarget target)2167 void JumpList::patchAll(jsbytecode* code, JumpTarget target) {
2168 ptrdiff_t delta;
2169 for (ptrdiff_t jumpOffset = offset; jumpOffset != -1; jumpOffset += delta) {
2170 jsbytecode* pc = &code[jumpOffset];
2171 MOZ_ASSERT(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL);
2172 delta = GET_JUMP_OFFSET(pc);
2173 MOZ_ASSERT(delta < 0);
2174 ptrdiff_t span = target.offset - jumpOffset;
2175 SET_JUMP_OFFSET(pc, span);
2176 }
2177 }
2178
emitJumpNoFallthrough(JSOp op,JumpList * jump)2179 bool BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump) {
2180 ptrdiff_t offset;
2181 if (!emitCheck(5, &offset)) return false;
2182
2183 jsbytecode* code = this->code(offset);
2184 code[0] = jsbytecode(op);
2185 MOZ_ASSERT(-1 <= jump->offset && jump->offset < offset);
2186 jump->push(this->code(0), offset);
2187 updateDepth(offset);
2188 return true;
2189 }
2190
emitJump(JSOp op,JumpList * jump)2191 bool BytecodeEmitter::emitJump(JSOp op, JumpList* jump) {
2192 if (!emitJumpNoFallthrough(op, jump)) return false;
2193 if (BytecodeFallsThrough(op)) {
2194 JumpTarget fallthrough;
2195 if (!emitJumpTarget(&fallthrough)) return false;
2196 }
2197 return true;
2198 }
2199
emitBackwardJump(JSOp op,JumpTarget target,JumpList * jump,JumpTarget * fallthrough)2200 bool BytecodeEmitter::emitBackwardJump(JSOp op, JumpTarget target,
2201 JumpList* jump,
2202 JumpTarget* fallthrough) {
2203 if (!emitJumpNoFallthrough(op, jump)) return false;
2204 patchJumpsToTarget(*jump, target);
2205
2206 // Unconditionally create a fallthrough for closing iterators, and as a
2207 // target for break statements.
2208 if (!emitJumpTarget(fallthrough)) return false;
2209 return true;
2210 }
2211
patchJumpsToTarget(JumpList jump,JumpTarget target)2212 void BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target) {
2213 MOZ_ASSERT(-1 <= jump.offset && jump.offset <= offset());
2214 MOZ_ASSERT(0 <= target.offset && target.offset <= offset());
2215 MOZ_ASSERT_IF(jump.offset != -1 && target.offset + 4 <= offset(),
2216 BytecodeIsJumpTarget(JSOp(*code(target.offset))));
2217 jump.patchAll(code(0), target);
2218 }
2219
emitJumpTargetAndPatch(JumpList jump)2220 bool BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump) {
2221 if (jump.offset == -1) return true;
2222 JumpTarget target;
2223 if (!emitJumpTarget(&target)) return false;
2224 patchJumpsToTarget(jump, target);
2225 return true;
2226 }
2227
emitCall(JSOp op,uint16_t argc,ParseNode * pn)2228 bool BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn) {
2229 if (pn && !updateSourceCoordNotes(pn->pn_pos.begin)) return false;
2230 return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
2231 }
2232
emitDupAt(unsigned slotFromTop)2233 bool BytecodeEmitter::emitDupAt(unsigned slotFromTop) {
2234 MOZ_ASSERT(slotFromTop < unsigned(stackDepth));
2235
2236 if (slotFromTop == 0) return emit1(JSOP_DUP);
2237
2238 if (slotFromTop >= JS_BIT(24)) {
2239 reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
2240 return false;
2241 }
2242
2243 ptrdiff_t off;
2244 if (!emitN(JSOP_DUPAT, 3, &off)) return false;
2245
2246 jsbytecode* pc = code(off);
2247 SET_UINT24(pc, slotFromTop);
2248 return true;
2249 }
2250
emitPopN(unsigned n)2251 bool BytecodeEmitter::emitPopN(unsigned n) {
2252 MOZ_ASSERT(n != 0);
2253
2254 if (n == 1) return emit1(JSOP_POP);
2255
2256 // 2 JSOP_POPs (2 bytes) are shorter than JSOP_POPN (3 bytes).
2257 if (n == 2) return emit1(JSOP_POP) && emit1(JSOP_POP);
2258
2259 return emitUint16Operand(JSOP_POPN, n);
2260 }
2261
emitCheckIsObj(CheckIsObjectKind kind)2262 bool BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind) {
2263 return emit2(JSOP_CHECKISOBJ, uint8_t(kind));
2264 }
2265
emitCheckIsCallable(CheckIsCallableKind kind)2266 bool BytecodeEmitter::emitCheckIsCallable(CheckIsCallableKind kind) {
2267 return emit2(JSOP_CHECKISCALLABLE, uint8_t(kind));
2268 }
2269
LengthOfSetLine(unsigned line)2270 static inline unsigned LengthOfSetLine(unsigned line) {
2271 return 1 /* SRC_SETLINE */ + (line > SN_4BYTE_OFFSET_MASK ? 4 : 1);
2272 }
2273
2274 /* Updates line number notes, not column notes. */
updateLineNumberNotes(uint32_t offset)2275 bool BytecodeEmitter::updateLineNumberNotes(uint32_t offset) {
2276 TokenStreamAnyChars* ts = &parser.tokenStream();
2277 bool onThisLine;
2278 if (!ts->srcCoords.isOnThisLine(offset, currentLine(), &onThisLine)) {
2279 ts->reportErrorNoOffset(JSMSG_OUT_OF_MEMORY);
2280 return false;
2281 }
2282
2283 if (!onThisLine) {
2284 unsigned line = ts->srcCoords.lineNum(offset);
2285 unsigned delta = line - currentLine();
2286
2287 /*
2288 * Encode any change in the current source line number by using
2289 * either several SRC_NEWLINE notes or just one SRC_SETLINE note,
2290 * whichever consumes less space.
2291 *
2292 * NB: We handle backward line number deltas (possible with for
2293 * loops where the update part is emitted after the body, but its
2294 * line number is <= any line number in the body) here by letting
2295 * unsigned delta_ wrap to a very large number, which triggers a
2296 * SRC_SETLINE.
2297 */
2298 current->currentLine = line;
2299 current->lastColumn = 0;
2300 if (delta >= LengthOfSetLine(line)) {
2301 if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(line))) return false;
2302 } else {
2303 do {
2304 if (!newSrcNote(SRC_NEWLINE)) return false;
2305 } while (--delta != 0);
2306 }
2307 }
2308 return true;
2309 }
2310
2311 /* Updates the line number and column number information in the source notes. */
updateSourceCoordNotes(uint32_t offset)2312 bool BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) {
2313 if (!updateLineNumberNotes(offset)) return false;
2314
2315 uint32_t columnIndex = parser.tokenStream().srcCoords.columnIndex(offset);
2316 ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(current->lastColumn);
2317 if (colspan != 0) {
2318 // If the column span is so large that we can't store it, then just
2319 // discard this information. This can happen with minimized or otherwise
2320 // machine-generated code. Even gigantic column numbers are still
2321 // valuable if you have a source map to relate them to something real;
2322 // but it's better to fail soft here.
2323 if (!SN_REPRESENTABLE_COLSPAN(colspan)) return true;
2324 if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan))) return false;
2325 current->lastColumn = columnIndex;
2326 }
2327 return true;
2328 }
2329
emitLoopHead(ParseNode * nextpn,JumpTarget * top)2330 bool BytecodeEmitter::emitLoopHead(ParseNode* nextpn, JumpTarget* top) {
2331 if (nextpn) {
2332 /*
2333 * Try to give the JSOP_LOOPHEAD the same line number as the next
2334 * instruction. nextpn is often a block, in which case the next
2335 * instruction typically comes from the first statement inside.
2336 */
2337 if (nextpn->isKind(ParseNodeKind::LexicalScope))
2338 nextpn = nextpn->scopeBody();
2339 MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList),
2340 nextpn->isArity(PN_LIST));
2341 if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_head)
2342 nextpn = nextpn->pn_head;
2343 if (!updateSourceCoordNotes(nextpn->pn_pos.begin)) return false;
2344 }
2345
2346 *top = {offset()};
2347 return emit1(JSOP_LOOPHEAD);
2348 }
2349
emitLoopEntry(ParseNode * nextpn,JumpList entryJump)2350 bool BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump) {
2351 if (nextpn) {
2352 /* Update the line number, as for LOOPHEAD. */
2353 if (nextpn->isKind(ParseNodeKind::LexicalScope))
2354 nextpn = nextpn->scopeBody();
2355 MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList),
2356 nextpn->isArity(PN_LIST));
2357 if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_head)
2358 nextpn = nextpn->pn_head;
2359 if (!updateSourceCoordNotes(nextpn->pn_pos.begin)) return false;
2360 }
2361
2362 JumpTarget entry{offset()};
2363 patchJumpsToTarget(entryJump, entry);
2364
2365 LoopControl& loopInfo = innermostNestableControl->as<LoopControl>();
2366 MOZ_ASSERT(loopInfo.loopDepth() > 0);
2367
2368 uint8_t loopDepthAndFlags = PackLoopEntryDepthHintAndFlags(
2369 loopInfo.loopDepth(), loopInfo.canIonOsr());
2370 return emit2(JSOP_LOOPENTRY, loopDepthAndFlags);
2371 }
2372
checkTypeSet(JSOp op)2373 void BytecodeEmitter::checkTypeSet(JSOp op) {
2374 if (CodeSpec[op].format & JOF_TYPESET) {
2375 if (typesetCount < UINT16_MAX) typesetCount++;
2376 }
2377 }
2378
emitUint16Operand(JSOp op,uint32_t operand)2379 bool BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t operand) {
2380 MOZ_ASSERT(operand <= UINT16_MAX);
2381 if (!emit3(op, UINT16_LO(operand), UINT16_HI(operand))) return false;
2382 checkTypeSet(op);
2383 return true;
2384 }
2385
emitUint32Operand(JSOp op,uint32_t operand)2386 bool BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand) {
2387 ptrdiff_t off;
2388 if (!emitN(op, 4, &off)) return false;
2389 SET_UINT32(code(off), operand);
2390 checkTypeSet(op);
2391 return true;
2392 }
2393
2394 namespace {
2395
2396 class NonLocalExitControl {
2397 public:
2398 enum Kind {
2399 // IteratorClose is handled especially inside the exception unwinder.
2400 Throw,
2401
2402 // A 'continue' statement does not call IteratorClose for the loop it
2403 // is continuing, i.e. excluding the target loop.
2404 Continue,
2405
2406 // A 'break' or 'return' statement does call IteratorClose for the
2407 // loop it is breaking out of or returning from, i.e. including the
2408 // target loop.
2409 Break,
2410 Return
2411 };
2412
2413 private:
2414 BytecodeEmitter* bce_;
2415 const uint32_t savedScopeNoteIndex_;
2416 const int savedDepth_;
2417 uint32_t openScopeNoteIndex_;
2418 Kind kind_;
2419
2420 NonLocalExitControl(const NonLocalExitControl&) = delete;
2421
2422 MOZ_MUST_USE bool leaveScope(BytecodeEmitter::EmitterScope* scope);
2423
2424 public:
NonLocalExitControl(BytecodeEmitter * bce,Kind kind)2425 NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
2426 : bce_(bce),
2427 savedScopeNoteIndex_(bce->scopeNoteList.length()),
2428 savedDepth_(bce->stackDepth),
2429 openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
2430 kind_(kind) {}
2431
~NonLocalExitControl()2432 ~NonLocalExitControl() {
2433 for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length();
2434 n++)
2435 bce_->scopeNoteList.recordEnd(n, bce_->offset(), bce_->inPrologue());
2436 bce_->stackDepth = savedDepth_;
2437 }
2438
2439 MOZ_MUST_USE bool prepareForNonLocalJump(
2440 BytecodeEmitter::NestableControl* target);
2441
prepareForNonLocalJumpToOutermost()2442 MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
2443 return prepareForNonLocalJump(nullptr);
2444 }
2445 };
2446
leaveScope(BytecodeEmitter::EmitterScope * es)2447 bool NonLocalExitControl::leaveScope(BytecodeEmitter::EmitterScope* es) {
2448 if (!es->leave(bce_, /* nonLocal = */ true)) return false;
2449
2450 // As we pop each scope due to the non-local jump, emit notes that
2451 // record the extent of the enclosing scope. These notes will have
2452 // their ends recorded in ~NonLocalExitControl().
2453 uint32_t enclosingScopeIndex = ScopeNote::NoScopeIndex;
2454 if (es->enclosingInFrame())
2455 enclosingScopeIndex = es->enclosingInFrame()->index();
2456 if (!bce_->scopeNoteList.append(enclosingScopeIndex, bce_->offset(),
2457 bce_->inPrologue(), openScopeNoteIndex_))
2458 return false;
2459 openScopeNoteIndex_ = bce_->scopeNoteList.length() - 1;
2460
2461 return true;
2462 }
2463
2464 /*
2465 * Emit additional bytecode(s) for non-local jumps.
2466 */
prepareForNonLocalJump(BytecodeEmitter::NestableControl * target)2467 bool NonLocalExitControl::prepareForNonLocalJump(
2468 BytecodeEmitter::NestableControl* target) {
2469 using NestableControl = BytecodeEmitter::NestableControl;
2470 using EmitterScope = BytecodeEmitter::EmitterScope;
2471
2472 EmitterScope* es = bce_->innermostEmitterScope();
2473 int npops = 0;
2474
2475 AutoCheckUnstableEmitterScope cues(bce_);
2476
2477 // For 'continue', 'break', and 'return' statements, emit IteratorClose
2478 // bytecode inline. 'continue' statements do not call IteratorClose for
2479 // the loop they are continuing.
2480 bool emitIteratorClose =
2481 kind_ == Continue || kind_ == Break || kind_ == Return;
2482 bool emitIteratorCloseAtTarget = emitIteratorClose && kind_ != Continue;
2483
2484 auto flushPops = [&npops](BytecodeEmitter* bce) {
2485 if (npops && !bce->emitPopN(npops)) return false;
2486 npops = 0;
2487 return true;
2488 };
2489
2490 // Walk the nestable control stack and patch jumps.
2491 for (NestableControl* control = bce_->innermostNestableControl;
2492 control != target; control = control->enclosing()) {
2493 // Walk the scope stack and leave the scopes we entered. Leaving a scope
2494 // may emit administrative ops like JSOP_POPLEXICALENV but never anything
2495 // that manipulates the stack.
2496 for (; es != control->emitterScope(); es = es->enclosingInFrame()) {
2497 if (!leaveScope(es)) return false;
2498 }
2499
2500 switch (control->kind()) {
2501 case StatementKind::Finally: {
2502 TryFinallyControl& finallyControl = control->as<TryFinallyControl>();
2503 if (finallyControl.emittingSubroutine()) {
2504 /*
2505 * There's a [exception or hole, retsub pc-index] pair and the
2506 * possible return value on the stack that we need to pop.
2507 */
2508 npops += 3;
2509 } else {
2510 if (!flushPops(bce_)) return false;
2511 if (!bce_->emitJump(JSOP_GOSUB, &finallyControl.gosubs)) // ...
2512 return false;
2513 }
2514 break;
2515 }
2516
2517 case StatementKind::ForOfLoop:
2518 if (emitIteratorClose) {
2519 if (!flushPops(bce_)) return false;
2520
2521 ForOfLoopControl& loopinfo = control->as<ForOfLoopControl>();
2522 if (!loopinfo.emitPrepareForNonLocalJumpFromScope(
2523 bce_, *es,
2524 /* isTarget = */ false)) {
2525 // [stack] ...
2526 return false;
2527 }
2528 } else {
2529 // The iterator next method, the iterator, and the current
2530 // value are on the stack.
2531 npops += 3;
2532 }
2533 break;
2534
2535 case StatementKind::ForInLoop:
2536 if (!flushPops(bce_)) return false;
2537
2538 // The iterator and the current value are on the stack.
2539 if (!bce_->emit1(JSOP_POP)) // ... ITER
2540 return false;
2541 if (!bce_->emit1(JSOP_ENDITER)) // ...
2542 return false;
2543 break;
2544
2545 default:
2546 break;
2547 }
2548 }
2549
2550 if (!flushPops(bce_)) return false;
2551
2552 if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
2553 ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
2554 if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
2555 /* isTarget = */ true)) {
2556 // [stack] ... UNDEF UNDEF UNDEF
2557 return false;
2558 }
2559 }
2560
2561 EmitterScope* targetEmitterScope =
2562 target ? target->emitterScope() : bce_->varEmitterScope;
2563 for (; es != targetEmitterScope; es = es->enclosingInFrame()) {
2564 if (!leaveScope(es)) return false;
2565 }
2566
2567 return true;
2568 }
2569
2570 } // anonymous namespace
2571
emitGoto(NestableControl * target,JumpList * jumplist,SrcNoteType noteType)2572 bool BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist,
2573 SrcNoteType noteType) {
2574 NonLocalExitControl nle(this, noteType == SRC_CONTINUE
2575 ? NonLocalExitControl::Continue
2576 : NonLocalExitControl::Break);
2577
2578 if (!nle.prepareForNonLocalJump(target)) return false;
2579
2580 if (noteType != SRC_NULL) {
2581 if (!newSrcNote(noteType)) return false;
2582 }
2583
2584 return emitJump(JSOP_GOTO, jumplist);
2585 }
2586
innermostScope() const2587 Scope* BytecodeEmitter::innermostScope() const {
2588 return innermostEmitterScope()->scope(this);
2589 }
2590
emitIndex32(JSOp op,uint32_t index)2591 bool BytecodeEmitter::emitIndex32(JSOp op, uint32_t index) {
2592 MOZ_ASSERT(checkStrictOrSloppy(op));
2593
2594 const size_t len = 1 + UINT32_INDEX_LEN;
2595 MOZ_ASSERT(len == size_t(CodeSpec[op].length));
2596
2597 ptrdiff_t offset;
2598 if (!emitCheck(len, &offset)) return false;
2599
2600 jsbytecode* code = this->code(offset);
2601 code[0] = jsbytecode(op);
2602 SET_UINT32_INDEX(code, index);
2603 checkTypeSet(op);
2604 updateDepth(offset);
2605 return true;
2606 }
2607
emitIndexOp(JSOp op,uint32_t index)2608 bool BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index) {
2609 MOZ_ASSERT(checkStrictOrSloppy(op));
2610
2611 const size_t len = CodeSpec[op].length;
2612 MOZ_ASSERT(len >= 1 + UINT32_INDEX_LEN);
2613
2614 ptrdiff_t offset;
2615 if (!emitCheck(len, &offset)) return false;
2616
2617 jsbytecode* code = this->code(offset);
2618 code[0] = jsbytecode(op);
2619 SET_UINT32_INDEX(code, index);
2620 checkTypeSet(op);
2621 updateDepth(offset);
2622 return true;
2623 }
2624
emitAtomOp(JSAtom * atom,JSOp op)2625 bool BytecodeEmitter::emitAtomOp(JSAtom* atom, JSOp op) {
2626 MOZ_ASSERT(atom);
2627 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
2628
2629 // .generator lookups should be emitted as JSOP_GETALIASEDVAR instead of
2630 // JSOP_GETNAME etc, to bypass |with| objects on the scope chain.
2631 // It's safe to emit .this lookups though because |with| objects skip
2632 // those.
2633 MOZ_ASSERT_IF(op == JSOP_GETNAME || op == JSOP_GETGNAME,
2634 atom != cx->names().dotGenerator);
2635
2636 if (op == JSOP_GETPROP && atom == cx->names().length) {
2637 /* Specialize length accesses for the interpreter. */
2638 op = JSOP_LENGTH;
2639 }
2640
2641 uint32_t index;
2642 if (!makeAtomIndex(atom, &index)) return false;
2643
2644 return emitIndexOp(op, index);
2645 }
2646
emitAtomOp(ParseNode * pn,JSOp op)2647 bool BytecodeEmitter::emitAtomOp(ParseNode* pn, JSOp op) {
2648 MOZ_ASSERT(pn->pn_atom != nullptr);
2649 return emitAtomOp(pn->pn_atom, op);
2650 }
2651
emitInternedScopeOp(uint32_t index,JSOp op)2652 bool BytecodeEmitter::emitInternedScopeOp(uint32_t index, JSOp op) {
2653 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE);
2654 MOZ_ASSERT(index < scopeList.length());
2655 return emitIndex32(op, index);
2656 }
2657
emitInternedObjectOp(uint32_t index,JSOp op)2658 bool BytecodeEmitter::emitInternedObjectOp(uint32_t index, JSOp op) {
2659 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
2660 MOZ_ASSERT(index < objectList.length);
2661 return emitIndex32(op, index);
2662 }
2663
emitObjectOp(ObjectBox * objbox,JSOp op)2664 bool BytecodeEmitter::emitObjectOp(ObjectBox* objbox, JSOp op) {
2665 return emitInternedObjectOp(objectList.add(objbox), op);
2666 }
2667
emitObjectPairOp(ObjectBox * objbox1,ObjectBox * objbox2,JSOp op)2668 bool BytecodeEmitter::emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2,
2669 JSOp op) {
2670 uint32_t index = objectList.add(objbox1);
2671 objectList.add(objbox2);
2672 return emitInternedObjectOp(index, op);
2673 }
2674
emitRegExp(uint32_t index)2675 bool BytecodeEmitter::emitRegExp(uint32_t index) {
2676 return emitIndex32(JSOP_REGEXP, index);
2677 }
2678
emitLocalOp(JSOp op,uint32_t slot)2679 bool BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot) {
2680 MOZ_ASSERT(JOF_OPTYPE(op) != JOF_ENVCOORD);
2681 MOZ_ASSERT(IsLocalOp(op));
2682
2683 ptrdiff_t off;
2684 if (!emitN(op, LOCALNO_LEN, &off)) return false;
2685
2686 SET_LOCALNO(code(off), slot);
2687 return true;
2688 }
2689
emitArgOp(JSOp op,uint16_t slot)2690 bool BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot) {
2691 MOZ_ASSERT(IsArgOp(op));
2692 ptrdiff_t off;
2693 if (!emitN(op, ARGNO_LEN, &off)) return false;
2694
2695 SET_ARGNO(code(off), slot);
2696 return true;
2697 }
2698
emitEnvCoordOp(JSOp op,EnvironmentCoordinate ec)2699 bool BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec) {
2700 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ENVCOORD);
2701
2702 unsigned n = ENVCOORD_HOPS_LEN + ENVCOORD_SLOT_LEN;
2703 MOZ_ASSERT(int(n) + 1 /* op */ == CodeSpec[op].length);
2704
2705 ptrdiff_t off;
2706 if (!emitN(op, n, &off)) return false;
2707
2708 jsbytecode* pc = code(off);
2709 SET_ENVCOORD_HOPS(pc, ec.hops());
2710 pc += ENVCOORD_HOPS_LEN;
2711 SET_ENVCOORD_SLOT(pc, ec.slot());
2712 pc += ENVCOORD_SLOT_LEN;
2713 checkTypeSet(op);
2714 return true;
2715 }
2716
GetIncDecInfo(ParseNodeKind kind,bool * post)2717 static JSOp GetIncDecInfo(ParseNodeKind kind, bool* post) {
2718 MOZ_ASSERT(kind == ParseNodeKind::PostIncrement ||
2719 kind == ParseNodeKind::PreIncrement ||
2720 kind == ParseNodeKind::PostDecrement ||
2721 kind == ParseNodeKind::PreDecrement);
2722 *post = kind == ParseNodeKind::PostIncrement ||
2723 kind == ParseNodeKind::PostDecrement;
2724 return (kind == ParseNodeKind::PostIncrement ||
2725 kind == ParseNodeKind::PreIncrement)
2726 ? JSOP_ADD
2727 : JSOP_SUB;
2728 }
2729
strictifySetNameOp(JSOp op)2730 JSOp BytecodeEmitter::strictifySetNameOp(JSOp op) {
2731 switch (op) {
2732 case JSOP_SETNAME:
2733 if (sc->strict()) op = JSOP_STRICTSETNAME;
2734 break;
2735 case JSOP_SETGNAME:
2736 if (sc->strict()) op = JSOP_STRICTSETGNAME;
2737 break;
2738 default:;
2739 }
2740 return op;
2741 }
2742
checkSideEffects(ParseNode * pn,bool * answer)2743 bool BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) {
2744 if (!CheckRecursionLimit(cx)) return false;
2745
2746 restart:
2747
2748 switch (pn->getKind()) {
2749 // Trivial cases with no side effects.
2750 case ParseNodeKind::EmptyStatement:
2751 case ParseNodeKind::String:
2752 case ParseNodeKind::TemplateString:
2753 case ParseNodeKind::RegExp:
2754 case ParseNodeKind::True:
2755 case ParseNodeKind::False:
2756 case ParseNodeKind::Null:
2757 case ParseNodeKind::RawUndefined:
2758 case ParseNodeKind::Elision:
2759 case ParseNodeKind::Generator:
2760 case ParseNodeKind::Number:
2761 case ParseNodeKind::ObjectPropertyName:
2762 MOZ_ASSERT(pn->isArity(PN_NULLARY));
2763 *answer = false;
2764 return true;
2765
2766 // |this| can throw in derived class constructors, including nested arrow
2767 // functions or eval.
2768 case ParseNodeKind::This:
2769 MOZ_ASSERT(pn->isArity(PN_UNARY));
2770 *answer = sc->needsThisTDZChecks();
2771 return true;
2772
2773 // Trivial binary nodes with more token pos holders.
2774 case ParseNodeKind::NewTarget:
2775 MOZ_ASSERT(pn->isArity(PN_BINARY));
2776 MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder));
2777 MOZ_ASSERT(pn->pn_right->isKind(ParseNodeKind::PosHolder));
2778 *answer = false;
2779 return true;
2780
2781 case ParseNodeKind::Break:
2782 case ParseNodeKind::Continue:
2783 case ParseNodeKind::Debugger:
2784 MOZ_ASSERT(pn->isArity(PN_NULLARY));
2785 *answer = true;
2786 return true;
2787
2788 // Watch out for getters!
2789 case ParseNodeKind::Dot:
2790 MOZ_ASSERT(pn->isArity(PN_NAME));
2791 *answer = true;
2792 return true;
2793
2794 // Unary cases with side effects only if the child has them.
2795 case ParseNodeKind::TypeOfExpr:
2796 case ParseNodeKind::Void:
2797 case ParseNodeKind::Not:
2798 MOZ_ASSERT(pn->isArity(PN_UNARY));
2799 return checkSideEffects(pn->pn_kid, answer);
2800
2801 // Even if the name expression is effect-free, performing ToPropertyKey on
2802 // it might not be effect-free:
2803 //
2804 // RegExp.prototype.toString = () => { throw 42; };
2805 // ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
2806 //
2807 // function Q() {
2808 // ({ [new.target]: 0 });
2809 // }
2810 // Q.toString = () => { throw 17; };
2811 // new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
2812 case ParseNodeKind::ComputedName:
2813 MOZ_ASSERT(pn->isArity(PN_UNARY));
2814 *answer = true;
2815 return true;
2816
2817 // Looking up or evaluating the associated name could throw.
2818 case ParseNodeKind::TypeOfName:
2819 MOZ_ASSERT(pn->isArity(PN_UNARY));
2820 *answer = true;
2821 return true;
2822
2823 // This unary case has side effects on the enclosing object, sure. But
2824 // that's not the question this function answers: it's whether the
2825 // operation may have a side effect on something *other* than the result
2826 // of the overall operation in which it's embedded. The answer to that
2827 // is no, because an object literal having a mutated prototype only
2828 // produces a value, without affecting anything else.
2829 case ParseNodeKind::MutateProto:
2830 MOZ_ASSERT(pn->isArity(PN_UNARY));
2831 return checkSideEffects(pn->pn_kid, answer);
2832
2833 // Unary cases with obvious side effects.
2834 case ParseNodeKind::PreIncrement:
2835 case ParseNodeKind::PostIncrement:
2836 case ParseNodeKind::PreDecrement:
2837 case ParseNodeKind::PostDecrement:
2838 case ParseNodeKind::Throw:
2839 MOZ_ASSERT(pn->isArity(PN_UNARY));
2840 *answer = true;
2841 return true;
2842
2843 // These might invoke valueOf/toString, even with a subexpression without
2844 // side effects! Consider |+{ valueOf: null, toString: null }|.
2845 case ParseNodeKind::BitNot:
2846 case ParseNodeKind::Pos:
2847 case ParseNodeKind::Neg:
2848 MOZ_ASSERT(pn->isArity(PN_UNARY));
2849 *answer = true;
2850 return true;
2851
2852 // This invokes the (user-controllable) iterator protocol.
2853 case ParseNodeKind::Spread:
2854 MOZ_ASSERT(pn->isArity(PN_UNARY));
2855 *answer = true;
2856 return true;
2857
2858 case ParseNodeKind::InitialYield:
2859 case ParseNodeKind::YieldStar:
2860 case ParseNodeKind::Yield:
2861 case ParseNodeKind::Await:
2862 MOZ_ASSERT(pn->isArity(PN_UNARY));
2863 *answer = true;
2864 return true;
2865
2866 // Deletion generally has side effects, even if isolated cases have none.
2867 case ParseNodeKind::DeleteName:
2868 case ParseNodeKind::DeleteProp:
2869 case ParseNodeKind::DeleteElem:
2870 MOZ_ASSERT(pn->isArity(PN_UNARY));
2871 *answer = true;
2872 return true;
2873
2874 // Deletion of a non-Reference expression has side effects only through
2875 // evaluating the expression.
2876 case ParseNodeKind::DeleteExpr: {
2877 MOZ_ASSERT(pn->isArity(PN_UNARY));
2878 ParseNode* expr = pn->pn_kid;
2879 return checkSideEffects(expr, answer);
2880 }
2881
2882 case ParseNodeKind::ExpressionStatement:
2883 MOZ_ASSERT(pn->isArity(PN_UNARY));
2884 return checkSideEffects(pn->pn_kid, answer);
2885
2886 // Binary cases with obvious side effects.
2887 case ParseNodeKind::Assign:
2888 case ParseNodeKind::AddAssign:
2889 case ParseNodeKind::SubAssign:
2890 case ParseNodeKind::BitOrAssign:
2891 case ParseNodeKind::BitXorAssign:
2892 case ParseNodeKind::BitAndAssign:
2893 case ParseNodeKind::LshAssign:
2894 case ParseNodeKind::RshAssign:
2895 case ParseNodeKind::UrshAssign:
2896 case ParseNodeKind::MulAssign:
2897 case ParseNodeKind::DivAssign:
2898 case ParseNodeKind::ModAssign:
2899 case ParseNodeKind::PowAssign:
2900 case ParseNodeKind::SetThis:
2901 MOZ_ASSERT(pn->isArity(PN_BINARY));
2902 *answer = true;
2903 return true;
2904
2905 case ParseNodeKind::StatementList:
2906 // Strict equality operations and logical operators are well-behaved and
2907 // perform no conversions.
2908 case ParseNodeKind::Or:
2909 case ParseNodeKind::And:
2910 case ParseNodeKind::StrictEq:
2911 case ParseNodeKind::StrictNe:
2912 // Any subexpression of a comma expression could be effectful.
2913 case ParseNodeKind::Comma:
2914 MOZ_ASSERT(pn->pn_count > 0);
2915 MOZ_FALLTHROUGH;
2916 // Subcomponents of a literal may be effectful.
2917 case ParseNodeKind::Array:
2918 case ParseNodeKind::Object:
2919 MOZ_ASSERT(pn->isArity(PN_LIST));
2920 for (ParseNode* item = pn->pn_head; item; item = item->pn_next) {
2921 if (!checkSideEffects(item, answer)) return false;
2922 if (*answer) return true;
2923 }
2924 return true;
2925
2926 // Most other binary operations (parsed as lists in SpiderMonkey) may
2927 // perform conversions triggering side effects. Math operations perform
2928 // ToNumber and may fail invoking invalid user-defined toString/valueOf:
2929 // |5 < { toString: null }|. |instanceof| throws if provided a
2930 // non-object constructor: |null instanceof null|. |in| throws if given
2931 // a non-object RHS: |5 in null|.
2932 case ParseNodeKind::BitOr:
2933 case ParseNodeKind::BitXor:
2934 case ParseNodeKind::BitAnd:
2935 case ParseNodeKind::Eq:
2936 case ParseNodeKind::Ne:
2937 case ParseNodeKind::Lt:
2938 case ParseNodeKind::Le:
2939 case ParseNodeKind::Gt:
2940 case ParseNodeKind::Ge:
2941 case ParseNodeKind::InstanceOf:
2942 case ParseNodeKind::In:
2943 case ParseNodeKind::Lsh:
2944 case ParseNodeKind::Rsh:
2945 case ParseNodeKind::Ursh:
2946 case ParseNodeKind::Add:
2947 case ParseNodeKind::Sub:
2948 case ParseNodeKind::Star:
2949 case ParseNodeKind::Div:
2950 case ParseNodeKind::Mod:
2951 case ParseNodeKind::Pow:
2952 MOZ_ASSERT(pn->isArity(PN_LIST));
2953 MOZ_ASSERT(pn->pn_count >= 2);
2954 *answer = true;
2955 return true;
2956
2957 case ParseNodeKind::Colon:
2958 case ParseNodeKind::Case:
2959 MOZ_ASSERT(pn->isArity(PN_BINARY));
2960 if (!checkSideEffects(pn->pn_left, answer)) return false;
2961 if (*answer) return true;
2962 return checkSideEffects(pn->pn_right, answer);
2963
2964 // More getters.
2965 case ParseNodeKind::Elem:
2966 MOZ_ASSERT(pn->isArity(PN_BINARY));
2967 *answer = true;
2968 return true;
2969
2970 // These affect visible names in this code, or in other code.
2971 case ParseNodeKind::Import:
2972 case ParseNodeKind::ExportFrom:
2973 case ParseNodeKind::ExportDefault:
2974 MOZ_ASSERT(pn->isArity(PN_BINARY));
2975 *answer = true;
2976 return true;
2977
2978 // Likewise.
2979 case ParseNodeKind::Export:
2980 MOZ_ASSERT(pn->isArity(PN_UNARY));
2981 *answer = true;
2982 return true;
2983
2984 // Every part of a loop might be effect-free, but looping infinitely *is*
2985 // an effect. (Language lawyer trivia: C++ says threads can be assumed
2986 // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
2987 // implementation's equivalent of the below could set |*answer = false;|
2988 // if all loop sub-nodes set |*answer = false|!)
2989 case ParseNodeKind::DoWhile:
2990 case ParseNodeKind::While:
2991 case ParseNodeKind::For:
2992 MOZ_ASSERT(pn->isArity(PN_BINARY));
2993 *answer = true;
2994 return true;
2995
2996 // Declarations affect the name set of the relevant scope.
2997 case ParseNodeKind::Var:
2998 case ParseNodeKind::Const:
2999 case ParseNodeKind::Let:
3000 MOZ_ASSERT(pn->isArity(PN_LIST));
3001 *answer = true;
3002 return true;
3003
3004 case ParseNodeKind::If:
3005 case ParseNodeKind::Conditional:
3006 MOZ_ASSERT(pn->isArity(PN_TERNARY));
3007 if (!checkSideEffects(pn->pn_kid1, answer)) return false;
3008 if (*answer) return true;
3009 if (!checkSideEffects(pn->pn_kid2, answer)) return false;
3010 if (*answer) return true;
3011 if ((pn = pn->pn_kid3)) goto restart;
3012 return true;
3013
3014 // Function calls can invoke non-local code.
3015 case ParseNodeKind::New:
3016 case ParseNodeKind::Call:
3017 case ParseNodeKind::TaggedTemplate:
3018 case ParseNodeKind::SuperCall:
3019 MOZ_ASSERT(pn->isArity(PN_LIST));
3020 *answer = true;
3021 return true;
3022
3023 case ParseNodeKind::Pipeline:
3024 MOZ_ASSERT(pn->isArity(PN_LIST));
3025 MOZ_ASSERT(pn->pn_count >= 2);
3026 *answer = true;
3027 return true;
3028
3029 // Classes typically introduce names. Even if no name is introduced,
3030 // the heritage and/or class body (through computed property names)
3031 // usually have effects.
3032 case ParseNodeKind::Class:
3033 MOZ_ASSERT(pn->isArity(PN_TERNARY));
3034 *answer = true;
3035 return true;
3036
3037 // |with| calls |ToObject| on its expression and so throws if that value
3038 // is null/undefined.
3039 case ParseNodeKind::With:
3040 MOZ_ASSERT(pn->isArity(PN_BINARY));
3041 *answer = true;
3042 return true;
3043
3044 case ParseNodeKind::Return:
3045 MOZ_ASSERT(pn->isArity(PN_BINARY));
3046 *answer = true;
3047 return true;
3048
3049 case ParseNodeKind::Name:
3050 MOZ_ASSERT(pn->isArity(PN_NAME));
3051 *answer = true;
3052 return true;
3053
3054 // Shorthands could trigger getters: the |x| in the object literal in
3055 // |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
3056 // one. (Of course, it isn't necessary to use |with| for a shorthand to
3057 // trigger a getter.)
3058 case ParseNodeKind::Shorthand:
3059 MOZ_ASSERT(pn->isArity(PN_BINARY));
3060 *answer = true;
3061 return true;
3062
3063 case ParseNodeKind::Function:
3064 MOZ_ASSERT(pn->isArity(PN_CODE));
3065 /*
3066 * A named function, contrary to ES3, is no longer effectful, because
3067 * we bind its name lexically (using JSOP_CALLEE) instead of creating
3068 * an Object instance and binding a readonly, permanent property in it
3069 * (the object and binding can be detected and hijacked or captured).
3070 * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
3071 */
3072 *answer = false;
3073 return true;
3074
3075 case ParseNodeKind::Module:
3076 *answer = false;
3077 return true;
3078
3079 case ParseNodeKind::Try:
3080 MOZ_ASSERT(pn->isArity(PN_TERNARY));
3081 if (!checkSideEffects(pn->pn_kid1, answer)) return false;
3082 if (*answer) return true;
3083 if (ParseNode* catchScope = pn->pn_kid2) {
3084 MOZ_ASSERT(catchScope->isKind(ParseNodeKind::LexicalScope));
3085 if (!checkSideEffects(catchScope, answer)) return false;
3086 if (*answer) return true;
3087 }
3088 if (ParseNode* finallyBlock = pn->pn_kid3) {
3089 if (!checkSideEffects(finallyBlock, answer)) return false;
3090 }
3091 return true;
3092
3093 case ParseNodeKind::Catch:
3094 MOZ_ASSERT(pn->isArity(PN_BINARY));
3095 if (ParseNode* name = pn->pn_left) {
3096 if (!checkSideEffects(name, answer)) return false;
3097 if (*answer) return true;
3098 }
3099 return checkSideEffects(pn->pn_right, answer);
3100
3101 case ParseNodeKind::Switch:
3102 MOZ_ASSERT(pn->isArity(PN_BINARY));
3103 if (!checkSideEffects(pn->pn_left, answer)) return false;
3104 return *answer || checkSideEffects(pn->pn_right, answer);
3105
3106 case ParseNodeKind::Label:
3107 MOZ_ASSERT(pn->isArity(PN_NAME));
3108 return checkSideEffects(pn->expr(), answer);
3109
3110 case ParseNodeKind::LexicalScope:
3111 MOZ_ASSERT(pn->isArity(PN_SCOPE));
3112 return checkSideEffects(pn->scopeBody(), answer);
3113
3114 // We could methodically check every interpolated expression, but it's
3115 // probably not worth the trouble. Treat template strings as effect-free
3116 // only if they don't contain any substitutions.
3117 case ParseNodeKind::TemplateStringList:
3118 MOZ_ASSERT(pn->isArity(PN_LIST));
3119 MOZ_ASSERT(pn->pn_count > 0);
3120 MOZ_ASSERT((pn->pn_count % 2) == 1,
3121 "template strings must alternate template and substitution "
3122 "parts");
3123 *answer = pn->pn_count > 1;
3124 return true;
3125
3126 // This should be unreachable but is left as-is for now.
3127 case ParseNodeKind::ParamsBody:
3128 *answer = true;
3129 return true;
3130
3131 case ParseNodeKind::ForIn: // by ParseNodeKind::For
3132 case ParseNodeKind::ForOf: // by ParseNodeKind::For
3133 case ParseNodeKind::ForHead: // by ParseNodeKind::For
3134 case ParseNodeKind::ClassMethod: // by ParseNodeKind::Class
3135 case ParseNodeKind::ClassNames: // by ParseNodeKind::Class
3136 case ParseNodeKind::ClassMethodList: // by ParseNodeKind::Class
3137 case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
3138 case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
3139 case ParseNodeKind::ExportBatchSpec: // by ParseNodeKind::Export
3140 case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
3141 case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
3142 case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
3143 case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
3144 case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
3145 MOZ_CRASH("handled by parent nodes");
3146
3147 case ParseNodeKind::Limit: // invalid sentinel value
3148 MOZ_CRASH("invalid node kind");
3149 }
3150
3151 MOZ_CRASH(
3152 "invalid, unenumerated ParseNodeKind value encountered in "
3153 "BytecodeEmitter::checkSideEffects");
3154 }
3155
isInLoop()3156 bool BytecodeEmitter::isInLoop() {
3157 return findInnermostNestableControl<LoopControl>();
3158 }
3159
checkSingletonContext()3160 bool BytecodeEmitter::checkSingletonContext() {
3161 if (!script->treatAsRunOnce() || sc->isFunctionBox() || isInLoop())
3162 return false;
3163 hasSingletons = true;
3164 return true;
3165 }
3166
checkRunOnceContext()3167 bool BytecodeEmitter::checkRunOnceContext() {
3168 return checkSingletonContext() || (!isInLoop() && isRunOnceLambda());
3169 }
3170
needsImplicitThis()3171 bool BytecodeEmitter::needsImplicitThis() {
3172 // Short-circuit if there is an enclosing 'with' scope.
3173 if (sc->inWith()) return true;
3174
3175 // Otherwise see if the current point is under a 'with'.
3176 for (EmitterScope* es = innermostEmitterScope(); es;
3177 es = es->enclosingInFrame()) {
3178 if (es->scope(this)->kind() == ScopeKind::With) return true;
3179 }
3180
3181 return false;
3182 }
3183
maybeSetDisplayURL()3184 bool BytecodeEmitter::maybeSetDisplayURL() {
3185 if (tokenStream().hasDisplayURL()) {
3186 if (!parser.ss()->setDisplayURL(cx, tokenStream().displayURL()))
3187 return false;
3188 }
3189 return true;
3190 }
3191
maybeSetSourceMap()3192 bool BytecodeEmitter::maybeSetSourceMap() {
3193 if (tokenStream().hasSourceMapURL()) {
3194 MOZ_ASSERT(!parser.ss()->hasSourceMapURL());
3195 if (!parser.ss()->setSourceMapURL(cx, tokenStream().sourceMapURL()))
3196 return false;
3197 }
3198
3199 /*
3200 * Source map URLs passed as a compile option (usually via a HTTP source map
3201 * header) override any source map urls passed as comment pragmas.
3202 */
3203 if (parser.options().sourceMapURL()) {
3204 // Warn about the replacement, but use the new one.
3205 if (parser.ss()->hasSourceMapURL()) {
3206 if (!parser.warningNoOffset(JSMSG_ALREADY_HAS_PRAGMA,
3207 parser.ss()->filename(),
3208 "//# sourceMappingURL")) {
3209 return false;
3210 }
3211 }
3212
3213 if (!parser.ss()->setSourceMapURL(cx, parser.options().sourceMapURL()))
3214 return false;
3215 }
3216
3217 return true;
3218 }
3219
tellDebuggerAboutCompiledScript(JSContext * cx)3220 void BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext* cx) {
3221 // Note: when parsing off thread the resulting scripts need to be handed to
3222 // the debugger after rejoining to the active thread.
3223 if (cx->helperThread()) return;
3224
3225 // Lazy scripts are never top level (despite always being invoked with a
3226 // nullptr parent), and so the hook should never be fired.
3227 if (emitterMode != LazyFunction && !parent) Debugger::onNewScript(cx, script);
3228 }
3229
tokenStream()3230 inline TokenStreamAnyChars& BytecodeEmitter::tokenStream() {
3231 return parser.tokenStream();
3232 }
3233
reportError(ParseNode * pn,unsigned errorNumber,...)3234 void BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) {
3235 TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
3236
3237 va_list args;
3238 va_start(args, errorNumber);
3239
3240 ErrorMetadata metadata;
3241 if (parser.computeErrorMetadata(&metadata, pos.begin))
3242 ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber,
3243 args);
3244
3245 va_end(args);
3246 }
3247
reportExtraWarning(ParseNode * pn,unsigned errorNumber,...)3248 bool BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber,
3249 ...) {
3250 TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
3251
3252 va_list args;
3253 va_start(args, errorNumber);
3254
3255 bool result = parser.reportExtraWarningErrorNumberVA(nullptr, pos.begin,
3256 errorNumber, &args);
3257
3258 va_end(args);
3259 return result;
3260 }
3261
emitNewInit(JSProtoKey key)3262 bool BytecodeEmitter::emitNewInit(JSProtoKey key) {
3263 const size_t len = 1 + UINT32_INDEX_LEN;
3264 ptrdiff_t offset;
3265 if (!emitCheck(len, &offset)) return false;
3266
3267 jsbytecode* code = this->code(offset);
3268 code[0] = JSOP_NEWINIT;
3269 code[1] = jsbytecode(key);
3270 code[2] = 0;
3271 code[3] = 0;
3272 code[4] = 0;
3273 checkTypeSet(JSOP_NEWINIT);
3274 updateDepth(offset);
3275 return true;
3276 }
3277
iteratorResultShape(unsigned * shape)3278 bool BytecodeEmitter::iteratorResultShape(unsigned* shape) {
3279 // No need to do any guessing for the object kind, since we know exactly how
3280 // many properties we plan to have.
3281 gc::AllocKind kind = gc::GetGCObjectKind(2);
3282 RootedPlainObject obj(
3283 cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
3284 if (!obj) return false;
3285
3286 Rooted<jsid> value_id(cx, NameToId(cx->names().value));
3287 Rooted<jsid> done_id(cx, NameToId(cx->names().done));
3288 if (!NativeDefineDataProperty(cx, obj, value_id, UndefinedHandleValue,
3289 JSPROP_ENUMERATE))
3290 return false;
3291 if (!NativeDefineDataProperty(cx, obj, done_id, UndefinedHandleValue,
3292 JSPROP_ENUMERATE))
3293 return false;
3294
3295 ObjectBox* objbox = parser.newObjectBox(obj);
3296 if (!objbox) return false;
3297
3298 *shape = objectList.add(objbox);
3299
3300 return true;
3301 }
3302
emitPrepareIteratorResult()3303 bool BytecodeEmitter::emitPrepareIteratorResult() {
3304 unsigned shape;
3305 if (!iteratorResultShape(&shape)) return false;
3306 return emitIndex32(JSOP_NEWOBJECT, shape);
3307 }
3308
emitFinishIteratorResult(bool done)3309 bool BytecodeEmitter::emitFinishIteratorResult(bool done) {
3310 uint32_t value_id;
3311 if (!makeAtomIndex(cx->names().value, &value_id)) return false;
3312 uint32_t done_id;
3313 if (!makeAtomIndex(cx->names().done, &done_id)) return false;
3314
3315 if (!emitIndex32(JSOP_INITPROP, value_id)) return false;
3316 if (!emit1(done ? JSOP_TRUE : JSOP_FALSE)) return false;
3317 if (!emitIndex32(JSOP_INITPROP, done_id)) return false;
3318 return true;
3319 }
3320
emitGetNameAtLocation(JSAtom * name,const NameLocation & loc,bool callContext)3321 bool BytecodeEmitter::emitGetNameAtLocation(JSAtom* name,
3322 const NameLocation& loc,
3323 bool callContext) {
3324 switch (loc.kind()) {
3325 case NameLocation::Kind::Dynamic:
3326 if (!emitAtomOp(name, JSOP_GETNAME)) return false;
3327 break;
3328
3329 case NameLocation::Kind::Global:
3330 if (!emitAtomOp(name, JSOP_GETGNAME)) return false;
3331 break;
3332
3333 case NameLocation::Kind::Intrinsic:
3334 if (!emitAtomOp(name, JSOP_GETINTRINSIC)) return false;
3335 break;
3336
3337 case NameLocation::Kind::NamedLambdaCallee:
3338 if (!emit1(JSOP_CALLEE)) return false;
3339 break;
3340
3341 case NameLocation::Kind::Import:
3342 if (!emitAtomOp(name, JSOP_GETIMPORT)) return false;
3343 break;
3344
3345 case NameLocation::Kind::ArgumentSlot:
3346 if (!emitArgOp(JSOP_GETARG, loc.argumentSlot())) return false;
3347 break;
3348
3349 case NameLocation::Kind::FrameSlot:
3350 if (loc.isLexical()) {
3351 if (!emitTDZCheckIfNeeded(name, loc)) return false;
3352 }
3353 if (!emitLocalOp(JSOP_GETLOCAL, loc.frameSlot())) return false;
3354 break;
3355
3356 case NameLocation::Kind::EnvironmentCoordinate:
3357 if (loc.isLexical()) {
3358 if (!emitTDZCheckIfNeeded(name, loc)) return false;
3359 }
3360 if (!emitEnvCoordOp(JSOP_GETALIASEDVAR, loc.environmentCoordinate()))
3361 return false;
3362 break;
3363
3364 case NameLocation::Kind::DynamicAnnexBVar:
3365 MOZ_CRASH(
3366 "Synthesized vars for Annex B.3.3 should only be used in "
3367 "initialization");
3368 }
3369
3370 // Need to provide |this| value for call.
3371 if (callContext) {
3372 switch (loc.kind()) {
3373 case NameLocation::Kind::Dynamic: {
3374 JSOp thisOp =
3375 needsImplicitThis() ? JSOP_IMPLICITTHIS : JSOP_GIMPLICITTHIS;
3376 if (!emitAtomOp(name, thisOp)) return false;
3377 break;
3378 }
3379
3380 case NameLocation::Kind::Global:
3381 if (!emitAtomOp(name, JSOP_GIMPLICITTHIS)) return false;
3382 break;
3383
3384 case NameLocation::Kind::Intrinsic:
3385 case NameLocation::Kind::NamedLambdaCallee:
3386 case NameLocation::Kind::Import:
3387 case NameLocation::Kind::ArgumentSlot:
3388 case NameLocation::Kind::FrameSlot:
3389 case NameLocation::Kind::EnvironmentCoordinate:
3390 if (!emit1(JSOP_UNDEFINED)) return false;
3391 break;
3392
3393 case NameLocation::Kind::DynamicAnnexBVar:
3394 MOZ_CRASH(
3395 "Synthesized vars for Annex B.3.3 should only be used in "
3396 "initialization");
3397 }
3398 }
3399
3400 return true;
3401 }
3402
emitGetName(ParseNode * pn,bool callContext)3403 bool BytecodeEmitter::emitGetName(ParseNode* pn, bool callContext) {
3404 return emitGetName(pn->name(), callContext);
3405 }
3406
3407 template <typename RHSEmitter>
emitSetOrInitializeNameAtLocation(HandleAtom name,const NameLocation & loc,RHSEmitter emitRhs,bool initialize)3408 bool BytecodeEmitter::emitSetOrInitializeNameAtLocation(HandleAtom name,
3409 const NameLocation& loc,
3410 RHSEmitter emitRhs,
3411 bool initialize) {
3412 bool emittedBindOp = false;
3413
3414 switch (loc.kind()) {
3415 case NameLocation::Kind::Dynamic:
3416 case NameLocation::Kind::Import:
3417 case NameLocation::Kind::DynamicAnnexBVar: {
3418 uint32_t atomIndex;
3419 if (!makeAtomIndex(name, &atomIndex)) return false;
3420 if (loc.kind() == NameLocation::Kind::DynamicAnnexBVar) {
3421 // Annex B vars always go on the nearest variable environment,
3422 // even if lexical environments in between contain same-named
3423 // bindings.
3424 if (!emit1(JSOP_BINDVAR)) return false;
3425 } else {
3426 if (!emitIndexOp(JSOP_BINDNAME, atomIndex)) return false;
3427 }
3428 emittedBindOp = true;
3429 if (!emitRhs(this, loc, emittedBindOp)) return false;
3430 if (!emitIndexOp(strictifySetNameOp(JSOP_SETNAME), atomIndex))
3431 return false;
3432 break;
3433 }
3434
3435 case NameLocation::Kind::Global: {
3436 JSOp op;
3437 uint32_t atomIndex;
3438 if (!makeAtomIndex(name, &atomIndex)) return false;
3439 if (loc.isLexical() && initialize) {
3440 // INITGLEXICAL always gets the global lexical scope. It doesn't
3441 // need a BINDGNAME.
3442 MOZ_ASSERT(innermostScope()->is<GlobalScope>());
3443 op = JSOP_INITGLEXICAL;
3444 } else {
3445 if (!emitIndexOp(JSOP_BINDGNAME, atomIndex)) return false;
3446 emittedBindOp = true;
3447 op = strictifySetNameOp(JSOP_SETGNAME);
3448 }
3449 if (!emitRhs(this, loc, emittedBindOp)) return false;
3450 if (!emitIndexOp(op, atomIndex)) return false;
3451 break;
3452 }
3453
3454 case NameLocation::Kind::Intrinsic:
3455 if (!emitRhs(this, loc, emittedBindOp)) return false;
3456 if (!emitAtomOp(name, JSOP_SETINTRINSIC)) return false;
3457 break;
3458
3459 case NameLocation::Kind::NamedLambdaCallee:
3460 if (!emitRhs(this, loc, emittedBindOp)) return false;
3461 // Assigning to the named lambda is a no-op in sloppy mode but
3462 // throws in strict mode.
3463 if (sc->strict() && !emit1(JSOP_THROWSETCALLEE)) return false;
3464 break;
3465
3466 case NameLocation::Kind::ArgumentSlot: {
3467 // If we assign to a positional formal parameter and the arguments
3468 // object is unmapped (strict mode or function with
3469 // default/rest/destructing args), parameters do not alias
3470 // arguments[i], and to make the arguments object reflect initial
3471 // parameter values prior to any mutation we create it eagerly
3472 // whenever parameters are (or might, in the case of calls to eval)
3473 // assigned.
3474 FunctionBox* funbox = sc->asFunctionBox();
3475 if (funbox->argumentsHasLocalBinding() && !funbox->hasMappedArgsObj())
3476 funbox->setDefinitelyNeedsArgsObj();
3477
3478 if (!emitRhs(this, loc, emittedBindOp)) return false;
3479 if (!emitArgOp(JSOP_SETARG, loc.argumentSlot())) return false;
3480 break;
3481 }
3482
3483 case NameLocation::Kind::FrameSlot: {
3484 JSOp op = JSOP_SETLOCAL;
3485 if (!emitRhs(this, loc, emittedBindOp)) return false;
3486 if (loc.isLexical()) {
3487 if (initialize) {
3488 op = JSOP_INITLEXICAL;
3489 } else {
3490 if (loc.isConst()) op = JSOP_THROWSETCONST;
3491
3492 if (!emitTDZCheckIfNeeded(name, loc)) return false;
3493 }
3494 }
3495 if (!emitLocalOp(op, loc.frameSlot())) return false;
3496 if (op == JSOP_INITLEXICAL) {
3497 if (!innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ))
3498 return false;
3499 }
3500 break;
3501 }
3502
3503 case NameLocation::Kind::EnvironmentCoordinate: {
3504 JSOp op = JSOP_SETALIASEDVAR;
3505 if (!emitRhs(this, loc, emittedBindOp)) return false;
3506 if (loc.isLexical()) {
3507 if (initialize) {
3508 op = JSOP_INITALIASEDLEXICAL;
3509 } else {
3510 if (loc.isConst()) op = JSOP_THROWSETALIASEDCONST;
3511
3512 if (!emitTDZCheckIfNeeded(name, loc)) return false;
3513 }
3514 }
3515 if (loc.bindingKind() == BindingKind::NamedLambdaCallee) {
3516 // Assigning to the named lambda is a no-op in sloppy mode and throws
3517 // in strict mode.
3518 op = JSOP_THROWSETALIASEDCONST;
3519 if (sc->strict() && !emitEnvCoordOp(op, loc.environmentCoordinate()))
3520 return false;
3521 } else {
3522 if (!emitEnvCoordOp(op, loc.environmentCoordinate())) return false;
3523 }
3524 if (op == JSOP_INITALIASEDLEXICAL) {
3525 if (!innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ))
3526 return false;
3527 }
3528 break;
3529 }
3530 }
3531
3532 return true;
3533 }
3534
emitTDZCheckIfNeeded(JSAtom * name,const NameLocation & loc)3535 bool BytecodeEmitter::emitTDZCheckIfNeeded(JSAtom* name,
3536 const NameLocation& loc) {
3537 // Dynamic accesses have TDZ checks built into their VM code and should
3538 // never emit explicit TDZ checks.
3539 MOZ_ASSERT(loc.hasKnownSlot());
3540 MOZ_ASSERT(loc.isLexical());
3541
3542 Maybe<MaybeCheckTDZ> check =
3543 innermostTDZCheckCache->needsTDZCheck(this, name);
3544 if (!check) return false;
3545
3546 // We've already emitted a check in this basic block.
3547 if (*check == DontCheckTDZ) return true;
3548
3549 if (loc.kind() == NameLocation::Kind::FrameSlot) {
3550 if (!emitLocalOp(JSOP_CHECKLEXICAL, loc.frameSlot())) return false;
3551 } else {
3552 if (!emitEnvCoordOp(JSOP_CHECKALIASEDLEXICAL, loc.environmentCoordinate()))
3553 return false;
3554 }
3555
3556 return innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ);
3557 }
3558
emitPropLHS(ParseNode * pn)3559 bool BytecodeEmitter::emitPropLHS(ParseNode* pn) {
3560 MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot));
3561 MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper());
3562
3563 ParseNode* pn2 = pn->pn_expr;
3564
3565 /*
3566 * If the object operand is also a dotted property reference, reverse the
3567 * list linked via pn_expr temporarily so we can iterate over it from the
3568 * bottom up (reversing again as we go), to avoid excessive recursion.
3569 */
3570 if (pn2->isKind(ParseNodeKind::Dot) && !pn2->as<PropertyAccess>().isSuper()) {
3571 ParseNode* pndot = pn2;
3572 ParseNode* pnup = nullptr;
3573 ParseNode* pndown;
3574 for (;;) {
3575 /* Reverse pndot->pn_expr to point up, not down. */
3576 pndown = pndot->pn_expr;
3577 pndot->pn_expr = pnup;
3578 if (!pndown->isKind(ParseNodeKind::Dot) ||
3579 pndown->as<PropertyAccess>().isSuper())
3580 break;
3581 pnup = pndot;
3582 pndot = pndown;
3583 }
3584
3585 /* pndown is a primary expression, not a dotted property reference. */
3586 if (!emitTree(pndown)) return false;
3587
3588 do {
3589 /* Walk back up the list, emitting annotated name ops. */
3590 if (!emitAtomOp(pndot, JSOP_GETPROP)) return false;
3591
3592 /* Reverse the pn_expr link again. */
3593 pnup = pndot->pn_expr;
3594 pndot->pn_expr = pndown;
3595 pndown = pndot;
3596 } while ((pndot = pnup) != nullptr);
3597 return true;
3598 }
3599
3600 // The non-optimized case.
3601 return emitTree(pn2);
3602 }
3603
emitSuperPropLHS(ParseNode * superBase,bool isCall)3604 bool BytecodeEmitter::emitSuperPropLHS(ParseNode* superBase, bool isCall) {
3605 if (!emitGetThisForSuperBase(superBase)) return false;
3606 if (isCall && !emit1(JSOP_DUP)) return false;
3607 if (!emit1(JSOP_SUPERBASE)) return false;
3608 return true;
3609 }
3610
emitPropOp(ParseNode * pn,JSOp op)3611 bool BytecodeEmitter::emitPropOp(ParseNode* pn, JSOp op) {
3612 MOZ_ASSERT(pn->isArity(PN_NAME));
3613
3614 if (!emitPropLHS(pn)) return false;
3615
3616 if (op == JSOP_CALLPROP && !emit1(JSOP_DUP)) return false;
3617
3618 if (!emitAtomOp(pn, op)) return false;
3619
3620 if (op == JSOP_CALLPROP && !emit1(JSOP_SWAP)) return false;
3621
3622 return true;
3623 }
3624
emitSuperPropOp(ParseNode * pn,JSOp op,bool isCall)3625 bool BytecodeEmitter::emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall) {
3626 ParseNode* base = &pn->as<PropertyAccess>().expression();
3627 if (!emitSuperPropLHS(base, isCall)) return false;
3628
3629 if (!emitAtomOp(pn, op)) return false;
3630
3631 if (isCall && !emit1(JSOP_SWAP)) return false;
3632
3633 return true;
3634 }
3635
emitPropIncDec(ParseNode * pn)3636 bool BytecodeEmitter::emitPropIncDec(ParseNode* pn) {
3637 MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Dot));
3638
3639 bool post;
3640 bool isSuper = pn->pn_kid->as<PropertyAccess>().isSuper();
3641 JSOp binop = GetIncDecInfo(pn->getKind(), &post);
3642
3643 if (isSuper) {
3644 ParseNode* base = &pn->pn_kid->as<PropertyAccess>().expression();
3645 if (!emitSuperPropLHS(base)) // THIS OBJ
3646 return false;
3647 if (!emit1(JSOP_DUP2)) // THIS OBJ THIS OBJ
3648 return false;
3649 } else {
3650 if (!emitPropLHS(pn->pn_kid)) // OBJ
3651 return false;
3652 if (!emit1(JSOP_DUP)) // OBJ OBJ
3653 return false;
3654 }
3655 if (!emitAtomOp(pn->pn_kid,
3656 isSuper ? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
3657 return false;
3658 if (!emit1(JSOP_POS)) // OBJ N
3659 return false;
3660 if (post && !emit1(JSOP_DUP)) // OBJ N? N
3661 return false;
3662 if (!emit1(JSOP_ONE)) // OBJ N? N 1
3663 return false;
3664 if (!emit1(binop)) // OBJ N? N+1
3665 return false;
3666
3667 if (post) {
3668 if (!emit2(JSOP_PICK, 2 + isSuper)) // N? N+1 OBJ
3669 return false;
3670 if (!emit1(JSOP_SWAP)) // N? OBJ N+1
3671 return false;
3672 if (isSuper) {
3673 if (!emit2(JSOP_PICK, 3)) // N THIS N+1 OBJ
3674 return false;
3675 if (!emit1(JSOP_SWAP)) // N THIS OBJ N+1
3676 return false;
3677 }
3678 }
3679
3680 JSOp setOp =
3681 isSuper ? sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
3682 : sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
3683 if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1
3684 return false;
3685 if (post && !emit1(JSOP_POP)) // RESULT
3686 return false;
3687
3688 return true;
3689 }
3690
emitGetNameAtLocationForCompoundAssignment(JSAtom * name,const NameLocation & loc)3691 bool BytecodeEmitter::emitGetNameAtLocationForCompoundAssignment(
3692 JSAtom* name, const NameLocation& loc) {
3693 if (loc.kind() == NameLocation::Kind::Dynamic) {
3694 // For dynamic accesses we need to emit GETBOUNDNAME instead of
3695 // GETNAME for correctness: looking up @@unscopables on the
3696 // environment chain (due to 'with' environments) must only happen
3697 // once.
3698 //
3699 // GETBOUNDNAME uses the environment already pushed on the stack from
3700 // the earlier BINDNAME.
3701 if (!emit1(JSOP_DUP)) // ENV ENV
3702 return false;
3703 if (!emitAtomOp(name, JSOP_GETBOUNDNAME)) // ENV V
3704 return false;
3705 } else {
3706 if (!emitGetNameAtLocation(name, loc)) // ENV? V
3707 return false;
3708 }
3709
3710 return true;
3711 }
3712
emitNameIncDec(ParseNode * pn)3713 bool BytecodeEmitter::emitNameIncDec(ParseNode* pn) {
3714 MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Name));
3715
3716 bool post;
3717 JSOp binop = GetIncDecInfo(pn->getKind(), &post);
3718
3719 auto emitRhs = [pn, post, binop](BytecodeEmitter* bce,
3720 const NameLocation& loc,
3721 bool emittedBindOp) {
3722 JSAtom* name = pn->pn_kid->name();
3723 if (!bce->emitGetNameAtLocationForCompoundAssignment(name, loc)) // ENV? V
3724 return false;
3725 if (!bce->emit1(JSOP_POS)) // ENV? N
3726 return false;
3727 if (post && !bce->emit1(JSOP_DUP)) // ENV? N? N
3728 return false;
3729 if (!bce->emit1(JSOP_ONE)) // ENV? N? N 1
3730 return false;
3731 if (!bce->emit1(binop)) // ENV? N? N+1
3732 return false;
3733
3734 if (post && emittedBindOp) {
3735 if (!bce->emit2(JSOP_PICK, 2)) // N? N+1 ENV?
3736 return false;
3737 if (!bce->emit1(JSOP_SWAP)) // N? ENV? N+1
3738 return false;
3739 }
3740
3741 return true;
3742 };
3743
3744 if (!emitSetName(pn->pn_kid, emitRhs)) return false;
3745
3746 if (post && !emit1(JSOP_POP)) return false;
3747
3748 return true;
3749 }
3750
emitElemOperands(ParseNode * pn,EmitElemOption opts)3751 bool BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts) {
3752 MOZ_ASSERT(pn->isArity(PN_BINARY));
3753
3754 if (!emitTree(pn->pn_left)) return false;
3755
3756 if (opts == EmitElemOption::IncDec) {
3757 if (!emit1(JSOP_CHECKOBJCOERCIBLE)) return false;
3758 } else if (opts == EmitElemOption::Call) {
3759 if (!emit1(JSOP_DUP)) return false;
3760 }
3761
3762 if (!emitTree(pn->pn_right)) return false;
3763
3764 if (opts == EmitElemOption::Set) {
3765 if (!emit2(JSOP_PICK, 2)) return false;
3766 } else if (opts == EmitElemOption::IncDec ||
3767 opts == EmitElemOption::CompoundAssign) {
3768 if (!emit1(JSOP_TOID)) return false;
3769 }
3770 return true;
3771 }
3772
emitSuperElemOperands(ParseNode * pn,EmitElemOption opts)3773 bool BytecodeEmitter::emitSuperElemOperands(ParseNode* pn,
3774 EmitElemOption opts) {
3775 MOZ_ASSERT(pn->isKind(ParseNodeKind::Elem) &&
3776 pn->as<PropertyByValue>().isSuper());
3777
3778 // The ordering here is somewhat screwy. We need to evaluate the propval
3779 // first, by spec. Do a little dance to not emit more than one JSOP_THIS.
3780 // Since JSOP_THIS might throw in derived class constructors, we cannot
3781 // just push it earlier as the receiver. We have to swap it down instead.
3782
3783 if (!emitTree(pn->pn_right)) return false;
3784
3785 // We need to convert the key to an object id first, so that we do not do
3786 // it inside both the GETELEM and the SETELEM.
3787 if (opts == EmitElemOption::IncDec ||
3788 opts == EmitElemOption::CompoundAssign) {
3789 if (!emit1(JSOP_TOID)) return false;
3790 }
3791
3792 if (!emitGetThisForSuperBase(pn->pn_left)) return false;
3793
3794 if (opts == EmitElemOption::Call) {
3795 if (!emit1(JSOP_SWAP)) return false;
3796
3797 // We need another |this| on top, also
3798 if (!emitDupAt(1)) return false;
3799 }
3800
3801 if (!emit1(JSOP_SUPERBASE)) return false;
3802
3803 if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3)) return false;
3804
3805 return true;
3806 }
3807
emitElemOpBase(JSOp op)3808 bool BytecodeEmitter::emitElemOpBase(JSOp op) {
3809 if (!emit1(op)) return false;
3810
3811 checkTypeSet(op);
3812 return true;
3813 }
3814
emitElemOp(ParseNode * pn,JSOp op)3815 bool BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op) {
3816 EmitElemOption opts = EmitElemOption::Get;
3817 if (op == JSOP_CALLELEM)
3818 opts = EmitElemOption::Call;
3819 else if (op == JSOP_SETELEM || op == JSOP_STRICTSETELEM)
3820 opts = EmitElemOption::Set;
3821
3822 return emitElemOperands(pn, opts) && emitElemOpBase(op);
3823 }
3824
emitSuperElemOp(ParseNode * pn,JSOp op,bool isCall)3825 bool BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall) {
3826 EmitElemOption opts = EmitElemOption::Get;
3827 if (isCall)
3828 opts = EmitElemOption::Call;
3829 else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER)
3830 opts = EmitElemOption::Set;
3831
3832 if (!emitSuperElemOperands(pn, opts)) return false;
3833 if (!emitElemOpBase(op)) return false;
3834
3835 if (isCall && !emit1(JSOP_SWAP)) return false;
3836
3837 return true;
3838 }
3839
emitElemIncDec(ParseNode * pn)3840 bool BytecodeEmitter::emitElemIncDec(ParseNode* pn) {
3841 MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Elem));
3842
3843 bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
3844
3845 // We need to convert the key to an object id first, so that we do not do
3846 // it inside both the GETELEM and the SETELEM. This is done by
3847 // emit(Super)ElemOperands.
3848 if (isSuper) {
3849 if (!emitSuperElemOperands(pn->pn_kid, EmitElemOption::IncDec))
3850 return false;
3851 } else {
3852 if (!emitElemOperands(pn->pn_kid, EmitElemOption::IncDec)) return false;
3853 }
3854
3855 bool post;
3856 JSOp binop = GetIncDecInfo(pn->getKind(), &post);
3857
3858 JSOp getOp;
3859 if (isSuper) {
3860 // There's no such thing as JSOP_DUP3, so we have to be creative.
3861 // Note that pushing things again is no fewer JSOps.
3862 if (!emitDupAt(2)) // KEY THIS OBJ KEY
3863 return false;
3864 if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS
3865 return false;
3866 if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS OBJ
3867 return false;
3868 getOp = JSOP_GETELEM_SUPER;
3869 } else {
3870 // OBJ KEY
3871 if (!emit1(JSOP_DUP2)) // OBJ KEY OBJ KEY
3872 return false;
3873 getOp = JSOP_GETELEM;
3874 }
3875 if (!emitElemOpBase(getOp)) // OBJ KEY V
3876 return false;
3877 if (!emit1(JSOP_POS)) // OBJ KEY N
3878 return false;
3879 if (post && !emit1(JSOP_DUP)) // OBJ KEY N? N
3880 return false;
3881 if (!emit1(JSOP_ONE)) // OBJ KEY N? N 1
3882 return false;
3883 if (!emit1(binop)) // OBJ KEY N? N+1
3884 return false;
3885
3886 if (post) {
3887 if (isSuper) {
3888 // We have one more value to rotate around, because of |this|
3889 // on the stack
3890 if (!emit2(JSOP_PICK, 4)) return false;
3891 }
3892 if (!emit2(JSOP_PICK, 3 + isSuper)) // KEY N N+1 OBJ
3893 return false;
3894 if (!emit2(JSOP_PICK, 3 + isSuper)) // N N+1 OBJ KEY
3895 return false;
3896 if (!emit2(JSOP_PICK, 2 + isSuper)) // N OBJ KEY N+1
3897 return false;
3898 }
3899
3900 JSOp setOp =
3901 isSuper ? (sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
3902 : (sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM);
3903 if (!emitElemOpBase(setOp)) // N? N+1
3904 return false;
3905 if (post && !emit1(JSOP_POP)) // RESULT
3906 return false;
3907
3908 return true;
3909 }
3910
emitCallIncDec(ParseNode * incDec)3911 bool BytecodeEmitter::emitCallIncDec(ParseNode* incDec) {
3912 MOZ_ASSERT(incDec->isKind(ParseNodeKind::PreIncrement) ||
3913 incDec->isKind(ParseNodeKind::PostIncrement) ||
3914 incDec->isKind(ParseNodeKind::PreDecrement) ||
3915 incDec->isKind(ParseNodeKind::PostDecrement));
3916
3917 MOZ_ASSERT(incDec->pn_kid->isKind(ParseNodeKind::Call));
3918
3919 ParseNode* call = incDec->pn_kid;
3920 if (!emitTree(call)) // CALLRESULT
3921 return false;
3922 if (!emit1(JSOP_POS)) // N
3923 return false;
3924
3925 // The increment/decrement has no side effects, so proceed to throw for
3926 // invalid assignment target.
3927 return emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS);
3928 }
3929
emitNumberOp(double dval)3930 bool BytecodeEmitter::emitNumberOp(double dval) {
3931 int32_t ival;
3932 if (NumberIsInt32(dval, &ival)) {
3933 if (ival == 0) return emit1(JSOP_ZERO);
3934 if (ival == 1) return emit1(JSOP_ONE);
3935 if ((int)(int8_t)ival == ival)
3936 return emit2(JSOP_INT8, uint8_t(int8_t(ival)));
3937
3938 uint32_t u = uint32_t(ival);
3939 if (u < JS_BIT(16)) {
3940 if (!emitUint16Operand(JSOP_UINT16, u)) return false;
3941 } else if (u < JS_BIT(24)) {
3942 ptrdiff_t off;
3943 if (!emitN(JSOP_UINT24, 3, &off)) return false;
3944 SET_UINT24(code(off), u);
3945 } else {
3946 ptrdiff_t off;
3947 if (!emitN(JSOP_INT32, 4, &off)) return false;
3948 SET_INT32(code(off), ival);
3949 }
3950 return true;
3951 }
3952
3953 if (!constList.append(DoubleValue(dval))) return false;
3954
3955 return emitIndex32(JSOP_DOUBLE, constList.length() - 1);
3956 }
3957
3958 /*
3959 * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
3960 * LLVM is deciding to inline this function which uses a lot of stack space
3961 * into emitTree which is recursive and uses relatively little stack space.
3962 */
emitSwitch(ParseNode * pn)3963 MOZ_NEVER_INLINE bool BytecodeEmitter::emitSwitch(ParseNode* pn) {
3964 ParseNode* cases = pn->pn_right;
3965 MOZ_ASSERT(cases->isKind(ParseNodeKind::LexicalScope) ||
3966 cases->isKind(ParseNodeKind::StatementList));
3967
3968 // Emit code for the discriminant.
3969 if (!emitTree(pn->pn_left)) return false;
3970
3971 // Enter the scope before pushing the switch BreakableControl since all
3972 // breaks are under this scope.
3973 Maybe<TDZCheckCache> tdzCache;
3974 Maybe<EmitterScope> emitterScope;
3975 if (cases->isKind(ParseNodeKind::LexicalScope)) {
3976 if (!cases->isEmptyScope()) {
3977 tdzCache.emplace(this);
3978 emitterScope.emplace(this);
3979 if (!emitterScope->enterLexical(this, ScopeKind::Lexical,
3980 cases->scopeBindings()))
3981 return false;
3982 }
3983
3984 // Advance |cases| to refer to the switch case list.
3985 cases = cases->scopeBody();
3986
3987 // A switch statement may contain hoisted functions inside its
3988 // cases. The PNX_FUNCDEFS flag is propagated from the STATEMENTLIST
3989 // bodies of the cases to the case list.
3990 if (cases->pn_xflags & PNX_FUNCDEFS) {
3991 MOZ_ASSERT(emitterScope);
3992 for (ParseNode* caseNode = cases->pn_head; caseNode;
3993 caseNode = caseNode->pn_next) {
3994 if (caseNode->pn_right->pn_xflags & PNX_FUNCDEFS) {
3995 if (!emitHoistedFunctionsInList(caseNode->pn_right)) return false;
3996 }
3997 }
3998 }
3999 }
4000
4001 // After entering the scope, push the switch control.
4002 BreakableControl controlInfo(this, StatementKind::Switch);
4003
4004 ptrdiff_t top = offset();
4005
4006 // Switch bytecodes run from here till end of final case.
4007 uint32_t caseCount = cases->pn_count;
4008 if (caseCount > JS_BIT(16)) {
4009 parser.reportError(JSMSG_TOO_MANY_CASES);
4010 return false;
4011 }
4012
4013 // Try for most optimal, fall back if not dense ints.
4014 JSOp switchOp = JSOP_TABLESWITCH;
4015 uint32_t tableLength = 0;
4016 int32_t low, high;
4017 bool hasDefault = false;
4018 CaseClause* firstCase =
4019 cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
4020 if (caseCount == 0 ||
4021 (caseCount == 1 && (hasDefault = firstCase->isDefault()))) {
4022 caseCount = 0;
4023 low = 0;
4024 high = -1;
4025 } else {
4026 Vector<jsbitmap, 128, SystemAllocPolicy> intmap;
4027 int32_t intmapBitLength = 0;
4028
4029 low = JSVAL_INT_MAX;
4030 high = JSVAL_INT_MIN;
4031
4032 for (CaseClause* caseNode = firstCase; caseNode;
4033 caseNode = caseNode->next()) {
4034 if (caseNode->isDefault()) {
4035 hasDefault = true;
4036 caseCount--; // one of the "cases" was the default
4037 continue;
4038 }
4039
4040 if (switchOp == JSOP_CONDSWITCH) continue;
4041
4042 MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4043
4044 ParseNode* caseValue = caseNode->caseExpression();
4045
4046 if (caseValue->getKind() != ParseNodeKind::Number) {
4047 switchOp = JSOP_CONDSWITCH;
4048 continue;
4049 }
4050
4051 int32_t i;
4052 if (!NumberIsInt32(caseValue->pn_dval, &i)) {
4053 switchOp = JSOP_CONDSWITCH;
4054 continue;
4055 }
4056
4057 if (unsigned(i + int(JS_BIT(15))) >= unsigned(JS_BIT(16))) {
4058 switchOp = JSOP_CONDSWITCH;
4059 continue;
4060 }
4061 if (i < low) low = i;
4062 if (i > high) high = i;
4063
4064 // Check for duplicates, which require a JSOP_CONDSWITCH.
4065 // We bias i by 65536 if it's negative, and hope that's a rare
4066 // case (because it requires a malloc'd bitmap).
4067 if (i < 0) i += JS_BIT(16);
4068 if (i >= intmapBitLength) {
4069 size_t newLength = (i / JS_BITMAP_NBITS) + 1;
4070 if (!intmap.resize(newLength)) return false;
4071 intmapBitLength = newLength * JS_BITMAP_NBITS;
4072 }
4073 if (JS_TEST_BIT(intmap, i)) {
4074 switchOp = JSOP_CONDSWITCH;
4075 continue;
4076 }
4077 JS_SET_BIT(intmap, i);
4078 }
4079
4080 // Compute table length and select condswitch instead if overlarge or
4081 // more than half-sparse.
4082 if (switchOp == JSOP_TABLESWITCH) {
4083 tableLength = uint32_t(high - low + 1);
4084 if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount)
4085 switchOp = JSOP_CONDSWITCH;
4086 }
4087 }
4088
4089 // The note has one or two offsets: first tells total switch code length;
4090 // second (if condswitch) tells offset to first JSOP_CASE.
4091 unsigned noteIndex;
4092 size_t switchSize;
4093 if (switchOp == JSOP_CONDSWITCH) {
4094 // 0 bytes of immediate for unoptimized switch.
4095 switchSize = 0;
4096 if (!newSrcNote3(SRC_CONDSWITCH, 0, 0, ¬eIndex)) return false;
4097 } else {
4098 MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4099
4100 // 3 offsets (len, low, high) before the table, 1 per entry.
4101 switchSize = size_t(JUMP_OFFSET_LEN * (3 + tableLength));
4102 if (!newSrcNote2(SRC_TABLESWITCH, 0, ¬eIndex)) return false;
4103 }
4104
4105 // Emit switchOp followed by switchSize bytes of jump or lookup table.
4106 MOZ_ASSERT(top == offset());
4107 if (!emitN(switchOp, switchSize)) return false;
4108
4109 Vector<CaseClause*, 32, SystemAllocPolicy> table;
4110
4111 JumpList condSwitchDefaultOff;
4112 if (switchOp == JSOP_CONDSWITCH) {
4113 unsigned caseNoteIndex;
4114 bool beforeCases = true;
4115 ptrdiff_t lastCaseOffset = -1;
4116
4117 // The case conditions need their own TDZ cache since they might not
4118 // all execute.
4119 TDZCheckCache tdzCache(this);
4120
4121 // Emit code for evaluating cases and jumping to case statements.
4122 for (CaseClause* caseNode = firstCase; caseNode;
4123 caseNode = caseNode->next()) {
4124 ParseNode* caseValue = caseNode->caseExpression();
4125
4126 // If the expression is a literal, suppress line number emission so
4127 // that debugging works more naturally.
4128 if (caseValue) {
4129 if (!emitTree(
4130 caseValue, ValueUsage::WantValue,
4131 caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE)) {
4132 return false;
4133 }
4134 }
4135
4136 if (!beforeCases) {
4137 // prevCase is the previous JSOP_CASE's bytecode offset.
4138 if (!setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
4139 return false;
4140 }
4141 if (!caseValue) {
4142 // This is the default clause.
4143 continue;
4144 }
4145
4146 if (!newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex)) return false;
4147
4148 // The case clauses are produced before any of the case body. The
4149 // JumpList is saved on the parsed tree, then later restored and
4150 // patched when generating the cases body.
4151 JumpList caseJump;
4152 if (!emitJump(JSOP_CASE, &caseJump)) return false;
4153 caseNode->setOffset(caseJump.offset);
4154 lastCaseOffset = caseJump.offset;
4155
4156 if (beforeCases) {
4157 // Switch note's second offset is to first JSOP_CASE.
4158 unsigned noteCount = notes().length();
4159 if (!setSrcNoteOffset(noteIndex, 1, lastCaseOffset - top)) return false;
4160 unsigned noteCountDelta = notes().length() - noteCount;
4161 if (noteCountDelta != 0) caseNoteIndex += noteCountDelta;
4162 beforeCases = false;
4163 }
4164 }
4165
4166 // If we didn't have an explicit default (which could fall in between
4167 // cases, preventing us from fusing this setSrcNoteOffset with the call
4168 // in the loop above), link the last case to the implicit default for
4169 // the benefit of IonBuilder.
4170 if (!hasDefault && !beforeCases &&
4171 !setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset)) {
4172 return false;
4173 }
4174
4175 // Emit default even if no explicit default statement.
4176 if (!emitJump(JSOP_DEFAULT, &condSwitchDefaultOff)) return false;
4177 } else {
4178 MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4179
4180 // skip default offset.
4181 jsbytecode* pc = code(top + JUMP_OFFSET_LEN);
4182
4183 // Fill in switch bounds, which we know fit in 16-bit offsets.
4184 SET_JUMP_OFFSET(pc, low);
4185 pc += JUMP_OFFSET_LEN;
4186 SET_JUMP_OFFSET(pc, high);
4187 pc += JUMP_OFFSET_LEN;
4188
4189 if (tableLength != 0) {
4190 if (!table.growBy(tableLength)) return false;
4191
4192 for (CaseClause* caseNode = firstCase; caseNode;
4193 caseNode = caseNode->next()) {
4194 if (ParseNode* caseValue = caseNode->caseExpression()) {
4195 MOZ_ASSERT(caseValue->isKind(ParseNodeKind::Number));
4196
4197 int32_t i = int32_t(caseValue->pn_dval);
4198 MOZ_ASSERT(double(i) == caseValue->pn_dval);
4199
4200 i -= low;
4201 MOZ_ASSERT(uint32_t(i) < tableLength);
4202 MOZ_ASSERT(!table[i]);
4203 table[i] = caseNode;
4204 }
4205 }
4206 }
4207 }
4208
4209 JumpTarget defaultOffset{-1};
4210
4211 // Emit code for each case's statements.
4212 for (CaseClause* caseNode = firstCase; caseNode;
4213 caseNode = caseNode->next()) {
4214 if (switchOp == JSOP_CONDSWITCH && !caseNode->isDefault()) {
4215 // The case offset got saved in the caseNode structure after
4216 // emitting the JSOP_CASE jump instruction above.
4217 JumpList caseCond;
4218 caseCond.offset = caseNode->offset();
4219 if (!emitJumpTargetAndPatch(caseCond)) return false;
4220 }
4221
4222 JumpTarget here;
4223 if (!emitJumpTarget(&here)) return false;
4224 if (caseNode->isDefault()) defaultOffset = here;
4225
4226 // If this is emitted as a TABLESWITCH, we'll need to know this case's
4227 // offset later when emitting the table. Store it in the node's
4228 // pn_offset (giving the field a different meaning vs. how we used it
4229 // on the immediately preceding line of code).
4230 caseNode->setOffset(here.offset);
4231
4232 TDZCheckCache tdzCache(this);
4233
4234 if (!emitTree(caseNode->statementList())) return false;
4235 }
4236
4237 if (!hasDefault) {
4238 // If no default case, offset for default is to end of switch.
4239 if (!emitJumpTarget(&defaultOffset)) return false;
4240 }
4241 MOZ_ASSERT(defaultOffset.offset != -1);
4242
4243 // Set the default offset (to end of switch if no default).
4244 jsbytecode* pc;
4245 if (switchOp == JSOP_CONDSWITCH) {
4246 pc = nullptr;
4247 patchJumpsToTarget(condSwitchDefaultOff, defaultOffset);
4248 } else {
4249 MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4250 pc = code(top);
4251 SET_JUMP_OFFSET(pc, defaultOffset.offset - top);
4252 pc += JUMP_OFFSET_LEN;
4253 }
4254
4255 // Set the SRC_SWITCH note's offset operand to tell end of switch.
4256 if (!setSrcNoteOffset(noteIndex, 0, lastNonJumpTargetOffset() - top))
4257 return false;
4258
4259 if (switchOp == JSOP_TABLESWITCH) {
4260 // Skip over the already-initialized switch bounds.
4261 pc += 2 * JUMP_OFFSET_LEN;
4262
4263 // Fill in the jump table, if there is one.
4264 for (uint32_t i = 0; i < tableLength; i++) {
4265 CaseClause* caseNode = table[i];
4266 ptrdiff_t off = caseNode ? caseNode->offset() - top : 0;
4267 SET_JUMP_OFFSET(pc, off);
4268 pc += JUMP_OFFSET_LEN;
4269 }
4270 }
4271
4272 // Patch breaks before leaving the scope, as all breaks are under the
4273 // lexical scope if it exists.
4274 if (!controlInfo.patchBreaks(this)) return false;
4275
4276 if (emitterScope && !emitterScope->leave(this)) return false;
4277
4278 return true;
4279 }
4280
isRunOnceLambda()4281 bool BytecodeEmitter::isRunOnceLambda() {
4282 // The run once lambda flags set by the parser are approximate, and we look
4283 // at properties of the function itself before deciding to emit a function
4284 // as a run once lambda.
4285
4286 if (!(parent && parent->emittingRunOnceLambda) &&
4287 (emitterMode != LazyFunction || !lazyScript->treatAsRunOnce())) {
4288 return false;
4289 }
4290
4291 FunctionBox* funbox = sc->asFunctionBox();
4292 return !funbox->argumentsHasLocalBinding() && !funbox->isGenerator() &&
4293 !funbox->isAsync() && !funbox->function()->explicitName();
4294 }
4295
emitYieldOp(JSOp op)4296 bool BytecodeEmitter::emitYieldOp(JSOp op) {
4297 if (op == JSOP_FINALYIELDRVAL) return emit1(JSOP_FINALYIELDRVAL);
4298
4299 MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT);
4300
4301 ptrdiff_t off;
4302 if (!emitN(op, 3, &off)) return false;
4303
4304 uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
4305 if (yieldAndAwaitIndex >= JS_BIT(24)) {
4306 reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
4307 return false;
4308 }
4309
4310 if (op == JSOP_AWAIT)
4311 yieldAndAwaitOffsetList.numAwaits++;
4312 else
4313 yieldAndAwaitOffsetList.numYields++;
4314
4315 SET_UINT24(code(off), yieldAndAwaitIndex);
4316
4317 if (!yieldAndAwaitOffsetList.append(offset())) return false;
4318
4319 return emit1(JSOP_DEBUGAFTERYIELD);
4320 }
4321
emitSetThis(ParseNode * pn)4322 bool BytecodeEmitter::emitSetThis(ParseNode* pn) {
4323 // ParseNodeKind::SetThis is used to update |this| after a super() call
4324 // in a derived class constructor.
4325
4326 MOZ_ASSERT(pn->isKind(ParseNodeKind::SetThis));
4327 MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::Name));
4328
4329 RootedAtom name(cx, pn->pn_left->name());
4330 auto emitRhs = [&name, pn](BytecodeEmitter* bce, const NameLocation&, bool) {
4331 // Emit the new |this| value.
4332 if (!bce->emitTree(pn->pn_right)) return false;
4333 // Get the original |this| and throw if we already initialized
4334 // it. Do *not* use the NameLocation argument, as that's the special
4335 // lexical location below to deal with super() semantics.
4336 if (!bce->emitGetName(name)) return false;
4337 if (!bce->emit1(JSOP_CHECKTHISREINIT)) return false;
4338 if (!bce->emit1(JSOP_POP)) return false;
4339 return true;
4340 };
4341
4342 // The 'this' binding is not lexical, but due to super() semantics this
4343 // initialization needs to be treated as a lexical one.
4344 NameLocation loc = lookupName(name);
4345 NameLocation lexicalLoc;
4346 if (loc.kind() == NameLocation::Kind::FrameSlot) {
4347 lexicalLoc = NameLocation::FrameSlot(BindingKind::Let, loc.frameSlot());
4348 } else if (loc.kind() == NameLocation::Kind::EnvironmentCoordinate) {
4349 EnvironmentCoordinate coord = loc.environmentCoordinate();
4350 uint8_t hops = AssertedCast<uint8_t>(coord.hops());
4351 lexicalLoc = NameLocation::EnvironmentCoordinate(BindingKind::Let, hops,
4352 coord.slot());
4353 } else {
4354 MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic);
4355 lexicalLoc = loc;
4356 }
4357
4358 return emitSetOrInitializeNameAtLocation(name, lexicalLoc, emitRhs, true);
4359 }
4360
emitScript(ParseNode * body)4361 bool BytecodeEmitter::emitScript(ParseNode* body) {
4362 AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, tokenStream(),
4363 body);
4364
4365 TDZCheckCache tdzCache(this);
4366 EmitterScope emitterScope(this);
4367 if (sc->isGlobalContext()) {
4368 switchToPrologue();
4369 if (!emitterScope.enterGlobal(this, sc->asGlobalContext())) return false;
4370 switchToMain();
4371 } else if (sc->isEvalContext()) {
4372 switchToPrologue();
4373 if (!emitterScope.enterEval(this, sc->asEvalContext())) return false;
4374 switchToMain();
4375 } else {
4376 MOZ_ASSERT(sc->isModuleContext());
4377 if (!emitterScope.enterModule(this, sc->asModuleContext())) return false;
4378 }
4379
4380 setFunctionBodyEndPos(body->pn_pos);
4381
4382 if (sc->isEvalContext() && !sc->strict() &&
4383 body->isKind(ParseNodeKind::LexicalScope) && !body->isEmptyScope()) {
4384 // Sloppy eval scripts may need to emit DEFFUNs in the prologue. If there is
4385 // an immediately enclosed lexical scope, we need to enter the lexical
4386 // scope in the prologue for the DEFFUNs to pick up the right
4387 // environment chain.
4388 EmitterScope lexicalEmitterScope(this);
4389
4390 switchToPrologue();
4391 if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical,
4392 body->scopeBindings()))
4393 return false;
4394 switchToMain();
4395
4396 if (!emitLexicalScopeBody(body->scopeBody())) return false;
4397
4398 if (!lexicalEmitterScope.leave(this)) return false;
4399 } else {
4400 if (!emitTree(body)) return false;
4401 }
4402
4403 if (!updateSourceCoordNotes(body->pn_pos.end)) return false;
4404
4405 if (!emit1(JSOP_RETRVAL)) return false;
4406
4407 if (!emitterScope.leave(this)) return false;
4408
4409 if (!JSScript::fullyInitFromEmitter(cx, script, this)) return false;
4410
4411 // URL and source map information must be set before firing
4412 // Debugger::onNewScript.
4413 if (!maybeSetDisplayURL() || !maybeSetSourceMap()) return false;
4414
4415 tellDebuggerAboutCompiledScript(cx);
4416
4417 return true;
4418 }
4419
emitFunctionScript(ParseNode * body)4420 bool BytecodeEmitter::emitFunctionScript(ParseNode* body) {
4421 FunctionBox* funbox = sc->asFunctionBox();
4422 AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, tokenStream(),
4423 funbox);
4424
4425 // The ordering of these EmitterScopes is important. The named lambda
4426 // scope needs to enclose the function scope needs to enclose the extra
4427 // var scope.
4428
4429 Maybe<EmitterScope> namedLambdaEmitterScope;
4430 if (funbox->namedLambdaBindings()) {
4431 namedLambdaEmitterScope.emplace(this);
4432 if (!namedLambdaEmitterScope->enterNamedLambda(this, funbox)) return false;
4433 }
4434
4435 /*
4436 * Emit a prologue for run-once scripts which will deoptimize JIT code
4437 * if the script ends up running multiple times via foo.caller related
4438 * shenanigans.
4439 *
4440 * Also mark the script so that initializers created within it may be
4441 * given more precise types.
4442 */
4443 if (isRunOnceLambda()) {
4444 script->setTreatAsRunOnce();
4445 MOZ_ASSERT(!script->hasRunOnce());
4446
4447 switchToPrologue();
4448 if (!emit1(JSOP_RUNONCE)) return false;
4449 switchToMain();
4450 }
4451
4452 setFunctionBodyEndPos(body->pn_pos);
4453 if (!emitTree(body)) return false;
4454
4455 if (!updateSourceCoordNotes(body->pn_pos.end)) return false;
4456
4457 // Always end the script with a JSOP_RETRVAL. Some other parts of the
4458 // codebase depend on this opcode,
4459 // e.g. InterpreterRegs::setToEndOfScript.
4460 if (!emit1(JSOP_RETRVAL)) return false;
4461
4462 if (namedLambdaEmitterScope) {
4463 if (!namedLambdaEmitterScope->leave(this)) return false;
4464 namedLambdaEmitterScope.reset();
4465 }
4466
4467 if (!JSScript::fullyInitFromEmitter(cx, script, this)) return false;
4468
4469 // URL and source map information must be set before firing
4470 // Debugger::onNewScript. Only top-level functions need this, as compiling
4471 // the outer scripts of nested functions already processed the source.
4472 if (emitterMode != LazyFunction && !parent) {
4473 if (!maybeSetDisplayURL() || !maybeSetSourceMap()) return false;
4474
4475 tellDebuggerAboutCompiledScript(cx);
4476 }
4477
4478 return true;
4479 }
4480
4481 template <typename NameEmitter>
emitDestructuringDeclsWithEmitter(ParseNode * pattern,NameEmitter emitName)4482 bool BytecodeEmitter::emitDestructuringDeclsWithEmitter(ParseNode* pattern,
4483 NameEmitter emitName) {
4484 if (pattern->isKind(ParseNodeKind::Array)) {
4485 for (ParseNode* element = pattern->pn_head; element;
4486 element = element->pn_next) {
4487 if (element->isKind(ParseNodeKind::Elision)) continue;
4488 ParseNode* target = element;
4489 if (element->isKind(ParseNodeKind::Spread)) {
4490 target = element->pn_kid;
4491 }
4492 if (target->isKind(ParseNodeKind::Assign)) target = target->pn_left;
4493 if (target->isKind(ParseNodeKind::Name)) {
4494 if (!emitName(this, target)) return false;
4495 } else {
4496 if (!emitDestructuringDeclsWithEmitter(target, emitName)) return false;
4497 }
4498 }
4499 return true;
4500 }
4501
4502 MOZ_ASSERT(pattern->isKind(ParseNodeKind::Object));
4503 for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
4504 MOZ_ASSERT(member->isKind(ParseNodeKind::MutateProto) ||
4505 member->isKind(ParseNodeKind::Colon) ||
4506 member->isKind(ParseNodeKind::Shorthand));
4507
4508 ParseNode* target = member->isKind(ParseNodeKind::MutateProto)
4509 ? member->pn_kid
4510 : member->pn_right;
4511
4512 if (target->isKind(ParseNodeKind::Assign)) target = target->pn_left;
4513 if (target->isKind(ParseNodeKind::Name)) {
4514 if (!emitName(this, target)) return false;
4515 } else {
4516 if (!emitDestructuringDeclsWithEmitter(target, emitName)) return false;
4517 }
4518 }
4519 return true;
4520 }
4521
emitDestructuringLHSRef(ParseNode * target,size_t * emitted)4522 bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target,
4523 size_t* emitted) {
4524 *emitted = 0;
4525
4526 if (target->isKind(ParseNodeKind::Spread))
4527 target = target->pn_kid;
4528 else if (target->isKind(ParseNodeKind::Assign))
4529 target = target->pn_left;
4530
4531 // No need to recur into ParseNodeKind::Array and
4532 // ParseNodeKind::Object subpatterns here, since
4533 // emitSetOrInitializeDestructuring does the recursion when
4534 // setting or initializing value. Getting reference doesn't recur.
4535 if (target->isKind(ParseNodeKind::Name) ||
4536 target->isKind(ParseNodeKind::Array) ||
4537 target->isKind(ParseNodeKind::Object)) {
4538 return true;
4539 }
4540
4541 #ifdef DEBUG
4542 int depth = stackDepth;
4543 #endif
4544
4545 switch (target->getKind()) {
4546 case ParseNodeKind::Dot: {
4547 if (target->as<PropertyAccess>().isSuper()) {
4548 if (!emitSuperPropLHS(&target->as<PropertyAccess>().expression()))
4549 return false;
4550 *emitted = 2;
4551 } else {
4552 if (!emitTree(target->pn_expr)) return false;
4553 *emitted = 1;
4554 }
4555 break;
4556 }
4557
4558 case ParseNodeKind::Elem: {
4559 if (target->as<PropertyByValue>().isSuper()) {
4560 if (!emitSuperElemOperands(target, EmitElemOption::Ref)) return false;
4561 *emitted = 3;
4562 } else {
4563 if (!emitElemOperands(target, EmitElemOption::Ref)) return false;
4564 *emitted = 2;
4565 }
4566 break;
4567 }
4568
4569 case ParseNodeKind::Call:
4570 MOZ_ASSERT_UNREACHABLE(
4571 "Parser::reportIfNotValidSimpleAssignmentTarget "
4572 "rejects function calls as assignment "
4573 "targets in destructuring assignments");
4574 break;
4575
4576 default:
4577 MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
4578 }
4579
4580 MOZ_ASSERT(stackDepth == depth + int(*emitted));
4581
4582 return true;
4583 }
4584
emitSetOrInitializeDestructuring(ParseNode * target,DestructuringFlavor flav)4585 bool BytecodeEmitter::emitSetOrInitializeDestructuring(
4586 ParseNode* target, DestructuringFlavor flav) {
4587 // Now emit the lvalue opcode sequence. If the lvalue is a nested
4588 // destructuring initialiser-form, call ourselves to handle it, then pop
4589 // the matched value. Otherwise emit an lvalue bytecode sequence followed
4590 // by an assignment op.
4591 if (target->isKind(ParseNodeKind::Spread))
4592 target = target->pn_kid;
4593 else if (target->isKind(ParseNodeKind::Assign))
4594 target = target->pn_left;
4595 if (target->isKind(ParseNodeKind::Array) ||
4596 target->isKind(ParseNodeKind::Object)) {
4597 if (!emitDestructuringOps(target, flav)) return false;
4598 // Per its post-condition, emitDestructuringOps has left the
4599 // to-be-destructured value on top of the stack.
4600 if (!emit1(JSOP_POP)) return false;
4601 } else {
4602 switch (target->getKind()) {
4603 case ParseNodeKind::Name: {
4604 auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&,
4605 bool emittedBindOp) {
4606 if (emittedBindOp) {
4607 // This is like ordinary assignment, but with one
4608 // difference.
4609 //
4610 // In `a = b`, we first determine a binding for `a` (using
4611 // JSOP_BINDNAME or JSOP_BINDGNAME), then we evaluate `b`,
4612 // then a JSOP_SETNAME instruction.
4613 //
4614 // In `[a] = [b]`, per spec, `b` is evaluated first, then
4615 // we determine a binding for `a`. Then we need to do
4616 // assignment-- but the operands are on the stack in the
4617 // wrong order for JSOP_SETPROP, so we have to add a
4618 // JSOP_SWAP.
4619 //
4620 // In the cases where we are emitting a name op, emit a
4621 // swap because of this.
4622 return bce->emit1(JSOP_SWAP);
4623 }
4624
4625 // In cases of emitting a frame slot or environment slot,
4626 // nothing needs be done.
4627 return true;
4628 };
4629
4630 RootedAtom name(cx, target->name());
4631 switch (flav) {
4632 case DestructuringDeclaration:
4633 if (!emitInitializeName(name, emitSwapScopeAndRhs)) return false;
4634 break;
4635
4636 case DestructuringFormalParameterInVarScope: {
4637 // If there's an parameter expression var scope, the
4638 // destructuring declaration needs to initialize the name in
4639 // the function scope. The innermost scope is the var scope,
4640 // and its enclosing scope is the function scope.
4641 EmitterScope* funScope =
4642 innermostEmitterScope()->enclosingInFrame();
4643 NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
4644 if (!emitSetOrInitializeNameAtLocation(name, paramLoc,
4645 emitSwapScopeAndRhs, true))
4646 return false;
4647 break;
4648 }
4649
4650 case DestructuringAssignment:
4651 if (!emitSetName(name, emitSwapScopeAndRhs)) return false;
4652 break;
4653 }
4654
4655 break;
4656 }
4657
4658 case ParseNodeKind::Dot: {
4659 // The reference is already pushed by emitDestructuringLHSRef.
4660 JSOp setOp;
4661 if (target->as<PropertyAccess>().isSuper())
4662 setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
4663 else
4664 setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
4665 if (!emitAtomOp(target, setOp)) return false;
4666 break;
4667 }
4668
4669 case ParseNodeKind::Elem: {
4670 // The reference is already pushed by emitDestructuringLHSRef.
4671 if (target->as<PropertyByValue>().isSuper()) {
4672 JSOp setOp =
4673 sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
4674 // emitDestructuringLHSRef already did emitSuperElemOperands
4675 // part of emitSuperElemOp. Perform remaining part here.
4676 if (!emitElemOpBase(setOp)) return false;
4677 } else {
4678 JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
4679 if (!emitElemOpBase(setOp)) return false;
4680 }
4681 break;
4682 }
4683
4684 case ParseNodeKind::Call:
4685 MOZ_ASSERT_UNREACHABLE(
4686 "Parser::reportIfNotValidSimpleAssignmentTarget "
4687 "rejects function calls as assignment "
4688 "targets in destructuring assignments");
4689 break;
4690
4691 default:
4692 MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind");
4693 }
4694
4695 // Pop the assigned value.
4696 if (!emit1(JSOP_POP)) return false;
4697 }
4698
4699 return true;
4700 }
4701
emitIteratorNext(ParseNode * pn,IteratorKind iterKind,bool allowSelfHosted)4702 bool BytecodeEmitter::emitIteratorNext(
4703 ParseNode* pn, IteratorKind iterKind /* = IteratorKind::Sync */,
4704 bool allowSelfHosted /* = false */) {
4705 MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
4706 ".next() iteration is prohibited in self-hosted code because it "
4707 "can run user-modifiable iteration code");
4708
4709 // [stack] ... NEXT ITER
4710 MOZ_ASSERT(this->stackDepth >= 2);
4711
4712 if (!emitCall(JSOP_CALL, 0, pn)) // ... RESULT
4713 return false;
4714
4715 if (iterKind == IteratorKind::Async) {
4716 if (!emitAwaitInInnermostScope()) // ... RESULT
4717 return false;
4718 }
4719
4720 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
4721 return false;
4722 checkTypeSet(JSOP_CALL);
4723 return true;
4724 }
4725
emitPushNotUndefinedOrNull()4726 bool BytecodeEmitter::emitPushNotUndefinedOrNull() {
4727 // [stack] V
4728 MOZ_ASSERT(this->stackDepth > 0);
4729
4730 if (!emit1(JSOP_DUP)) // V V
4731 return false;
4732 if (!emit1(JSOP_UNDEFINED)) // V V UNDEFINED
4733 return false;
4734 if (!emit1(JSOP_STRICTNE)) // V ?NEQL
4735 return false;
4736
4737 JumpList undefinedOrNullJump;
4738 if (!emitJump(JSOP_AND, &undefinedOrNullJump)) // V ?NEQL
4739 return false;
4740
4741 if (!emit1(JSOP_POP)) // V
4742 return false;
4743 if (!emit1(JSOP_DUP)) // V V
4744 return false;
4745 if (!emit1(JSOP_NULL)) // V V NULL
4746 return false;
4747 if (!emit1(JSOP_STRICTNE)) // V ?NEQL
4748 return false;
4749
4750 if (!emitJumpTargetAndPatch(undefinedOrNullJump)) // V NOT-UNDEF-OR-NULL
4751 return false;
4752
4753 return true;
4754 }
4755
emitIteratorCloseInScope(EmitterScope & currentScope,IteratorKind iterKind,CompletionKind completionKind,bool allowSelfHosted)4756 bool BytecodeEmitter::emitIteratorCloseInScope(
4757 EmitterScope& currentScope,
4758 IteratorKind iterKind /* = IteratorKind::Sync */,
4759 CompletionKind completionKind /* = CompletionKind::Normal */,
4760 bool allowSelfHosted /* = false */) {
4761 MOZ_ASSERT(
4762 allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
4763 ".close() on iterators is prohibited in self-hosted code because it "
4764 "can run user-modifiable iteration code");
4765
4766 // Generate inline logic corresponding to IteratorClose (ES 7.4.6).
4767 //
4768 // Callers need to ensure that the iterator object is at the top of the
4769 // stack.
4770
4771 if (!emit1(JSOP_DUP)) // ... ITER ITER
4772 return false;
4773
4774 // Step 3.
4775 //
4776 // Get the "return" method.
4777 if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) // ... ITER RET
4778 return false;
4779
4780 // Step 4.
4781 //
4782 // Do nothing if "return" is undefined or null.
4783 IfThenElseEmitter ifReturnMethodIsDefined(this);
4784 if (!emitPushNotUndefinedOrNull()) // ... ITER RET NOT-UNDEF-OR-NULL
4785 return false;
4786
4787 if (!ifReturnMethodIsDefined.emitIfElse()) // ... ITER RET
4788 return false;
4789
4790 if (completionKind == CompletionKind::Throw) {
4791 // 7.4.6 IteratorClose ( iterator, completion )
4792 // ...
4793 // 3. Let return be ? GetMethod(iterator, "return").
4794 // 4. If return is undefined, return Completion(completion).
4795 // 5. Let innerResult be Call(return, iterator, « »).
4796 // 6. If completion.[[Type]] is throw, return Completion(completion).
4797 // 7. If innerResult.[[Type]] is throw, return
4798 // Completion(innerResult).
4799 //
4800 // For CompletionKind::Normal case, JSOP_CALL for step 5 checks if RET
4801 // is callable, and throws if not. Since step 6 doesn't match and
4802 // error handling in step 3 and step 7 can be merged.
4803 //
4804 // For CompletionKind::Throw case, an error thrown by JSOP_CALL for
4805 // step 5 is ignored by try-catch. So we should check if RET is
4806 // callable here, outside of try-catch, and the throw immediately if
4807 // not.
4808 CheckIsCallableKind kind = CheckIsCallableKind::IteratorReturn;
4809 if (!emitCheckIsCallable(kind)) // ... ITER RET
4810 return false;
4811 }
4812
4813 // Steps 5, 8.
4814 //
4815 // Call "return" if it is not undefined or null, and check that it returns
4816 // an Object.
4817 if (!emit1(JSOP_SWAP)) // ... RET ITER
4818 return false;
4819
4820 Maybe<TryEmitter> tryCatch;
4821
4822 if (completionKind == CompletionKind::Throw) {
4823 tryCatch.emplace(this, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
4824 TryEmitter::DontUseControl);
4825
4826 // Mutate stack to balance stack for try-catch.
4827 if (!emit1(JSOP_UNDEFINED)) // ... RET ITER UNDEF
4828 return false;
4829 if (!tryCatch->emitTry()) // ... RET ITER UNDEF
4830 return false;
4831 if (!emitDupAt(2)) // ... RET ITER UNDEF RET
4832 return false;
4833 if (!emitDupAt(2)) // ... RET ITER UNDEF RET ITER
4834 return false;
4835 }
4836
4837 if (!emitCall(JSOP_CALL, 0)) // ... ... RESULT
4838 return false;
4839 checkTypeSet(JSOP_CALL);
4840
4841 if (iterKind == IteratorKind::Async) {
4842 if (completionKind != CompletionKind::Throw) {
4843 // Await clobbers rval, so save the current rval.
4844 if (!emit1(JSOP_GETRVAL)) // ... ... RESULT RVAL
4845 return false;
4846 if (!emit1(JSOP_SWAP)) // ... ... RVAL RESULT
4847 return false;
4848 }
4849 if (!emitAwaitInScope(currentScope)) // ... ... RVAL? RESULT
4850 return false;
4851 }
4852
4853 if (completionKind == CompletionKind::Throw) {
4854 if (!emit1(JSOP_SWAP)) // ... RET ITER RESULT UNDEF
4855 return false;
4856 if (!emit1(JSOP_POP)) // ... RET ITER RESULT
4857 return false;
4858
4859 if (!tryCatch->emitCatch()) // ... RET ITER RESULT
4860 return false;
4861
4862 // Just ignore the exception thrown by call and await.
4863 if (!emit1(JSOP_EXCEPTION)) // ... RET ITER RESULT EXC
4864 return false;
4865 if (!emit1(JSOP_POP)) // ... RET ITER RESULT
4866 return false;
4867
4868 if (!tryCatch->emitEnd()) // ... RET ITER RESULT
4869 return false;
4870
4871 // Restore stack.
4872 if (!emit2(JSOP_UNPICK, 2)) // ... RESULT RET ITER
4873 return false;
4874 if (!emitPopN(2)) // ... RESULT
4875 return false;
4876 } else {
4877 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ... RVAL? RESULT
4878 return false;
4879
4880 if (iterKind == IteratorKind::Async) {
4881 if (!emit1(JSOP_SWAP)) // ... RESULT RVAL
4882 return false;
4883 if (!emit1(JSOP_SETRVAL)) // ... RESULT
4884 return false;
4885 }
4886 }
4887
4888 if (!ifReturnMethodIsDefined.emitElse()) // ... ITER RET
4889 return false;
4890
4891 if (!emit1(JSOP_POP)) // ... ITER
4892 return false;
4893
4894 if (!ifReturnMethodIsDefined.emitEnd()) return false;
4895
4896 return emit1(JSOP_POP);
4897 // [stack] ...
4898 }
4899
4900 template <typename InnerEmitter>
wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth,InnerEmitter emitter)4901 bool BytecodeEmitter::wrapWithDestructuringIteratorCloseTryNote(
4902 int32_t iterDepth, InnerEmitter emitter) {
4903 MOZ_ASSERT(this->stackDepth >= iterDepth);
4904
4905 // Pad a nop at the beginning of the bytecode covered by the trynote so
4906 // that when unwinding environments, we may unwind to the scope
4907 // corresponding to the pc *before* the start, in case the first bytecode
4908 // emitted by |emitter| is the start of an inner scope. See comment above
4909 // UnwindEnvironmentToTryPc.
4910 if (!emit1(JSOP_TRY_DESTRUCTURING_ITERCLOSE)) return false;
4911
4912 ptrdiff_t start = offset();
4913 if (!emitter(this)) return false;
4914 ptrdiff_t end = offset();
4915 if (start != end)
4916 return tryNoteList.append(JSTRY_DESTRUCTURING_ITERCLOSE, iterDepth, start,
4917 end);
4918 return true;
4919 }
4920
emitDefault(ParseNode * defaultExpr,ParseNode * pattern)4921 bool BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern) {
4922 if (!emit1(JSOP_DUP)) // VALUE VALUE
4923 return false;
4924 if (!emit1(JSOP_UNDEFINED)) // VALUE VALUE UNDEFINED
4925 return false;
4926 if (!emit1(JSOP_STRICTEQ)) // VALUE EQL?
4927 return false;
4928 // Emit source note to enable ion compilation.
4929 if (!newSrcNote(SRC_IF)) return false;
4930 JumpList jump;
4931 if (!emitJump(JSOP_IFEQ, &jump)) // VALUE
4932 return false;
4933 if (!emit1(JSOP_POP)) // .
4934 return false;
4935 if (!emitInitializerInBranch(defaultExpr, pattern)) // DEFAULTVALUE
4936 return false;
4937 if (!emitJumpTargetAndPatch(jump)) return false;
4938 return true;
4939 }
4940
setOrEmitSetFunName(ParseNode * maybeFun,HandleAtom name,FunctionPrefixKind prefixKind)4941 bool BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name,
4942 FunctionPrefixKind prefixKind) {
4943 if (maybeFun->isKind(ParseNodeKind::Function)) {
4944 // Function doesn't have 'name' property at this point.
4945 // Set function's name at compile time.
4946 JSFunction* fun = maybeFun->pn_funbox->function();
4947
4948 // Single node can be emitted multiple times if it appears in
4949 // array destructuring default. If function already has a name,
4950 // just return.
4951 if (fun->hasCompileTimeName()) {
4952 #ifdef DEBUG
4953 RootedFunction rootedFun(cx, fun);
4954 JSAtom* funName = NameToFunctionName(cx, name, prefixKind);
4955 if (!funName) return false;
4956 MOZ_ASSERT(funName == rootedFun->compileTimeName());
4957 #endif
4958 return true;
4959 }
4960
4961 fun->setCompileTimeName(name);
4962 return true;
4963 }
4964
4965 uint32_t nameIndex;
4966 if (!makeAtomIndex(name, &nameIndex)) return false;
4967 if (!emitIndexOp(JSOP_STRING, nameIndex)) // FUN NAME
4968 return false;
4969 uint8_t kind = uint8_t(prefixKind);
4970 if (!emit2(JSOP_SETFUNNAME, kind)) // FUN
4971 return false;
4972 return true;
4973 }
4974
emitInitializer(ParseNode * initializer,ParseNode * pattern)4975 bool BytecodeEmitter::emitInitializer(ParseNode* initializer,
4976 ParseNode* pattern) {
4977 if (!emitTree(initializer)) return false;
4978
4979 if (!pattern->isInParens() && pattern->isKind(ParseNodeKind::Name) &&
4980 initializer->isDirectRHSAnonFunction()) {
4981 RootedAtom name(cx, pattern->name());
4982 if (!setOrEmitSetFunName(initializer, name, FunctionPrefixKind::None))
4983 return false;
4984 }
4985
4986 return true;
4987 }
4988
emitInitializerInBranch(ParseNode * initializer,ParseNode * pattern)4989 bool BytecodeEmitter::emitInitializerInBranch(ParseNode* initializer,
4990 ParseNode* pattern) {
4991 TDZCheckCache tdzCache(this);
4992 return emitInitializer(initializer, pattern);
4993 }
4994
emitDestructuringOpsArray(ParseNode * pattern,DestructuringFlavor flav)4995 bool BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern,
4996 DestructuringFlavor flav) {
4997 MOZ_ASSERT(pattern->isKind(ParseNodeKind::Array));
4998 MOZ_ASSERT(pattern->isArity(PN_LIST));
4999 MOZ_ASSERT(this->stackDepth != 0);
5000
5001 // Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
5002 //
5003 // Lines that are annotated "covered by trynote" mean that upon throwing
5004 // an exception, IteratorClose is called on iter only if done is false.
5005 //
5006 // let x, y;
5007 // let a, b, c, d;
5008 // let iter, next, lref, result, done, value; // stack values
5009 //
5010 // iter = x[Symbol.iterator]();
5011 // next = iter.next;
5012 //
5013 // // ==== emitted by loop for a ====
5014 // lref = GetReference(a); // covered by trynote
5015 //
5016 // result = Call(next, iter);
5017 // done = result.done;
5018 //
5019 // if (done)
5020 // value = undefined;
5021 // else
5022 // value = result.value;
5023 //
5024 // SetOrInitialize(lref, value); // covered by trynote
5025 //
5026 // // ==== emitted by loop for b ====
5027 // lref = GetReference(b); // covered by trynote
5028 //
5029 // if (done) {
5030 // value = undefined;
5031 // } else {
5032 // result = Call(next, iter);
5033 // done = result.done;
5034 // if (done)
5035 // value = undefined;
5036 // else
5037 // value = result.value;
5038 // }
5039 //
5040 // SetOrInitialize(lref, value); // covered by trynote
5041 //
5042 // // ==== emitted by loop for elision ====
5043 // if (done) {
5044 // value = undefined;
5045 // } else {
5046 // result = Call(next, iter);
5047 // done = result.done;
5048 // if (done)
5049 // value = undefined;
5050 // else
5051 // value = result.value;
5052 // }
5053 //
5054 // // ==== emitted by loop for c ====
5055 // lref = GetReference(c); // covered by trynote
5056 //
5057 // if (done) {
5058 // value = undefined;
5059 // } else {
5060 // result = Call(next, iter);
5061 // done = result.done;
5062 // if (done)
5063 // value = undefined;
5064 // else
5065 // value = result.value;
5066 // }
5067 //
5068 // if (value === undefined)
5069 // value = y; // covered by trynote
5070 //
5071 // SetOrInitialize(lref, value); // covered by trynote
5072 //
5073 // // ==== emitted by loop for d ====
5074 // lref = GetReference(d); // covered by trynote
5075 //
5076 // if (done)
5077 // value = [];
5078 // else
5079 // value = [...iter];
5080 //
5081 // SetOrInitialize(lref, value); // covered by trynote
5082 //
5083 // // === emitted after loop ===
5084 // if (!done)
5085 // IteratorClose(iter);
5086
5087 // Use an iterator to destructure the RHS, instead of index lookup. We
5088 // must leave the *original* value on the stack.
5089 if (!emit1(JSOP_DUP)) // ... OBJ OBJ
5090 return false;
5091 if (!emitIterator()) // ... OBJ NEXT ITER
5092 return false;
5093
5094 // For an empty pattern [], call IteratorClose unconditionally. Nothing
5095 // else needs to be done.
5096 if (!pattern->pn_head) {
5097 if (!emit1(JSOP_SWAP)) // ... OBJ ITER NEXT
5098 return false;
5099 if (!emit1(JSOP_POP)) // ... OBJ ITER
5100 return false;
5101
5102 return emitIteratorCloseInInnermostScope();
5103 // [stack] ... OBJ
5104 }
5105
5106 // Push an initial FALSE value for DONE.
5107 if (!emit1(JSOP_FALSE)) // ... OBJ NEXT ITER FALSE
5108 return false;
5109
5110 // JSTRY_DESTRUCTURING_ITERCLOSE expects the iterator and the done value
5111 // to be the second to top and the top of the stack, respectively.
5112 // IteratorClose is called upon exception only if done is false.
5113 int32_t tryNoteDepth = stackDepth;
5114
5115 for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
5116 bool isFirst = member == pattern->pn_head;
5117 DebugOnly<bool> hasNext = !!member->pn_next;
5118
5119 size_t emitted = 0;
5120
5121 // Spec requires LHS reference to be evaluated first.
5122 ParseNode* lhsPattern = member;
5123 if (lhsPattern->isKind(ParseNodeKind::Assign))
5124 lhsPattern = lhsPattern->pn_left;
5125
5126 bool isElision = lhsPattern->isKind(ParseNodeKind::Elision);
5127 if (!isElision) {
5128 auto emitLHSRef = [lhsPattern, &emitted](BytecodeEmitter* bce) {
5129 return bce->emitDestructuringLHSRef(lhsPattern, &emitted);
5130 // [stack] ... OBJ NEXT ITER DONE LREF*
5131 };
5132 if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitLHSRef))
5133 return false;
5134 }
5135
5136 // Pick the DONE value to the top of the stack.
5137 if (emitted) {
5138 if (!emit2(JSOP_PICK, emitted)) // ... OBJ NEXT ITER *LREF DONE
5139 return false;
5140 }
5141
5142 if (isFirst) {
5143 // If this element is the first, DONE is always FALSE, so pop it.
5144 //
5145 // Non-first elements should emit if-else depending on the
5146 // member pattern, below.
5147 if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER *LREF
5148 return false;
5149 }
5150
5151 if (member->isKind(ParseNodeKind::Spread)) {
5152 IfThenElseEmitter ifThenElse(this);
5153 if (!isFirst) {
5154 // If spread is not the first element of the pattern,
5155 // iterator can already be completed.
5156 // ... OBJ NEXT ITER *LREF DONE
5157 if (!ifThenElse.emitIfElse()) // ... OBJ NEXT ITER *LREF
5158 return false;
5159
5160 if (!emitUint32Operand(JSOP_NEWARRAY,
5161 0)) // ... OBJ NEXT ITER *LREF ARRAY
5162 return false;
5163 if (!ifThenElse.emitElse()) // ... OBJ NEXT ITER *LREF
5164 return false;
5165 }
5166
5167 // If iterator is not completed, create a new array with the rest
5168 // of the iterator.
5169 if (!emitDupAt(emitted + 1)) // ... OBJ NEXT ITER *LREF NEXT
5170 return false;
5171 if (!emitDupAt(emitted + 1)) // ... OBJ NEXT ITER *LREF NEXT ITER
5172 return false;
5173 if (!emitUint32Operand(JSOP_NEWARRAY,
5174 0)) // ... OBJ NEXT ITER *LREF NEXT ITER ARRAY
5175 return false;
5176 if (!emitNumberOp(0)) // ... OBJ NEXT ITER *LREF NEXT ITER ARRAY INDEX
5177 return false;
5178 if (!emitSpread()) // ... OBJ NEXT ITER *LREF ARRAY INDEX
5179 return false;
5180 if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER *LREF ARRAY
5181 return false;
5182
5183 if (!isFirst) {
5184 if (!ifThenElse.emitEnd()) return false;
5185 MOZ_ASSERT(ifThenElse.pushed() == 1);
5186 }
5187
5188 // At this point the iterator is done. Unpick a TRUE value for DONE above
5189 // ITER.
5190 if (!emit1(JSOP_TRUE)) // ... OBJ NEXT ITER *LREF ARRAY TRUE
5191 return false;
5192 if (!emit2(JSOP_UNPICK,
5193 emitted + 1)) // ... OBJ NEXT ITER TRUE *LREF ARRAY
5194 return false;
5195
5196 auto emitAssignment = [member, flav](BytecodeEmitter* bce) {
5197 return bce->emitSetOrInitializeDestructuring(member, flav);
5198 // [stack] ... OBJ NEXT ITER TRUE
5199 };
5200 if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth,
5201 emitAssignment))
5202 return false;
5203
5204 MOZ_ASSERT(!hasNext);
5205 break;
5206 }
5207
5208 ParseNode* pndefault = nullptr;
5209 if (member->isKind(ParseNodeKind::Assign)) pndefault = member->pn_right;
5210
5211 MOZ_ASSERT(!member->isKind(ParseNodeKind::Spread));
5212
5213 IfThenElseEmitter ifAlreadyDone(this);
5214 if (!isFirst) {
5215 // ... OBJ NEXT ITER *LREF DONE
5216 if (!ifAlreadyDone.emitIfElse()) // ... OBJ NEXT ITER *LREF
5217 return false;
5218
5219 if (!emit1(JSOP_UNDEFINED)) // ... OBJ NEXT ITER *LREF UNDEF
5220 return false;
5221 if (!emit1(JSOP_NOP_DESTRUCTURING)) // ... OBJ NEXT ITER *LREF UNDEF
5222 return false;
5223
5224 // The iterator is done. Unpick a TRUE value for DONE above ITER.
5225 if (!emit1(JSOP_TRUE)) // ... OBJ NEXT ITER *LREF UNDEF TRUE
5226 return false;
5227 if (!emit2(JSOP_UNPICK,
5228 emitted + 1)) // ... OBJ NEXT ITER TRUE *LREF UNDEF
5229 return false;
5230
5231 if (!ifAlreadyDone.emitElse()) // ... OBJ NEXT ITER *LREF
5232 return false;
5233 }
5234
5235 if (!emitDupAt(emitted + 1)) // ... OBJ NEXT ITER *LREF NEXT
5236 return false;
5237 if (!emitDupAt(emitted + 1)) // ... OBJ NEXT ITER *LREF NEXT ITER
5238 return false;
5239 if (!emitIteratorNext(pattern)) // ... OBJ NEXT ITER *LREF RESULT
5240 return false;
5241 if (!emit1(JSOP_DUP)) // ... OBJ NEXT ITER *LREF RESULT RESULT
5242 return false;
5243 if (!emitAtomOp(cx->names().done,
5244 JSOP_GETPROP)) // ... OBJ NEXT ITER *LREF RESULT DONE
5245 return false;
5246
5247 if (!emit1(JSOP_DUP)) // ... OBJ NEXT ITER *LREF RESULT DONE DONE
5248 return false;
5249 if (!emit2(JSOP_UNPICK,
5250 emitted + 2)) // ... OBJ NEXT ITER DONE *LREF RESULT DONE
5251 return false;
5252
5253 IfThenElseEmitter ifDone(this);
5254 if (!ifDone.emitIfElse()) // ... OBJ NEXT ITER DONE *LREF RESULT
5255 return false;
5256
5257 if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER DONE *LREF
5258 return false;
5259 if (!emit1(JSOP_UNDEFINED)) // ... OBJ NEXT ITER DONE *LREF UNDEF
5260 return false;
5261 if (!emit1(JSOP_NOP_DESTRUCTURING)) // ... OBJ NEXT ITER DONE *LREF UNDEF
5262 return false;
5263
5264 if (!ifDone.emitElse()) // ... OBJ NEXT ITER DONE *LREF RESULT
5265 return false;
5266
5267 if (!emitAtomOp(cx->names().value,
5268 JSOP_GETPROP)) // ... OBJ NEXT ITER DONE *LREF VALUE
5269 return false;
5270
5271 if (!ifDone.emitEnd()) return false;
5272 MOZ_ASSERT(ifDone.pushed() == 0);
5273
5274 if (!isFirst) {
5275 if (!ifAlreadyDone.emitEnd()) return false;
5276 MOZ_ASSERT(ifAlreadyDone.pushed() == 2);
5277 }
5278
5279 if (pndefault) {
5280 auto emitDefault = [pndefault, lhsPattern](BytecodeEmitter* bce) {
5281 return bce->emitDefault(pndefault, lhsPattern);
5282 // [stack] ... OBJ NEXT ITER DONE LREF* VALUE
5283 };
5284
5285 if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitDefault))
5286 return false;
5287 }
5288
5289 if (!isElision) {
5290 auto emitAssignment = [lhsPattern, flav](BytecodeEmitter* bce) {
5291 return bce->emitSetOrInitializeDestructuring(lhsPattern, flav);
5292 // [stack] ... OBJ NEXT ITER DONE
5293 };
5294
5295 if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth,
5296 emitAssignment))
5297 return false;
5298 } else {
5299 if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER DONE
5300 return false;
5301 }
5302 }
5303
5304 // The last DONE value is on top of the stack. If not DONE, call
5305 // IteratorClose.
5306 // ... OBJ NEXT ITER DONE
5307 IfThenElseEmitter ifDone(this);
5308 if (!ifDone.emitIfElse()) // ... OBJ NEXT ITER
5309 return false;
5310 if (!emitPopN(2)) // ... OBJ
5311 return false;
5312 if (!ifDone.emitElse()) // ... OBJ NEXT ITER
5313 return false;
5314 if (!emit1(JSOP_SWAP)) // ... OBJ ITER NEXT
5315 return false;
5316 if (!emit1(JSOP_POP)) // ... OBJ ITER
5317 return false;
5318 if (!emitIteratorCloseInInnermostScope()) // ... OBJ
5319 return false;
5320 if (!ifDone.emitEnd()) return false;
5321
5322 return true;
5323 }
5324
emitComputedPropertyName(ParseNode * computedPropName)5325 bool BytecodeEmitter::emitComputedPropertyName(ParseNode* computedPropName) {
5326 MOZ_ASSERT(computedPropName->isKind(ParseNodeKind::ComputedName));
5327 return emitTree(computedPropName->pn_kid) && emit1(JSOP_TOID);
5328 }
5329
emitDestructuringOpsObject(ParseNode * pattern,DestructuringFlavor flav)5330 bool BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern,
5331 DestructuringFlavor flav) {
5332 MOZ_ASSERT(pattern->isKind(ParseNodeKind::Object));
5333 MOZ_ASSERT(pattern->isArity(PN_LIST));
5334
5335 // [stack] ... RHS
5336 MOZ_ASSERT(this->stackDepth > 0);
5337
5338 if (!emit1(JSOP_CHECKOBJCOERCIBLE)) // ... RHS
5339 return false;
5340
5341 bool needsRestPropertyExcludedSet =
5342 pattern->pn_count > 1 && pattern->last()->isKind(ParseNodeKind::Spread);
5343 if (needsRestPropertyExcludedSet) {
5344 if (!emitDestructuringObjRestExclusionSet(pattern)) // ... RHS SET
5345 return false;
5346
5347 if (!emit1(JSOP_SWAP)) // ... SET RHS
5348 return false;
5349 }
5350
5351 for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
5352 ParseNode* subpattern;
5353 if (member->isKind(ParseNodeKind::MutateProto) ||
5354 member->isKind(ParseNodeKind::Spread)) {
5355 subpattern = member->pn_kid;
5356 } else {
5357 subpattern = member->pn_right;
5358 }
5359
5360 ParseNode* lhs = subpattern;
5361 MOZ_ASSERT_IF(member->isKind(ParseNodeKind::Spread),
5362 !lhs->isKind(ParseNodeKind::Assign));
5363 if (lhs->isKind(ParseNodeKind::Assign)) lhs = lhs->pn_left;
5364
5365 size_t emitted;
5366 if (!emitDestructuringLHSRef(lhs, &emitted)) // ... *SET RHS *LREF
5367 return false;
5368
5369 // Duplicate the value being destructured to use as a reference base.
5370 if (!emitDupAt(emitted)) // ... *SET RHS *LREF RHS
5371 return false;
5372
5373 if (member->isKind(ParseNodeKind::Spread)) {
5374 if (!updateSourceCoordNotes(member->pn_pos.begin)) return false;
5375
5376 if (!emitNewInit(JSProto_Object)) // ... *SET RHS *LREF RHS TARGET
5377 return false;
5378 if (!emit1(JSOP_DUP)) // ... *SET RHS *LREF RHS TARGET TARGET
5379 return false;
5380 if (!emit2(JSOP_PICK, 2)) // ... *SET RHS *LREF TARGET TARGET RHS
5381 return false;
5382
5383 if (needsRestPropertyExcludedSet) {
5384 if (!emit2(JSOP_PICK,
5385 emitted + 4)) // ... RHS *LREF TARGET TARGET RHS SET
5386 return false;
5387 }
5388
5389 CopyOption option = needsRestPropertyExcludedSet ? CopyOption::Filtered
5390 : CopyOption::Unfiltered;
5391 if (!emitCopyDataProperties(option)) // ... RHS *LREF TARGET
5392 return false;
5393
5394 // Destructure TARGET per this member's lhs.
5395 if (!emitSetOrInitializeDestructuring(lhs, flav)) // ... RHS
5396 return false;
5397
5398 MOZ_ASSERT(member == pattern->last(), "Rest property is always last");
5399 break;
5400 }
5401
5402 // Now push the property name currently being matched, which is the
5403 // current property name "label" on the left of a colon in the object
5404 // initialiser.
5405 bool needsGetElem = true;
5406
5407 if (member->isKind(ParseNodeKind::MutateProto)) {
5408 if (!emitAtomOp(cx->names().proto,
5409 JSOP_GETPROP)) // ... *SET RHS *LREF PROP
5410 return false;
5411 needsGetElem = false;
5412 } else {
5413 MOZ_ASSERT(member->isKind(ParseNodeKind::Colon) ||
5414 member->isKind(ParseNodeKind::Shorthand));
5415
5416 ParseNode* key = member->pn_left;
5417 if (key->isKind(ParseNodeKind::Number)) {
5418 if (!emitNumberOp(key->pn_dval)) // ... *SET RHS *LREF RHS KEY
5419 return false;
5420 } else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
5421 key->isKind(ParseNodeKind::String)) {
5422 if (!emitAtomOp(key->pn_atom, JSOP_GETPROP)) // ... *SET RHS *LREF PROP
5423 return false;
5424 needsGetElem = false;
5425 } else {
5426 if (!emitComputedPropertyName(key)) // ... *SET RHS *LREF RHS KEY
5427 return false;
5428
5429 // Add the computed property key to the exclusion set.
5430 if (needsRestPropertyExcludedSet) {
5431 if (!emitDupAt(emitted + 3)) // ... SET RHS *LREF RHS KEY SET
5432 return false;
5433 if (!emitDupAt(1)) // ... SET RHS *LREF RHS KEY SET KEY
5434 return false;
5435 if (!emit1(JSOP_UNDEFINED)) // ... SET RHS *LREF RHS KEY SET KEY
5436 // UNDEFINED
5437 return false;
5438 if (!emit1(JSOP_INITELEM)) // ... SET RHS *LREF RHS KEY SET
5439 return false;
5440 if (!emit1(JSOP_POP)) // ... SET RHS *LREF RHS KEY
5441 return false;
5442 }
5443 }
5444 }
5445
5446 // Get the property value if not done already.
5447 if (needsGetElem &&
5448 !emitElemOpBase(JSOP_GETELEM)) // ... *SET RHS *LREF PROP
5449 return false;
5450
5451 if (subpattern->isKind(ParseNodeKind::Assign)) {
5452 if (!emitDefault(subpattern->pn_right, lhs)) // ... *SET RHS *LREF VALUE
5453 return false;
5454 }
5455
5456 // Destructure PROP per this member's lhs.
5457 if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... *SET RHS
5458 return false;
5459 }
5460
5461 return true;
5462 }
5463
emitDestructuringObjRestExclusionSet(ParseNode * pattern)5464 bool BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern) {
5465 MOZ_ASSERT(pattern->isKind(ParseNodeKind::Object));
5466 MOZ_ASSERT(pattern->isArity(PN_LIST));
5467 MOZ_ASSERT(pattern->last()->isKind(ParseNodeKind::Spread));
5468
5469 ptrdiff_t offset = this->offset();
5470 if (!emitNewInit(JSProto_Object)) return false;
5471
5472 // Try to construct the shape of the object as we go, so we can emit a
5473 // JSOP_NEWOBJECT with the final shape instead.
5474 // In the case of computed property names and indices, we cannot fix the
5475 // shape at bytecode compile time. When the shape cannot be determined,
5476 // |obj| is nulled out.
5477
5478 // No need to do any guessing for the object kind, since we know the upper
5479 // bound of how many properties we plan to have.
5480 gc::AllocKind kind = gc::GetGCObjectKind(pattern->pn_count - 1);
5481 RootedPlainObject obj(
5482 cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
5483 if (!obj) return false;
5484
5485 RootedAtom pnatom(cx);
5486 for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
5487 if (member->isKind(ParseNodeKind::Spread)) break;
5488
5489 bool isIndex = false;
5490 if (member->isKind(ParseNodeKind::MutateProto)) {
5491 pnatom.set(cx->names().proto);
5492 } else {
5493 ParseNode* key = member->pn_left;
5494 if (key->isKind(ParseNodeKind::Number)) {
5495 if (!emitNumberOp(key->pn_dval)) return false;
5496 isIndex = true;
5497 } else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
5498 key->isKind(ParseNodeKind::String)) {
5499 pnatom.set(key->pn_atom);
5500 } else {
5501 // Otherwise this is a computed property name which needs to
5502 // be added dynamically.
5503 obj.set(nullptr);
5504 continue;
5505 }
5506 }
5507
5508 // Initialize elements with |undefined|.
5509 if (!emit1(JSOP_UNDEFINED)) return false;
5510
5511 if (isIndex) {
5512 obj.set(nullptr);
5513 if (!emit1(JSOP_INITELEM)) return false;
5514 } else {
5515 uint32_t index;
5516 if (!makeAtomIndex(pnatom, &index)) return false;
5517
5518 if (obj) {
5519 MOZ_ASSERT(!obj->inDictionaryMode());
5520 Rooted<jsid> id(cx, AtomToId(pnatom));
5521 if (!NativeDefineDataProperty(cx, obj, id, UndefinedHandleValue,
5522 JSPROP_ENUMERATE))
5523 return false;
5524 if (obj->inDictionaryMode()) obj.set(nullptr);
5525 }
5526
5527 if (!emitIndex32(JSOP_INITPROP, index)) return false;
5528 }
5529 }
5530
5531 if (obj) {
5532 // The object survived and has a predictable shape: update the
5533 // original bytecode.
5534 if (!replaceNewInitWithNewObject(obj, offset)) return false;
5535 }
5536
5537 return true;
5538 }
5539
emitDestructuringOps(ParseNode * pattern,DestructuringFlavor flav)5540 bool BytecodeEmitter::emitDestructuringOps(ParseNode* pattern,
5541 DestructuringFlavor flav) {
5542 if (pattern->isKind(ParseNodeKind::Array))
5543 return emitDestructuringOpsArray(pattern, flav);
5544 return emitDestructuringOpsObject(pattern, flav);
5545 }
5546
emitTemplateString(ParseNode * pn)5547 bool BytecodeEmitter::emitTemplateString(ParseNode* pn) {
5548 MOZ_ASSERT(pn->isArity(PN_LIST));
5549
5550 bool pushedString = false;
5551
5552 for (ParseNode* pn2 = pn->pn_head; pn2 != NULL; pn2 = pn2->pn_next) {
5553 bool isString = (pn2->getKind() == ParseNodeKind::String ||
5554 pn2->getKind() == ParseNodeKind::TemplateString);
5555
5556 // Skip empty strings. These are very common: a template string like
5557 // `${a}${b}` has three empty strings and without this optimization
5558 // we'd emit four JSOP_ADD operations instead of just one.
5559 if (isString && pn2->pn_atom->empty()) continue;
5560
5561 if (!isString) {
5562 // We update source notes before emitting the expression
5563 if (!updateSourceCoordNotes(pn2->pn_pos.begin)) return false;
5564 }
5565
5566 if (!emitTree(pn2)) return false;
5567
5568 if (!isString) {
5569 // We need to convert the expression to a string
5570 if (!emit1(JSOP_TOSTRING)) return false;
5571 }
5572
5573 if (pushedString) {
5574 // We've pushed two strings onto the stack. Add them together, leaving
5575 // just one.
5576 if (!emit1(JSOP_ADD)) return false;
5577 } else {
5578 pushedString = true;
5579 }
5580 }
5581
5582 if (!pushedString) {
5583 // All strings were empty, this can happen for something like `${""}`.
5584 // Just push an empty string.
5585 if (!emitAtomOp(cx->names().empty, JSOP_STRING)) return false;
5586 }
5587
5588 return true;
5589 }
5590
emitDeclarationList(ParseNode * declList)5591 bool BytecodeEmitter::emitDeclarationList(ParseNode* declList) {
5592 MOZ_ASSERT(declList->isArity(PN_LIST));
5593 MOZ_ASSERT(declList->isOp(JSOP_NOP));
5594
5595 ParseNode* next;
5596 for (ParseNode* decl = declList->pn_head; decl; decl = next) {
5597 if (!updateSourceCoordNotes(decl->pn_pos.begin)) return false;
5598 next = decl->pn_next;
5599
5600 if (decl->isKind(ParseNodeKind::Assign)) {
5601 MOZ_ASSERT(decl->isOp(JSOP_NOP));
5602
5603 ParseNode* pattern = decl->pn_left;
5604 MOZ_ASSERT(pattern->isKind(ParseNodeKind::Array) ||
5605 pattern->isKind(ParseNodeKind::Object));
5606
5607 if (!emitTree(decl->pn_right)) return false;
5608
5609 if (!emitDestructuringOps(pattern, DestructuringDeclaration))
5610 return false;
5611
5612 if (!emit1(JSOP_POP)) return false;
5613 } else {
5614 if (!emitSingleDeclaration(declList, decl, decl->expr())) return false;
5615 }
5616 }
5617 return true;
5618 }
5619
emitSingleDeclaration(ParseNode * declList,ParseNode * decl,ParseNode * initializer)5620 bool BytecodeEmitter::emitSingleDeclaration(ParseNode* declList,
5621 ParseNode* decl,
5622 ParseNode* initializer) {
5623 MOZ_ASSERT(decl->isKind(ParseNodeKind::Name));
5624
5625 // Nothing to do for initializer-less 'var' declarations, as there's no TDZ.
5626 if (!initializer && declList->isKind(ParseNodeKind::Var)) return true;
5627
5628 auto emitRhs = [initializer, declList, decl](BytecodeEmitter* bce,
5629 const NameLocation&, bool) {
5630 if (!initializer) {
5631 // Lexical declarations are initialized to undefined without an
5632 // initializer.
5633 MOZ_ASSERT(declList->isKind(ParseNodeKind::Let),
5634 "var declarations without initializers handled above, "
5635 "and const declarations must have initializers");
5636 Unused
5637 << declList; // silence clang -Wunused-lambda-capture in opt builds
5638 return bce->emit1(JSOP_UNDEFINED);
5639 }
5640
5641 MOZ_ASSERT(initializer);
5642 return bce->emitInitializer(initializer, decl);
5643 };
5644
5645 if (!emitInitializeName(decl, emitRhs)) return false;
5646
5647 // Pop the RHS.
5648 return emit1(JSOP_POP);
5649 }
5650
EmitAssignmentRhs(BytecodeEmitter * bce,ParseNode * rhs,uint8_t offset)5651 static bool EmitAssignmentRhs(BytecodeEmitter* bce, ParseNode* rhs,
5652 uint8_t offset) {
5653 // If there is a RHS tree, emit the tree.
5654 if (rhs) return bce->emitTree(rhs);
5655
5656 // Otherwise the RHS value to assign is already on the stack, i.e., the
5657 // next enumeration value in a for-in or for-of loop. Depending on how
5658 // many other values have been pushed on the stack, we need to get the
5659 // already-pushed RHS value.
5660 if (offset != 1 && !bce->emit2(JSOP_PICK, offset - 1)) return false;
5661
5662 return true;
5663 }
5664
CompoundAssignmentParseNodeKindToJSOp(ParseNodeKind pnk)5665 static inline JSOp CompoundAssignmentParseNodeKindToJSOp(ParseNodeKind pnk) {
5666 switch (pnk) {
5667 case ParseNodeKind::Assign:
5668 return JSOP_NOP;
5669 case ParseNodeKind::AddAssign:
5670 return JSOP_ADD;
5671 case ParseNodeKind::SubAssign:
5672 return JSOP_SUB;
5673 case ParseNodeKind::BitOrAssign:
5674 return JSOP_BITOR;
5675 case ParseNodeKind::BitXorAssign:
5676 return JSOP_BITXOR;
5677 case ParseNodeKind::BitAndAssign:
5678 return JSOP_BITAND;
5679 case ParseNodeKind::LshAssign:
5680 return JSOP_LSH;
5681 case ParseNodeKind::RshAssign:
5682 return JSOP_RSH;
5683 case ParseNodeKind::UrshAssign:
5684 return JSOP_URSH;
5685 case ParseNodeKind::MulAssign:
5686 return JSOP_MUL;
5687 case ParseNodeKind::DivAssign:
5688 return JSOP_DIV;
5689 case ParseNodeKind::ModAssign:
5690 return JSOP_MOD;
5691 case ParseNodeKind::PowAssign:
5692 return JSOP_POW;
5693 default:
5694 MOZ_CRASH("unexpected compound assignment op");
5695 }
5696 }
5697
emitAssignment(ParseNode * lhs,ParseNodeKind pnk,ParseNode * rhs)5698 bool BytecodeEmitter::emitAssignment(ParseNode* lhs, ParseNodeKind pnk,
5699 ParseNode* rhs) {
5700 JSOp op = CompoundAssignmentParseNodeKindToJSOp(pnk);
5701
5702 // Name assignments are handled separately because choosing ops and when
5703 // to emit BINDNAME is involved and should avoid duplication.
5704 if (lhs->isKind(ParseNodeKind::Name)) {
5705 auto emitRhs = [op, lhs, rhs](BytecodeEmitter* bce,
5706 const NameLocation& lhsLoc,
5707 bool emittedBindOp) {
5708 // For compound assignments, first get the LHS value, then emit
5709 // the RHS and the op.
5710 if (op != JSOP_NOP) {
5711 if (!bce->emitGetNameAtLocationForCompoundAssignment(lhs->name(),
5712 lhsLoc))
5713 return false;
5714 }
5715
5716 // Emit the RHS. If we emitted a BIND[G]NAME, then the scope is on
5717 // the top of the stack and we need to pick the right RHS value.
5718 if (!EmitAssignmentRhs(bce, rhs, emittedBindOp ? 2 : 1)) return false;
5719
5720 if (!lhs->isInParens() && op == JSOP_NOP && rhs &&
5721 rhs->isDirectRHSAnonFunction()) {
5722 RootedAtom name(bce->cx, lhs->name());
5723 if (!bce->setOrEmitSetFunName(rhs, name, FunctionPrefixKind::None))
5724 return false;
5725 }
5726
5727 // Emit the compound assignment op if there is one.
5728 if (op != JSOP_NOP) {
5729 if (!bce->emit1(op)) return false;
5730 }
5731
5732 return true;
5733 };
5734
5735 return emitSetName(lhs, emitRhs);
5736 }
5737
5738 // Deal with non-name assignments.
5739 uint32_t atomIndex = (uint32_t)-1;
5740 uint8_t offset = 1;
5741
5742 switch (lhs->getKind()) {
5743 case ParseNodeKind::Dot:
5744 if (lhs->as<PropertyAccess>().isSuper()) {
5745 if (!emitSuperPropLHS(&lhs->as<PropertyAccess>().expression()))
5746 return false;
5747 offset += 2;
5748 } else {
5749 if (!emitTree(lhs->expr())) return false;
5750 offset += 1;
5751 }
5752 if (!makeAtomIndex(lhs->pn_atom, &atomIndex)) return false;
5753 break;
5754 case ParseNodeKind::Elem: {
5755 MOZ_ASSERT(lhs->isArity(PN_BINARY));
5756 EmitElemOption opt =
5757 op == JSOP_NOP ? EmitElemOption::Get : EmitElemOption::CompoundAssign;
5758 if (lhs->as<PropertyByValue>().isSuper()) {
5759 if (!emitSuperElemOperands(lhs, opt)) return false;
5760 offset += 3;
5761 } else {
5762 if (!emitElemOperands(lhs, opt)) return false;
5763 offset += 2;
5764 }
5765 break;
5766 }
5767 case ParseNodeKind::Array:
5768 case ParseNodeKind::Object:
5769 break;
5770 case ParseNodeKind::Call:
5771 if (!emitTree(lhs)) return false;
5772
5773 // Assignment to function calls is forbidden, but we have to make the
5774 // call first. Now we can throw.
5775 if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS))
5776 return false;
5777
5778 // Rebalance the stack to placate stack-depth assertions.
5779 if (!emit1(JSOP_POP)) return false;
5780 break;
5781 default:
5782 MOZ_ASSERT(0);
5783 }
5784
5785 if (op != JSOP_NOP) {
5786 MOZ_ASSERT(rhs);
5787 switch (lhs->getKind()) {
5788 case ParseNodeKind::Dot: {
5789 JSOp getOp;
5790 if (lhs->as<PropertyAccess>().isSuper()) {
5791 if (!emit1(JSOP_DUP2)) return false;
5792 getOp = JSOP_GETPROP_SUPER;
5793 } else {
5794 if (!emit1(JSOP_DUP)) return false;
5795 bool isLength = (lhs->pn_atom == cx->names().length);
5796 getOp = isLength ? JSOP_LENGTH : JSOP_GETPROP;
5797 }
5798 if (!emitIndex32(getOp, atomIndex)) return false;
5799 break;
5800 }
5801 case ParseNodeKind::Elem: {
5802 JSOp elemOp;
5803 if (lhs->as<PropertyByValue>().isSuper()) {
5804 if (!emitDupAt(2)) return false;
5805 if (!emitDupAt(2)) return false;
5806 if (!emitDupAt(2)) return false;
5807 elemOp = JSOP_GETELEM_SUPER;
5808 } else {
5809 if (!emit1(JSOP_DUP2)) return false;
5810 elemOp = JSOP_GETELEM;
5811 }
5812 if (!emitElemOpBase(elemOp)) return false;
5813 break;
5814 }
5815 case ParseNodeKind::Call:
5816 // We just emitted a JSOP_THROWMSG and popped the call's return
5817 // value. Push a random value to make sure the stack depth is
5818 // correct.
5819 if (!emit1(JSOP_NULL)) return false;
5820 break;
5821 default:;
5822 }
5823 }
5824
5825 if (!EmitAssignmentRhs(this, rhs, offset)) return false;
5826
5827 /* If += etc., emit the binary operator with a source note. */
5828 if (op != JSOP_NOP) {
5829 if (!newSrcNote(SRC_ASSIGNOP)) return false;
5830 if (!emit1(op)) return false;
5831 }
5832
5833 /* Finally, emit the specialized assignment bytecode. */
5834 switch (lhs->getKind()) {
5835 case ParseNodeKind::Dot: {
5836 JSOp setOp =
5837 lhs->as<PropertyAccess>().isSuper()
5838 ? (sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER)
5839 : (sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP);
5840 if (!emitIndexOp(setOp, atomIndex)) return false;
5841 break;
5842 }
5843 case ParseNodeKind::Call:
5844 // We threw above, so nothing to do here.
5845 break;
5846 case ParseNodeKind::Elem: {
5847 JSOp setOp =
5848 lhs->as<PropertyByValue>().isSuper()
5849 ? sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER
5850 : sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
5851 if (!emit1(setOp)) return false;
5852 break;
5853 }
5854 case ParseNodeKind::Array:
5855 case ParseNodeKind::Object:
5856 if (!emitDestructuringOps(lhs, DestructuringAssignment)) return false;
5857 break;
5858 default:
5859 MOZ_ASSERT(0);
5860 }
5861 return true;
5862 }
5863
getConstantValue(JSContext * cx,AllowConstantObjects allowObjects,MutableHandleValue vp,Value * compare,size_t ncompare,NewObjectKind newKind)5864 bool ParseNode::getConstantValue(JSContext* cx,
5865 AllowConstantObjects allowObjects,
5866 MutableHandleValue vp, Value* compare,
5867 size_t ncompare, NewObjectKind newKind) {
5868 MOZ_ASSERT(newKind == TenuredObject || newKind == SingletonObject);
5869
5870 switch (getKind()) {
5871 case ParseNodeKind::Number:
5872 vp.setNumber(pn_dval);
5873 return true;
5874 case ParseNodeKind::TemplateString:
5875 case ParseNodeKind::String:
5876 vp.setString(pn_atom);
5877 return true;
5878 case ParseNodeKind::True:
5879 vp.setBoolean(true);
5880 return true;
5881 case ParseNodeKind::False:
5882 vp.setBoolean(false);
5883 return true;
5884 case ParseNodeKind::Null:
5885 vp.setNull();
5886 return true;
5887 case ParseNodeKind::RawUndefined:
5888 vp.setUndefined();
5889 return true;
5890 case ParseNodeKind::CallSiteObj:
5891 case ParseNodeKind::Array: {
5892 unsigned count;
5893 ParseNode* pn;
5894
5895 if (allowObjects == DontAllowObjects) {
5896 vp.setMagic(JS_GENERIC_MAGIC);
5897 return true;
5898 }
5899
5900 ObjectGroup::NewArrayKind arrayKind = ObjectGroup::NewArrayKind::Normal;
5901 if (allowObjects == ForCopyOnWriteArray) {
5902 arrayKind = ObjectGroup::NewArrayKind::CopyOnWrite;
5903 allowObjects = DontAllowObjects;
5904 }
5905
5906 if (getKind() == ParseNodeKind::CallSiteObj) {
5907 count = pn_count - 1;
5908 pn = pn_head->pn_next;
5909 } else {
5910 MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
5911 count = pn_count;
5912 pn = pn_head;
5913 }
5914
5915 AutoValueVector values(cx);
5916 if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), count)) return false;
5917 size_t idx;
5918 for (idx = 0; pn; idx++, pn = pn->pn_next) {
5919 if (!pn->getConstantValue(cx, allowObjects, values[idx], values.begin(),
5920 idx))
5921 return false;
5922 if (values[idx].isMagic(JS_GENERIC_MAGIC)) {
5923 vp.setMagic(JS_GENERIC_MAGIC);
5924 return true;
5925 }
5926 }
5927 MOZ_ASSERT(idx == count);
5928
5929 ArrayObject* obj = ObjectGroup::newArrayObject(
5930 cx, values.begin(), values.length(), newKind, arrayKind);
5931 if (!obj) return false;
5932
5933 if (!CombineArrayElementTypes(cx, obj, compare, ncompare)) return false;
5934
5935 vp.setObject(*obj);
5936 return true;
5937 }
5938 case ParseNodeKind::Object: {
5939 MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
5940
5941 if (allowObjects == DontAllowObjects) {
5942 vp.setMagic(JS_GENERIC_MAGIC);
5943 return true;
5944 }
5945 MOZ_ASSERT(allowObjects == AllowObjects);
5946
5947 Rooted<IdValueVector> properties(cx, IdValueVector(cx));
5948
5949 RootedValue value(cx), idvalue(cx);
5950 for (ParseNode* pn = pn_head; pn; pn = pn->pn_next) {
5951 if (!pn->pn_right->getConstantValue(cx, allowObjects, &value))
5952 return false;
5953 if (value.isMagic(JS_GENERIC_MAGIC)) {
5954 vp.setMagic(JS_GENERIC_MAGIC);
5955 return true;
5956 }
5957
5958 ParseNode* pnid = pn->pn_left;
5959 if (pnid->isKind(ParseNodeKind::Number)) {
5960 idvalue = NumberValue(pnid->pn_dval);
5961 } else {
5962 MOZ_ASSERT(pnid->isKind(ParseNodeKind::ObjectPropertyName) ||
5963 pnid->isKind(ParseNodeKind::String));
5964 MOZ_ASSERT(pnid->pn_atom != cx->names().proto);
5965 idvalue = StringValue(pnid->pn_atom);
5966 }
5967
5968 RootedId id(cx);
5969 if (!ValueToId<CanGC>(cx, idvalue, &id)) return false;
5970
5971 if (!properties.append(IdValuePair(id, value))) return false;
5972 }
5973
5974 JSObject* obj = ObjectGroup::newPlainObject(cx, properties.begin(),
5975 properties.length(), newKind);
5976 if (!obj) return false;
5977
5978 if (!CombinePlainObjectPropertyTypes(cx, obj, compare, ncompare))
5979 return false;
5980
5981 vp.setObject(*obj);
5982 return true;
5983 }
5984 default:
5985 MOZ_CRASH("Unexpected node");
5986 }
5987 return false;
5988 }
5989
emitSingletonInitialiser(ParseNode * pn)5990 bool BytecodeEmitter::emitSingletonInitialiser(ParseNode* pn) {
5991 NewObjectKind newKind = (pn->getKind() == ParseNodeKind::Object)
5992 ? SingletonObject
5993 : TenuredObject;
5994
5995 RootedValue value(cx);
5996 if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value, nullptr, 0,
5997 newKind))
5998 return false;
5999
6000 MOZ_ASSERT_IF(newKind == SingletonObject, value.toObject().isSingleton());
6001
6002 ObjectBox* objbox = parser.newObjectBox(&value.toObject());
6003 if (!objbox) return false;
6004
6005 return emitObjectOp(objbox, JSOP_OBJECT);
6006 }
6007
emitCallSiteObject(ParseNode * pn)6008 bool BytecodeEmitter::emitCallSiteObject(ParseNode* pn) {
6009 RootedValue value(cx);
6010 if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value)) return false;
6011
6012 MOZ_ASSERT(value.isObject());
6013
6014 ObjectBox* objbox1 = parser.newObjectBox(&value.toObject());
6015 if (!objbox1) return false;
6016
6017 if (!pn->as<CallSiteNode>().getRawArrayValue(cx, &value)) return false;
6018
6019 MOZ_ASSERT(value.isObject());
6020
6021 ObjectBox* objbox2 = parser.newObjectBox(&value.toObject());
6022 if (!objbox2) return false;
6023
6024 return emitObjectPairOp(objbox1, objbox2, JSOP_CALLSITEOBJ);
6025 }
6026
6027 /* See the SRC_FOR source note offsetBias comments later in this file. */
6028 JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
6029 JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
6030
6031 namespace {
6032
6033 class EmitLevelManager {
6034 BytecodeEmitter* bce;
6035
6036 public:
EmitLevelManager(BytecodeEmitter * bce)6037 explicit EmitLevelManager(BytecodeEmitter* bce) : bce(bce) {
6038 bce->emitLevel++;
6039 }
~EmitLevelManager()6040 ~EmitLevelManager() { bce->emitLevel--; }
6041 };
6042
6043 } /* anonymous namespace */
6044
emitCatch(ParseNode * pn)6045 bool BytecodeEmitter::emitCatch(ParseNode* pn) {
6046 // We must be nested under a try-finally statement.
6047 MOZ_ASSERT(innermostNestableControl->is<TryFinallyControl>());
6048
6049 /* Pick up the pending exception and bind it to the catch variable. */
6050 if (!emit1(JSOP_EXCEPTION)) return false;
6051
6052 ParseNode* pn2 = pn->pn_left;
6053 if (!pn2) {
6054 // Catch parameter was omitted; just discard the exception.
6055 if (!emit1(JSOP_POP)) return false;
6056 } else {
6057 switch (pn2->getKind()) {
6058 case ParseNodeKind::Array:
6059 case ParseNodeKind::Object:
6060 if (!emitDestructuringOps(pn2, DestructuringDeclaration)) return false;
6061 if (!emit1(JSOP_POP)) return false;
6062 break;
6063
6064 case ParseNodeKind::Name:
6065 if (!emitLexicalInitialization(pn2)) return false;
6066 if (!emit1(JSOP_POP)) return false;
6067 break;
6068
6069 default:
6070 MOZ_ASSERT(0);
6071 }
6072 }
6073
6074 /* Emit the catch body. */
6075 return emitTree(pn->pn_right);
6076 }
6077
6078 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the
6079 // comment on EmitSwitch.
emitTry(ParseNode * pn)6080 MOZ_NEVER_INLINE bool BytecodeEmitter::emitTry(ParseNode* pn) {
6081 ParseNode* catchScope = pn->pn_kid2;
6082 ParseNode* finallyNode = pn->pn_kid3;
6083
6084 TryEmitter::Kind kind;
6085 if (catchScope) {
6086 if (finallyNode)
6087 kind = TryEmitter::TryCatchFinally;
6088 else
6089 kind = TryEmitter::TryCatch;
6090 } else {
6091 MOZ_ASSERT(finallyNode);
6092 kind = TryEmitter::TryFinally;
6093 }
6094 TryEmitter tryCatch(this, kind);
6095
6096 if (!tryCatch.emitTry()) return false;
6097
6098 if (!emitTree(pn->pn_kid1)) return false;
6099
6100 // If this try has a catch block, emit it.
6101 if (catchScope) {
6102 // The emitted code for a catch block looks like:
6103 //
6104 // [pushlexicalenv] only if any local aliased
6105 // exception
6106 // setlocal 0; pop assign or possibly destructure exception
6107 // < catch block contents >
6108 // debugleaveblock
6109 // [poplexicalenv] only if any local aliased
6110 // if there is a finally block:
6111 // gosub <finally>
6112 // goto <after finally>
6113 if (!tryCatch.emitCatch()) return false;
6114
6115 // Emit the lexical scope and catch body.
6116 MOZ_ASSERT(catchScope->isKind(ParseNodeKind::LexicalScope));
6117 if (!emitTree(catchScope)) return false;
6118 }
6119
6120 // Emit the finally handler, if there is one.
6121 if (finallyNode) {
6122 if (!tryCatch.emitFinally(Some(finallyNode->pn_pos.begin))) return false;
6123
6124 if (!emitTree(finallyNode)) return false;
6125 }
6126
6127 if (!tryCatch.emitEnd()) return false;
6128
6129 return true;
6130 }
6131
emitIf(ParseNode * pn)6132 bool BytecodeEmitter::emitIf(ParseNode* pn) {
6133 IfThenElseEmitter ifThenElse(this);
6134
6135 if_again:
6136 /* Emit code for the condition before pushing stmtInfo. */
6137 if (!emitTreeInBranch(pn->pn_kid1)) return false;
6138
6139 ParseNode* elseNode = pn->pn_kid3;
6140 if (elseNode) {
6141 if (!ifThenElse.emitIfElse()) return false;
6142 } else {
6143 if (!ifThenElse.emitIf()) return false;
6144 }
6145
6146 /* Emit code for the then part. */
6147 if (!emitTreeInBranch(pn->pn_kid2)) return false;
6148
6149 if (elseNode) {
6150 if (!ifThenElse.emitElse()) return false;
6151
6152 if (elseNode->isKind(ParseNodeKind::If)) {
6153 pn = elseNode;
6154 goto if_again;
6155 }
6156
6157 /* Emit code for the else part. */
6158 if (!emitTreeInBranch(elseNode)) return false;
6159 }
6160
6161 if (!ifThenElse.emitEnd()) return false;
6162
6163 return true;
6164 }
6165
emitHoistedFunctionsInList(ParseNode * list)6166 bool BytecodeEmitter::emitHoistedFunctionsInList(ParseNode* list) {
6167 MOZ_ASSERT(list->pn_xflags & PNX_FUNCDEFS);
6168
6169 for (ParseNode* pn = list->pn_head; pn; pn = pn->pn_next) {
6170 ParseNode* maybeFun = pn;
6171
6172 if (!sc->strict()) {
6173 while (maybeFun->isKind(ParseNodeKind::Label))
6174 maybeFun = maybeFun->as<LabeledStatement>().statement();
6175 }
6176
6177 if (maybeFun->isKind(ParseNodeKind::Function) &&
6178 maybeFun->functionIsHoisted()) {
6179 if (!emitTree(maybeFun)) return false;
6180 }
6181 }
6182
6183 return true;
6184 }
6185
emitLexicalScopeBody(ParseNode * body,EmitLineNumberNote emitLineNote)6186 bool BytecodeEmitter::emitLexicalScopeBody(ParseNode* body,
6187 EmitLineNumberNote emitLineNote) {
6188 if (body->isKind(ParseNodeKind::StatementList) &&
6189 body->pn_xflags & PNX_FUNCDEFS) {
6190 // This block contains function statements whose definitions are
6191 // hoisted to the top of the block. Emit these as a separate pass
6192 // before the rest of the block.
6193 if (!emitHoistedFunctionsInList(body)) return false;
6194 }
6195
6196 // Line notes were updated by emitLexicalScope.
6197 return emitTree(body, ValueUsage::WantValue, emitLineNote);
6198 }
6199
6200 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
6201 // the comment on emitSwitch.
emitLexicalScope(ParseNode * pn)6202 MOZ_NEVER_INLINE bool BytecodeEmitter::emitLexicalScope(ParseNode* pn) {
6203 MOZ_ASSERT(pn->isKind(ParseNodeKind::LexicalScope));
6204
6205 TDZCheckCache tdzCache(this);
6206
6207 ParseNode* body = pn->scopeBody();
6208 if (pn->isEmptyScope()) return emitLexicalScopeBody(body);
6209
6210 // We are about to emit some bytecode for what the spec calls "declaration
6211 // instantiation". Assign these instructions to the opening `{` of the
6212 // block. (Using the location of each declaration we're instantiating is
6213 // too weird when stepping in the debugger.)
6214 if (!ParseNodeRequiresSpecialLineNumberNotes(body)) {
6215 if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false;
6216 }
6217
6218 EmitterScope emitterScope(this);
6219 ScopeKind kind;
6220 if (body->isKind(ParseNodeKind::Catch)) {
6221 kind = (!body->pn_left || body->pn_left->isKind(ParseNodeKind::Name))
6222 ? ScopeKind::SimpleCatch
6223 : ScopeKind::Catch;
6224 } else {
6225 kind = ScopeKind::Lexical;
6226 }
6227
6228 if (!emitterScope.enterLexical(this, kind, pn->scopeBindings())) return false;
6229
6230 if (body->isKind(ParseNodeKind::For)) {
6231 // for loops need to emit {FRESHEN,RECREATE}LEXICALENV if there are
6232 // lexical declarations in the head. Signal this by passing a
6233 // non-nullptr lexical scope.
6234 if (!emitFor(body, &emitterScope)) return false;
6235 } else {
6236 if (!emitLexicalScopeBody(body, SUPPRESS_LINENOTE)) return false;
6237 }
6238
6239 return emitterScope.leave(this);
6240 }
6241
emitWith(ParseNode * pn)6242 bool BytecodeEmitter::emitWith(ParseNode* pn) {
6243 if (!emitTree(pn->pn_left)) return false;
6244
6245 EmitterScope emitterScope(this);
6246 if (!emitterScope.enterWith(this)) return false;
6247
6248 if (!emitTree(pn->pn_right)) return false;
6249
6250 return emitterScope.leave(this);
6251 }
6252
emitCopyDataProperties(CopyOption option)6253 bool BytecodeEmitter::emitCopyDataProperties(CopyOption option) {
6254 DebugOnly<int32_t> depth = this->stackDepth;
6255
6256 uint32_t argc;
6257 if (option == CopyOption::Filtered) {
6258 MOZ_ASSERT(depth > 2);
6259 // [stack] TARGET SOURCE SET
6260 argc = 3;
6261
6262 if (!emitAtomOp(cx->names().CopyDataProperties, JSOP_GETINTRINSIC)) {
6263 // [stack] TARGET SOURCE SET COPYDATAPROPERTIES
6264 return false;
6265 }
6266 } else {
6267 MOZ_ASSERT(depth > 1);
6268 // [stack] TARGET SOURCE
6269 argc = 2;
6270
6271 if (!emitAtomOp(cx->names().CopyDataPropertiesUnfiltered,
6272 JSOP_GETINTRINSIC)) {
6273 // [stack] TARGET SOURCE COPYDATAPROPERTIES
6274 return false;
6275 }
6276 }
6277
6278 if (!emit1(
6279 JSOP_UNDEFINED)) // TARGET SOURCE *SET COPYDATAPROPERTIES UNDEFINED
6280 return false;
6281 if (!emit2(JSOP_PICK,
6282 argc + 1)) // SOURCE *SET COPYDATAPROPERTIES UNDEFINED TARGET
6283 return false;
6284 if (!emit2(JSOP_PICK,
6285 argc + 1)) // *SET COPYDATAPROPERTIES UNDEFINED TARGET SOURCE
6286 return false;
6287 if (option == CopyOption::Filtered) {
6288 if (!emit2(JSOP_PICK,
6289 argc + 1)) // COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
6290 return false;
6291 }
6292 if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) // IGNORED
6293 return false;
6294 checkTypeSet(JSOP_CALL_IGNORES_RV);
6295
6296 if (!emit1(JSOP_POP)) // -
6297 return false;
6298
6299 MOZ_ASSERT(depth - int(argc) == this->stackDepth);
6300 return true;
6301 }
6302
emitIterator()6303 bool BytecodeEmitter::emitIterator() {
6304 // Convert iterable to iterator.
6305 if (!emit1(JSOP_DUP)) // OBJ OBJ
6306 return false;
6307 if (!emit2(JSOP_SYMBOL,
6308 uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
6309 return false;
6310 if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
6311 return false;
6312 if (!emit1(JSOP_SWAP)) // ITERFN OBJ
6313 return false;
6314 if (!emitCall(JSOP_CALLITER, 0)) // ITER
6315 return false;
6316 checkTypeSet(JSOP_CALLITER);
6317 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
6318 return false;
6319 if (!emit1(JSOP_DUP)) // ITER ITER
6320 return false;
6321 if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) // ITER NEXT
6322 return false;
6323 if (!emit1(JSOP_SWAP)) // NEXT ITER
6324 return false;
6325 return true;
6326 }
6327
emitAsyncIterator()6328 bool BytecodeEmitter::emitAsyncIterator() {
6329 // Convert iterable to iterator.
6330 if (!emit1(JSOP_DUP)) // OBJ OBJ
6331 return false;
6332 if (!emit2(
6333 JSOP_SYMBOL,
6334 uint8_t(JS::SymbolCode::asyncIterator))) // OBJ OBJ @@ASYNCITERATOR
6335 return false;
6336 if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
6337 return false;
6338
6339 IfThenElseEmitter ifAsyncIterIsUndefined(this);
6340 if (!emitPushNotUndefinedOrNull()) // OBJ ITERFN !UNDEF-OR-NULL
6341 return false;
6342 if (!emit1(JSOP_NOT)) // OBJ ITERFN UNDEF-OR-NULL
6343 return false;
6344 if (!ifAsyncIterIsUndefined.emitIfElse()) // OBJ ITERFN
6345 return false;
6346
6347 if (!emit1(JSOP_POP)) // OBJ
6348 return false;
6349 if (!emit1(JSOP_DUP)) // OBJ OBJ
6350 return false;
6351 if (!emit2(JSOP_SYMBOL,
6352 uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
6353 return false;
6354 if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
6355 return false;
6356 if (!emit1(JSOP_SWAP)) // ITERFN OBJ
6357 return false;
6358 if (!emitCall(JSOP_CALLITER, 0)) // ITER
6359 return false;
6360 checkTypeSet(JSOP_CALLITER);
6361 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
6362 return false;
6363
6364 if (!emit1(JSOP_DUP)) // ITER ITER
6365 return false;
6366 if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) // ITER SYNCNEXT
6367 return false;
6368
6369 if (!emit1(JSOP_TOASYNCITER)) // ITER
6370 return false;
6371
6372 if (!ifAsyncIterIsUndefined.emitElse()) // OBJ ITERFN
6373 return false;
6374
6375 if (!emit1(JSOP_SWAP)) // ITERFN OBJ
6376 return false;
6377 if (!emitCall(JSOP_CALLITER, 0)) // ITER
6378 return false;
6379 checkTypeSet(JSOP_CALLITER);
6380 if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
6381 return false;
6382
6383 if (!ifAsyncIterIsUndefined.emitEnd()) // ITER
6384 return false;
6385
6386 if (!emit1(JSOP_DUP)) // ITER ITER
6387 return false;
6388 if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) // ITER NEXT
6389 return false;
6390 if (!emit1(JSOP_SWAP)) // NEXT ITER
6391 return false;
6392
6393 return true;
6394 }
6395
emitSpread(bool allowSelfHosted)6396 bool BytecodeEmitter::emitSpread(bool allowSelfHosted) {
6397 LoopControl loopInfo(this, StatementKind::Spread);
6398
6399 // Jump down to the loop condition to minimize overhead assuming at least
6400 // one iteration, as the other loop forms do. Annotate so IonMonkey can
6401 // find the loop-closing jump.
6402 unsigned noteIndex;
6403 if (!newSrcNote(SRC_FOR_OF, ¬eIndex)) return false;
6404
6405 // Jump down to the loop condition to minimize overhead, assuming at least
6406 // one iteration. (This is also what we do for loops; whether this
6407 // assumption holds for spreads is an unanswered question.)
6408 JumpList initialJump;
6409 if (!emitJump(JSOP_GOTO, &initialJump)) // NEXT ITER ARR I (during the goto)
6410 return false;
6411
6412 JumpTarget top{-1};
6413 if (!emitLoopHead(nullptr, &top)) // NEXT ITER ARR I
6414 return false;
6415
6416 // When we enter the goto above, we have NEXT ITER ARR I on the stack. But
6417 // when we reach this point on the loop backedge (if spreading produces at
6418 // least one value), we've additionally pushed a RESULT iteration value.
6419 // Increment manually to reflect this.
6420 this->stackDepth++;
6421
6422 JumpList beq;
6423 JumpTarget breakTarget{-1};
6424 {
6425 #ifdef DEBUG
6426 auto loopDepth = this->stackDepth;
6427 #endif
6428
6429 // Emit code to assign result.value to the iteration variable.
6430 if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER ARR I VALUE
6431 return false;
6432 if (!emit1(JSOP_INITELEM_INC)) // NEXT ITER ARR (I+1)
6433 return false;
6434
6435 MOZ_ASSERT(this->stackDepth == loopDepth - 1);
6436
6437 // Spread operations can't contain |continue|, so don't bother setting loop
6438 // and enclosing "update" offsets, as we do with for-loops.
6439
6440 // COME FROM the beginning of the loop to here.
6441 if (!emitLoopEntry(nullptr, initialJump)) // NEXT ITER ARR I
6442 return false;
6443
6444 if (!emitDupAt(3)) // NEXT ITER ARR I NEXT
6445 return false;
6446 if (!emitDupAt(3)) // NEXT ITER ARR I NEXT ITER
6447 return false;
6448 if (!emitIteratorNext(nullptr, IteratorKind::Sync,
6449 allowSelfHosted)) // ITER ARR I RESULT
6450 return false;
6451 if (!emit1(JSOP_DUP)) // NEXT ITER ARR I RESULT RESULT
6452 return false;
6453 if (!emitAtomOp(cx->names().done,
6454 JSOP_GETPROP)) // NEXT ITER ARR I RESULT DONE
6455 return false;
6456
6457 if (!emitBackwardJump(JSOP_IFEQ, top, &beq,
6458 &breakTarget)) // NEXT ITER ARR I RESULT
6459 return false;
6460
6461 MOZ_ASSERT(this->stackDepth == loopDepth);
6462 }
6463
6464 // Let Ion know where the closing jump of this loop is.
6465 if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
6466 return false;
6467
6468 // No breaks or continues should occur in spreads.
6469 MOZ_ASSERT(loopInfo.breaks.offset == -1);
6470 MOZ_ASSERT(loopInfo.continues.offset == -1);
6471
6472 if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset,
6473 breakTarget.offset))
6474 return false;
6475
6476 if (!emit2(JSOP_PICK, 4)) // ITER ARR FINAL_INDEX RESULT NEXT
6477 return false;
6478 if (!emit2(JSOP_PICK, 4)) // ARR FINAL_INDEX RESULT NEXT ITER
6479 return false;
6480
6481 return emitPopN(3);
6482 // [stack] ARR FINAL_INDEX
6483 }
6484
emitInitializeForInOrOfTarget(ParseNode * forHead)6485 bool BytecodeEmitter::emitInitializeForInOrOfTarget(ParseNode* forHead) {
6486 MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
6487 forHead->isKind(ParseNodeKind::ForOf));
6488 MOZ_ASSERT(forHead->isArity(PN_TERNARY));
6489
6490 MOZ_ASSERT(this->stackDepth >= 1,
6491 "must have a per-iteration value for initializing");
6492
6493 ParseNode* target = forHead->pn_kid1;
6494 MOZ_ASSERT(!forHead->pn_kid2);
6495
6496 // If the for-in/of loop didn't have a variable declaration, per-loop
6497 // initialization is just assigning the iteration value to a target
6498 // expression.
6499 if (!parser.isDeclarationList(target))
6500 return emitAssignment(target, ParseNodeKind::Assign,
6501 nullptr); // ... ITERVAL
6502
6503 // Otherwise, per-loop initialization is (possibly) declaration
6504 // initialization. If the declaration is a lexical declaration, it must be
6505 // initialized. If the declaration is a variable declaration, an
6506 // assignment to that name (which does *not* necessarily assign to the
6507 // variable!) must be generated.
6508
6509 if (!updateSourceCoordNotes(target->pn_pos.begin)) return false;
6510
6511 MOZ_ASSERT(target->isForLoopDeclaration());
6512 target = parser.singleBindingFromDeclaration(target);
6513
6514 if (target->isKind(ParseNodeKind::Name)) {
6515 auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&,
6516 bool emittedBindOp) {
6517 if (emittedBindOp) {
6518 // Per-iteration initialization in for-in/of loops computes the
6519 // iteration value *before* initializing. Thus the
6520 // initializing value may be buried under a bind-specific value
6521 // on the stack. Swap it to the top of the stack.
6522 MOZ_ASSERT(bce->stackDepth >= 2);
6523 return bce->emit1(JSOP_SWAP);
6524 }
6525
6526 // In cases of emitting a frame slot or environment slot,
6527 // nothing needs be done.
6528 MOZ_ASSERT(bce->stackDepth >= 1);
6529 return true;
6530 };
6531
6532 // The caller handles removing the iteration value from the stack.
6533 return emitInitializeName(target, emitSwapScopeAndRhs);
6534 }
6535
6536 MOZ_ASSERT(
6537 !target->isKind(ParseNodeKind::Assign),
6538 "for-in/of loop destructuring declarations can't have initializers");
6539
6540 MOZ_ASSERT(target->isKind(ParseNodeKind::Array) ||
6541 target->isKind(ParseNodeKind::Object));
6542 return emitDestructuringOps(target, DestructuringDeclaration);
6543 }
6544
emitForOf(ParseNode * forOfLoop,EmitterScope * headLexicalEmitterScope)6545 bool BytecodeEmitter::emitForOf(ParseNode* forOfLoop,
6546 EmitterScope* headLexicalEmitterScope) {
6547 MOZ_ASSERT(forOfLoop->isKind(ParseNodeKind::For));
6548 MOZ_ASSERT(forOfLoop->isArity(PN_BINARY));
6549
6550 ParseNode* forOfHead = forOfLoop->pn_left;
6551 MOZ_ASSERT(forOfHead->isKind(ParseNodeKind::ForOf));
6552 MOZ_ASSERT(forOfHead->isArity(PN_TERNARY));
6553
6554 unsigned iflags = forOfLoop->pn_iflags;
6555 IteratorKind iterKind =
6556 (iflags & JSITER_FORAWAITOF) ? IteratorKind::Async : IteratorKind::Sync;
6557 MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox());
6558 MOZ_ASSERT_IF(iterKind == IteratorKind::Async,
6559 sc->asFunctionBox()->isAsync());
6560
6561 ParseNode* forHeadExpr = forOfHead->pn_kid3;
6562
6563 // Certain builtins (e.g. Array.from) are implemented in self-hosting
6564 // as for-of loops.
6565 bool allowSelfHostedIter = false;
6566 if (emitterMode == BytecodeEmitter::SelfHosting &&
6567 forHeadExpr->isKind(ParseNodeKind::Call) &&
6568 forHeadExpr->pn_head->name() == cx->names().allowContentIter) {
6569 allowSelfHostedIter = true;
6570 }
6571
6572 // Evaluate the expression being iterated. The forHeadExpr should use a
6573 // distinct TDZCheckCache to evaluate since (abstractly) it runs in its own
6574 // LexicalEnvironment.
6575 if (!emitTreeInBranch(forHeadExpr)) // ITERABLE
6576 return false;
6577 if (iterKind == IteratorKind::Async) {
6578 if (!emitAsyncIterator()) // NEXT ITER
6579 return false;
6580 } else {
6581 if (!emitIterator()) // NEXT ITER
6582 return false;
6583 }
6584
6585 int32_t iterDepth = stackDepth;
6586
6587 // For-of loops have the iterator next method, the iterator itself, and
6588 // the result.value on the stack.
6589 // Push an undefined to balance the stack.
6590 if (!emit1(JSOP_UNDEFINED)) // NEXT ITER UNDEF
6591 return false;
6592
6593 ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
6594
6595 // Annotate so IonMonkey can find the loop-closing jump.
6596 unsigned noteIndex;
6597 if (!newSrcNote(SRC_FOR_OF, ¬eIndex)) return false;
6598
6599 JumpList initialJump;
6600 if (!emitJump(JSOP_GOTO, &initialJump)) // NEXT ITER UNDEF
6601 return false;
6602
6603 JumpTarget top{-1};
6604 if (!emitLoopHead(nullptr, &top)) // NEXT ITER UNDEF
6605 return false;
6606
6607 // If the loop had an escaping lexical declaration, replace the current
6608 // environment with an dead zoned one to implement TDZ semantics.
6609 if (headLexicalEmitterScope) {
6610 // The environment chain only includes an environment for the for-of
6611 // loop head *if* a scope binding is captured, thereby requiring
6612 // recreation each iteration. If a lexical scope exists for the head,
6613 // it must be the innermost one. If that scope has closed-over
6614 // bindings inducing an environment, recreate the current environment.
6615 DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
6616 MOZ_ASSERT(forOfTarget->isKind(ParseNodeKind::Let) ||
6617 forOfTarget->isKind(ParseNodeKind::Const));
6618 MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
6619 MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() ==
6620 ScopeKind::Lexical);
6621
6622 if (headLexicalEmitterScope->hasEnvironment()) {
6623 if (!emit1(JSOP_RECREATELEXICALENV)) // NEXT ITER UNDEF
6624 return false;
6625 }
6626
6627 // For uncaptured bindings, put them back in TDZ.
6628 if (!headLexicalEmitterScope->deadZoneFrameSlots(this)) return false;
6629 }
6630
6631 JumpList beq;
6632 JumpTarget breakTarget{-1};
6633 {
6634 #ifdef DEBUG
6635 auto loopDepth = this->stackDepth;
6636 #endif
6637
6638 // Make sure this code is attributed to the "for".
6639 if (!updateSourceCoordNotes(forOfHead->pn_pos.begin)) return false;
6640
6641 if (!emit1(JSOP_POP)) // NEXT ITER
6642 return false;
6643 if (!emit1(JSOP_DUP2)) // NEXT ITER NEXT ITER
6644 return false;
6645
6646 if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter))
6647 return false; // NEXT ITER RESULT
6648
6649 if (!emit1(JSOP_DUP)) // NEXT ITER RESULT RESULT
6650 return false;
6651 if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // NEXT ITER RESULT DONE
6652 return false;
6653
6654 IfThenElseEmitter ifDone(this);
6655
6656 if (!ifDone.emitIf()) // NEXT ITER RESULT
6657 return false;
6658
6659 // Remove RESULT from the stack to release it.
6660 if (!emit1(JSOP_POP)) // NEXT ITER
6661 return false;
6662 if (!emit1(JSOP_UNDEFINED)) // NEXT ITER UNDEF
6663 return false;
6664
6665 // If the iteration is done, leave loop here, instead of the branch at
6666 // the end of the loop.
6667 if (!loopInfo.emitSpecialBreakForDone(this)) // NEXT ITER UNDEF
6668 return false;
6669
6670 if (!ifDone.emitEnd()) // NEXT ITER RESULT
6671 return false;
6672
6673 // Emit code to assign result.value to the iteration variable.
6674 //
6675 // Note that ES 13.7.5.13, step 5.c says getting result.value does not
6676 // call IteratorClose, so start JSTRY_ITERCLOSE after the GETPROP.
6677 if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER VALUE
6678 return false;
6679
6680 if (!loopInfo.emitBeginCodeNeedingIteratorClose(this)) return false;
6681
6682 if (!emitInitializeForInOrOfTarget(forOfHead)) // NEXT ITER VALUE
6683 return false;
6684
6685 MOZ_ASSERT(stackDepth == loopDepth,
6686 "the stack must be balanced around the initializing "
6687 "operation");
6688
6689 // Remove VALUE from the stack to release it.
6690 if (!emit1(JSOP_POP)) // NEXT ITER
6691 return false;
6692 if (!emit1(JSOP_UNDEFINED)) // NEXT ITER UNDEF
6693 return false;
6694
6695 // Perform the loop body.
6696 ParseNode* forBody = forOfLoop->pn_right;
6697 if (!emitTree(forBody)) // NEXT ITER UNDEF
6698 return false;
6699
6700 MOZ_ASSERT(stackDepth == loopDepth,
6701 "the stack must be balanced around the for-of body");
6702
6703 if (!loopInfo.emitEndCodeNeedingIteratorClose(this)) return false;
6704
6705 // Set offset for continues.
6706 loopInfo.continueTarget = {offset()};
6707
6708 if (!emitLoopEntry(forHeadExpr, initialJump)) // NEXT ITER UNDEF
6709 return false;
6710
6711 if (!emit1(JSOP_FALSE)) // NEXT ITER UNDEF FALSE
6712 return false;
6713 if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
6714 return false; // NEXT ITER UNDEF
6715
6716 MOZ_ASSERT(this->stackDepth == loopDepth);
6717 }
6718
6719 // Let Ion know where the closing jump of this loop is.
6720 if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
6721 return false;
6722
6723 if (!loopInfo.patchBreaksAndContinues(this)) return false;
6724
6725 if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset,
6726 breakTarget.offset))
6727 return false;
6728
6729 return emitPopN(3); //
6730 }
6731
emitForIn(ParseNode * forInLoop,EmitterScope * headLexicalEmitterScope)6732 bool BytecodeEmitter::emitForIn(ParseNode* forInLoop,
6733 EmitterScope* headLexicalEmitterScope) {
6734 MOZ_ASSERT(forInLoop->isKind(ParseNodeKind::For));
6735 MOZ_ASSERT(forInLoop->isArity(PN_BINARY));
6736 MOZ_ASSERT(forInLoop->isOp(JSOP_ITER));
6737
6738 ParseNode* forInHead = forInLoop->pn_left;
6739 MOZ_ASSERT(forInHead->isKind(ParseNodeKind::ForIn));
6740 MOZ_ASSERT(forInHead->isArity(PN_TERNARY));
6741
6742 // Annex B: Evaluate the var-initializer expression if present.
6743 // |for (var i = initializer in expr) { ... }|
6744 ParseNode* forInTarget = forInHead->pn_kid1;
6745 if (parser.isDeclarationList(forInTarget)) {
6746 ParseNode* decl = parser.singleBindingFromDeclaration(forInTarget);
6747 if (decl->isKind(ParseNodeKind::Name)) {
6748 if (ParseNode* initializer = decl->expr()) {
6749 MOZ_ASSERT(
6750 forInTarget->isKind(ParseNodeKind::Var),
6751 "for-in initializers are only permitted for |var| declarations");
6752
6753 if (!updateSourceCoordNotes(decl->pn_pos.begin)) return false;
6754
6755 auto emitRhs = [decl, initializer](BytecodeEmitter* bce,
6756 const NameLocation&, bool) {
6757 return bce->emitInitializer(initializer, decl);
6758 };
6759
6760 if (!emitInitializeName(decl, emitRhs)) return false;
6761
6762 // Pop the initializer.
6763 if (!emit1(JSOP_POP)) return false;
6764 }
6765 }
6766 }
6767
6768 // Evaluate the expression being iterated.
6769 ParseNode* expr = forInHead->pn_kid3;
6770 if (!emitTreeInBranch(expr)) // EXPR
6771 return false;
6772
6773 MOZ_ASSERT(forInLoop->pn_iflags == 0);
6774
6775 if (!emit1(JSOP_ITER)) // ITER
6776 return false;
6777
6778 // For-in loops have both the iterator and the value on the stack. Push
6779 // undefined to balance the stack.
6780 if (!emit1(JSOP_UNDEFINED)) // ITER ITERVAL
6781 return false;
6782
6783 LoopControl loopInfo(this, StatementKind::ForInLoop);
6784
6785 /* Annotate so IonMonkey can find the loop-closing jump. */
6786 unsigned noteIndex;
6787 if (!newSrcNote(SRC_FOR_IN, ¬eIndex)) return false;
6788
6789 // Jump down to the loop condition to minimize overhead (assuming at least
6790 // one iteration, just like the other loop forms).
6791 JumpList initialJump;
6792 if (!emitJump(JSOP_GOTO, &initialJump)) // ITER ITERVAL
6793 return false;
6794
6795 JumpTarget top{-1};
6796 if (!emitLoopHead(nullptr, &top)) // ITER ITERVAL
6797 return false;
6798
6799 // If the loop had an escaping lexical declaration, replace the current
6800 // environment with an dead zoned one to implement TDZ semantics.
6801 if (headLexicalEmitterScope) {
6802 // The environment chain only includes an environment for the for-in
6803 // loop head *if* a scope binding is captured, thereby requiring
6804 // recreation each iteration. If a lexical scope exists for the head,
6805 // it must be the innermost one. If that scope has closed-over
6806 // bindings inducing an environment, recreate the current environment.
6807 MOZ_ASSERT(forInTarget->isKind(ParseNodeKind::Let) ||
6808 forInTarget->isKind(ParseNodeKind::Const));
6809 MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
6810 MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() ==
6811 ScopeKind::Lexical);
6812
6813 if (headLexicalEmitterScope->hasEnvironment()) {
6814 if (!emit1(JSOP_RECREATELEXICALENV)) // ITER ITERVAL
6815 return false;
6816 }
6817
6818 // For uncaptured bindings, put them back in TDZ.
6819 if (!headLexicalEmitterScope->deadZoneFrameSlots(this)) return false;
6820 }
6821
6822 {
6823 #ifdef DEBUG
6824 auto loopDepth = this->stackDepth;
6825 #endif
6826 MOZ_ASSERT(loopDepth >= 2);
6827
6828 if (!emit1(JSOP_ITERNEXT)) // ITER ITERVAL
6829 return false;
6830
6831 if (!emitInitializeForInOrOfTarget(forInHead)) // ITER ITERVAL
6832 return false;
6833
6834 MOZ_ASSERT(this->stackDepth == loopDepth,
6835 "iterator and iterval must be left on the stack");
6836 }
6837
6838 // Perform the loop body.
6839 ParseNode* forBody = forInLoop->pn_right;
6840 if (!emitTree(forBody)) // ITER ITERVAL
6841 return false;
6842
6843 // Set offset for continues.
6844 loopInfo.continueTarget = {offset()};
6845
6846 // Make sure this code is attributed to the "for".
6847 if (!updateSourceCoordNotes(forInHead->pn_pos.begin)) return false;
6848
6849 if (!emitLoopEntry(nullptr, initialJump)) // ITER ITERVAL
6850 return false;
6851 if (!emit1(JSOP_POP)) // ITER
6852 return false;
6853 if (!emit1(JSOP_MOREITER)) // ITER NEXTITERVAL?
6854 return false;
6855 if (!emit1(JSOP_ISNOITER)) // ITER NEXTITERVAL? ISNOITER
6856 return false;
6857
6858 JumpList beq;
6859 JumpTarget breakTarget{-1};
6860 if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
6861 return false; // ITER NEXTITERVAL
6862
6863 // Set the srcnote offset so we can find the closing jump.
6864 if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
6865 return false;
6866
6867 if (!loopInfo.patchBreaksAndContinues(this)) return false;
6868
6869 // Pop the enumeration value.
6870 if (!emit1(JSOP_POP)) // ITER
6871 return false;
6872
6873 if (!tryNoteList.append(JSTRY_FOR_IN, this->stackDepth, top.offset, offset()))
6874 return false;
6875
6876 return emit1(JSOP_ENDITER); //
6877 }
6878
6879 /* C-style `for (init; cond; update) ...` loop. */
emitCStyleFor(ParseNode * pn,EmitterScope * headLexicalEmitterScope)6880 bool BytecodeEmitter::emitCStyleFor(ParseNode* pn,
6881 EmitterScope* headLexicalEmitterScope) {
6882 LoopControl loopInfo(this, StatementKind::ForLoop);
6883
6884 ParseNode* forHead = pn->pn_left;
6885 ParseNode* forBody = pn->pn_right;
6886
6887 // If the head of this for-loop declared any lexical variables, the parser
6888 // wrapped this ParseNodeKind::For node in a ParseNodeKind::LexicalScope
6889 // representing the implicit scope of those variables. By the time we get
6890 // here, we have already entered that scope. So far, so good.
6891 //
6892 // ### Scope freshening
6893 //
6894 // Each iteration of a `for (let V...)` loop creates a fresh loop variable
6895 // binding for V, even if the loop is a C-style `for(;;)` loop:
6896 //
6897 // var funcs = [];
6898 // for (let i = 0; i < 2; i++)
6899 // funcs.push(function() { return i; });
6900 // assertEq(funcs[0](), 0); // the two closures capture...
6901 // assertEq(funcs[1](), 1); // ...two different `i` bindings
6902 //
6903 // This is implemented by "freshening" the implicit block -- changing the
6904 // scope chain to a fresh clone of the instantaneous block object -- each
6905 // iteration, just before evaluating the "update" in for(;;) loops.
6906 //
6907 // No freshening occurs in `for (const ...;;)` as there's no point: you
6908 // can't reassign consts. This is observable through the Debugger API. (The
6909 // ES6 spec also skips cloning the environment in this case.)
6910 bool forLoopRequiresFreshening = false;
6911 if (ParseNode* init = forHead->pn_kid1) {
6912 // Emit the `init` clause, whether it's an expression or a variable
6913 // declaration. (The loop variables were hoisted into an enclosing
6914 // scope, but we still need to emit code for the initializers.)
6915 if (!updateSourceCoordNotes(init->pn_pos.begin)) return false;
6916 if (init->isForLoopDeclaration()) {
6917 if (!emitTree(init)) return false;
6918 } else {
6919 // 'init' is an expression, not a declaration. emitTree left its
6920 // value on the stack.
6921 if (!emitTree(init, ValueUsage::IgnoreValue)) return false;
6922 if (!emit1(JSOP_POP)) return false;
6923 }
6924
6925 // ES 13.7.4.8 step 2. The initial freshening.
6926 //
6927 // If an initializer let-declaration may be captured during loop iteration,
6928 // the current scope has an environment. If so, freshen the current
6929 // environment to expose distinct bindings for each loop iteration.
6930 forLoopRequiresFreshening =
6931 init->isKind(ParseNodeKind::Let) && headLexicalEmitterScope;
6932 if (forLoopRequiresFreshening) {
6933 // The environment chain only includes an environment for the for(;;)
6934 // loop head's let-declaration *if* a scope binding is captured, thus
6935 // requiring a fresh environment each iteration. If a lexical scope
6936 // exists for the head, it must be the innermost one. If that scope
6937 // has closed-over bindings inducing an environment, recreate the
6938 // current environment.
6939 MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
6940 MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() ==
6941 ScopeKind::Lexical);
6942
6943 if (headLexicalEmitterScope->hasEnvironment()) {
6944 if (!emit1(JSOP_FRESHENLEXICALENV)) return false;
6945 }
6946 }
6947 }
6948
6949 /*
6950 * NB: the SRC_FOR note has offsetBias 1 (JSOP_NOP_LENGTH).
6951 * Use tmp to hold the biased srcnote "top" offset, which differs
6952 * from the top local variable by the length of the JSOP_GOTO
6953 * emitted in between tmp and top if this loop has a condition.
6954 */
6955 unsigned noteIndex;
6956 if (!newSrcNote(SRC_FOR, ¬eIndex)) return false;
6957 if (!emit1(JSOP_NOP)) return false;
6958 ptrdiff_t tmp = offset();
6959
6960 JumpList jmp;
6961 if (forHead->pn_kid2) {
6962 /* Goto the loop condition, which branches back to iterate. */
6963 if (!emitJump(JSOP_GOTO, &jmp)) return false;
6964 }
6965
6966 /* Emit code for the loop body. */
6967 JumpTarget top{-1};
6968 if (!emitLoopHead(forBody, &top)) return false;
6969 if (jmp.offset == -1 && !emitLoopEntry(forBody, jmp)) return false;
6970
6971 if (!emitTreeInBranch(forBody)) return false;
6972
6973 // Set loop and enclosing "update" offsets, for continue. Note that we
6974 // continue to immediately *before* the block-freshening: continuing must
6975 // refresh the block.
6976 if (!emitJumpTarget(&loopInfo.continueTarget)) return false;
6977
6978 // ES 13.7.4.8 step 3.e. The per-iteration freshening.
6979 if (forLoopRequiresFreshening) {
6980 MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
6981 MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() ==
6982 ScopeKind::Lexical);
6983
6984 if (headLexicalEmitterScope->hasEnvironment()) {
6985 if (!emit1(JSOP_FRESHENLEXICALENV)) return false;
6986 }
6987 }
6988
6989 // Check for update code to do before the condition (if any).
6990 // The update code may not be executed at all; it needs its own TDZ cache.
6991 if (ParseNode* update = forHead->pn_kid3) {
6992 TDZCheckCache tdzCache(this);
6993
6994 if (!updateSourceCoordNotes(update->pn_pos.begin)) return false;
6995 if (!emitTree(update, ValueUsage::IgnoreValue)) return false;
6996 if (!emit1(JSOP_POP)) return false;
6997
6998 /* Restore the absolute line number for source note readers. */
6999 uint32_t lineNum = parser.tokenStream().srcCoords.lineNum(pn->pn_pos.end);
7000 if (currentLine() != lineNum) {
7001 if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum))) return false;
7002 current->currentLine = lineNum;
7003 current->lastColumn = 0;
7004 }
7005 }
7006
7007 ptrdiff_t tmp3 = offset();
7008
7009 if (forHead->pn_kid2) {
7010 /* Fix up the goto from top to target the loop condition. */
7011 MOZ_ASSERT(jmp.offset >= 0);
7012 if (!emitLoopEntry(forHead->pn_kid2, jmp)) return false;
7013
7014 if (!emitTree(forHead->pn_kid2)) return false;
7015 } else if (!forHead->pn_kid3) {
7016 // If there is no condition clause and no update clause, mark
7017 // the loop-ending "goto" with the location of the "for".
7018 // This ensures that the debugger will stop on each loop
7019 // iteration.
7020 if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false;
7021 }
7022
7023 /* Set the first note offset so we can find the loop condition. */
7024 if (!setSrcNoteOffset(noteIndex, 0, tmp3 - tmp)) return false;
7025 if (!setSrcNoteOffset(noteIndex, 1, loopInfo.continueTarget.offset - tmp))
7026 return false;
7027
7028 /* If no loop condition, just emit a loop-closing jump. */
7029 JumpList beq;
7030 JumpTarget breakTarget{-1};
7031 if (!emitBackwardJump(forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO, top, &beq,
7032 &breakTarget))
7033 return false;
7034
7035 /* The third note offset helps us find the loop-closing jump. */
7036 if (!setSrcNoteOffset(noteIndex, 2, beq.offset - tmp)) return false;
7037
7038 if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset,
7039 breakTarget.offset))
7040 return false;
7041
7042 if (!loopInfo.patchBreaksAndContinues(this)) return false;
7043
7044 return true;
7045 }
7046
emitFor(ParseNode * pn,EmitterScope * headLexicalEmitterScope)7047 bool BytecodeEmitter::emitFor(ParseNode* pn,
7048 EmitterScope* headLexicalEmitterScope) {
7049 MOZ_ASSERT(pn->isKind(ParseNodeKind::For));
7050
7051 if (pn->pn_left->isKind(ParseNodeKind::ForHead))
7052 return emitCStyleFor(pn, headLexicalEmitterScope);
7053
7054 if (!updateLineNumberNotes(pn->pn_pos.begin)) return false;
7055
7056 if (pn->pn_left->isKind(ParseNodeKind::ForIn))
7057 return emitForIn(pn, headLexicalEmitterScope);
7058
7059 MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::ForOf));
7060 return emitForOf(pn, headLexicalEmitterScope);
7061 }
7062
emitFunction(ParseNode * pn,bool needsProto)7063 MOZ_NEVER_INLINE bool BytecodeEmitter::emitFunction(ParseNode* pn,
7064 bool needsProto) {
7065 FunctionBox* funbox = pn->pn_funbox;
7066 RootedFunction fun(cx, funbox->function());
7067 RootedAtom name(cx, fun->explicitName());
7068 MOZ_ASSERT_IF(fun->isInterpretedLazy(), fun->lazyScript());
7069
7070 // Set the |wasEmitted| flag in the funbox once the function has been
7071 // emitted. Function definitions that need hoisting to the top of the
7072 // function will be seen by emitFunction in two places.
7073 if (funbox->wasEmitted) {
7074 // Annex B block-scoped functions are hoisted like any other
7075 // block-scoped function to the top of their scope. When their
7076 // definitions are seen for the second time, we need to emit the
7077 // assignment that assigns the function to the outer 'var' binding.
7078 if (funbox->isAnnexB) {
7079 auto emitRhs = [&name](BytecodeEmitter* bce, const NameLocation&, bool) {
7080 // The RHS is the value of the lexically bound name in the
7081 // innermost scope.
7082 return bce->emitGetName(name);
7083 };
7084
7085 // Get the location of the 'var' binding in the body scope. The
7086 // name must be found, else there is a bug in the Annex B handling
7087 // in Parser.
7088 //
7089 // In sloppy eval contexts, this location is dynamic.
7090 Maybe<NameLocation> lhsLoc =
7091 locationOfNameBoundInScope(name, varEmitterScope);
7092
7093 // If there are parameter expressions, the var name could be a
7094 // parameter.
7095 if (!lhsLoc && sc->isFunctionBox() &&
7096 sc->asFunctionBox()->hasExtraBodyVarScope())
7097 lhsLoc = locationOfNameBoundInScope(
7098 name, varEmitterScope->enclosingInFrame());
7099
7100 if (!lhsLoc) {
7101 lhsLoc = Some(NameLocation::DynamicAnnexBVar());
7102 } else {
7103 MOZ_ASSERT(lhsLoc->bindingKind() == BindingKind::Var ||
7104 lhsLoc->bindingKind() == BindingKind::FormalParameter ||
7105 (lhsLoc->bindingKind() == BindingKind::Let &&
7106 sc->asFunctionBox()->hasParameterExprs));
7107 }
7108
7109 if (!emitSetOrInitializeNameAtLocation(name, *lhsLoc, emitRhs, false))
7110 return false;
7111 if (!emit1(JSOP_POP)) return false;
7112 }
7113
7114 MOZ_ASSERT_IF(fun->hasScript(), fun->nonLazyScript());
7115 MOZ_ASSERT(pn->functionIsHoisted());
7116 return true;
7117 }
7118
7119 funbox->wasEmitted = true;
7120
7121 // Mark as singletons any function which will only be executed once, or
7122 // which is inner to a lambda we only expect to run once. In the latter
7123 // case, if the lambda runs multiple times then CloneFunctionObject will
7124 // make a deep clone of its contents.
7125 if (fun->isInterpreted()) {
7126 bool singleton = checkRunOnceContext();
7127 if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
7128 return false;
7129
7130 SharedContext* outersc = sc;
7131 if (fun->isInterpretedLazy()) {
7132 // We need to update the static scope chain regardless of whether
7133 // the LazyScript has already been initialized, due to the case
7134 // where we previously successfully compiled an inner function's
7135 // lazy script but failed to compile the outer script after the
7136 // fact. If we attempt to compile the outer script again, the
7137 // static scope chain will be newly allocated and will mismatch
7138 // the previously compiled LazyScript's.
7139 ScriptSourceObject* source =
7140 &script->sourceObject()->as<ScriptSourceObject>();
7141 fun->lazyScript()->setEnclosingScopeAndSource(innermostScope(), source);
7142 if (emittingRunOnceLambda) fun->lazyScript()->setTreatAsRunOnce();
7143 } else {
7144 MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript);
7145
7146 // Inherit most things (principals, version, etc) from the
7147 // parent. Use default values for the rest.
7148 Rooted<JSScript*> parent(cx, script);
7149 MOZ_ASSERT(parent->mutedErrors() == parser.options().mutedErrors());
7150 const TransitiveCompileOptions& transitiveOptions = parser.options();
7151 CompileOptions options(cx, transitiveOptions);
7152
7153 Rooted<JSObject*> sourceObject(cx, script->sourceObject());
7154 Rooted<JSScript*> script(
7155 cx, JSScript::Create(cx, options, sourceObject, funbox->bufStart,
7156 funbox->bufEnd, funbox->toStringStart,
7157 funbox->toStringEnd));
7158 if (!script) return false;
7159
7160 BytecodeEmitter bce2(this, parser, funbox, script,
7161 /* lazyScript = */ nullptr, pn->pn_pos, emitterMode);
7162 if (!bce2.init()) return false;
7163
7164 /* We measured the max scope depth when we parsed the function. */
7165 if (!bce2.emitFunctionScript(pn->pn_body)) return false;
7166
7167 if (funbox->isLikelyConstructorWrapper())
7168 script->setLikelyConstructorWrapper();
7169 }
7170
7171 if (outersc->isFunctionBox())
7172 outersc->asFunctionBox()->setHasInnerFunctions();
7173 } else {
7174 MOZ_ASSERT(IsAsmJSModule(fun));
7175 }
7176
7177 // Make the function object a literal in the outer script's pool.
7178 unsigned index = objectList.add(pn->pn_funbox);
7179
7180 // Non-hoisted functions simply emit their respective op.
7181 if (!pn->functionIsHoisted()) {
7182 // JSOP_LAMBDA_ARROW is always preceded by a new.target
7183 MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
7184 if (funbox->isAsync()) {
7185 MOZ_ASSERT(!needsProto);
7186 return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow(),
7187 fun->isGenerator());
7188 }
7189
7190 if (fun->isArrow()) {
7191 if (sc->allowNewTarget()) {
7192 if (!emit1(JSOP_NEWTARGET)) return false;
7193 } else {
7194 if (!emit1(JSOP_NULL)) return false;
7195 }
7196 }
7197
7198 if (needsProto) {
7199 MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA);
7200 pn->setOp(JSOP_FUNWITHPROTO);
7201 }
7202
7203 if (pn->getOp() == JSOP_DEFFUN) {
7204 if (!emitIndex32(JSOP_LAMBDA, index)) return false;
7205 return emit1(JSOP_DEFFUN);
7206 }
7207
7208 // This is a FunctionExpression, ArrowFunctionExpression, or class
7209 // constructor. Emit the single instruction (without location info).
7210 return emitIndex32(pn->getOp(), index);
7211 }
7212
7213 MOZ_ASSERT(!needsProto);
7214
7215 bool topLevelFunction;
7216 if (sc->isFunctionBox() || (sc->isEvalContext() && sc->strict())) {
7217 // No nested functions inside other functions are top-level.
7218 topLevelFunction = false;
7219 } else {
7220 // In sloppy eval scripts, top-level functions in are accessed
7221 // dynamically. In global and module scripts, top-level functions are
7222 // those bound in the var scope.
7223 NameLocation loc = lookupName(name);
7224 topLevelFunction = loc.kind() == NameLocation::Kind::Dynamic ||
7225 loc.bindingKind() == BindingKind::Var;
7226 }
7227
7228 if (topLevelFunction) {
7229 if (sc->isModuleContext()) {
7230 // For modules, we record the function and instantiate the binding
7231 // during ModuleInstantiate(), before the script is run.
7232
7233 RootedModuleObject module(cx, sc->asModuleContext()->module());
7234 if (!module->noteFunctionDeclaration(cx, name, fun)) return false;
7235 } else {
7236 MOZ_ASSERT(sc->isGlobalContext() || sc->isEvalContext());
7237 MOZ_ASSERT(pn->getOp() == JSOP_NOP);
7238 switchToPrologue();
7239 if (funbox->isAsync()) {
7240 if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow(),
7241 fun->isGenerator())) {
7242 return false;
7243 }
7244 } else {
7245 if (!emitIndex32(JSOP_LAMBDA, index)) return false;
7246 }
7247 if (!emit1(JSOP_DEFFUN)) return false;
7248 switchToMain();
7249 }
7250 } else {
7251 // For functions nested within functions and blocks, make a lambda and
7252 // initialize the binding name of the function in the current scope.
7253
7254 bool isAsync = funbox->isAsync();
7255 bool isGenerator = funbox->isGenerator();
7256 auto emitLambda = [index, isAsync, isGenerator](BytecodeEmitter* bce,
7257 const NameLocation&, bool) {
7258 if (isAsync) {
7259 return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
7260 /* isArrow = */ false, isGenerator);
7261 }
7262 return bce->emitIndexOp(JSOP_LAMBDA, index);
7263 };
7264
7265 if (!emitInitializeName(name, emitLambda)) return false;
7266 if (!emit1(JSOP_POP)) return false;
7267 }
7268
7269 return true;
7270 }
7271
emitAsyncWrapperLambda(unsigned index,bool isArrow)7272 bool BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
7273 if (isArrow) {
7274 if (sc->allowNewTarget()) {
7275 if (!emit1(JSOP_NEWTARGET)) return false;
7276 } else {
7277 if (!emit1(JSOP_NULL)) return false;
7278 }
7279 if (!emitIndex32(JSOP_LAMBDA_ARROW, index)) return false;
7280 } else {
7281 if (!emitIndex32(JSOP_LAMBDA, index)) return false;
7282 }
7283
7284 return true;
7285 }
7286
emitAsyncWrapper(unsigned index,bool needsHomeObject,bool isArrow,bool isGenerator)7287 bool BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject,
7288 bool isArrow, bool isGenerator) {
7289 // needsHomeObject can be true for propertyList for extended class.
7290 // In that case push both unwrapped and wrapped function, in order to
7291 // initialize home object of unwrapped function, and set wrapped function
7292 // as a property.
7293 //
7294 // lambda // unwrapped
7295 // dup // unwrapped unwrapped
7296 // toasync // unwrapped wrapped
7297 //
7298 // Emitted code is surrounded by the following code.
7299 //
7300 // // classObj classCtor classProto
7301 // (emitted code) // classObj classCtor classProto unwrapped wrapped
7302 // swap // classObj classCtor classProto wrapped unwrapped
7303 // inithomeobject 1 // classObj classCtor classProto wrapped unwrapped
7304 // // initialize the home object of unwrapped
7305 // // with classProto here
7306 // pop // classObj classCtor classProto wrapped
7307 // inithiddenprop // classObj classCtor classProto wrapped
7308 // // initialize the property of the classProto
7309 // // with wrapped function here
7310 // pop // classObj classCtor classProto
7311 //
7312 // needsHomeObject is false for other cases, push wrapped function only.
7313 if (!emitAsyncWrapperLambda(index, isArrow)) return false;
7314 if (needsHomeObject) {
7315 if (!emit1(JSOP_DUP)) return false;
7316 }
7317 if (isGenerator) {
7318 if (!emit1(JSOP_TOASYNCGEN)) return false;
7319 } else {
7320 if (!emit1(JSOP_TOASYNC)) return false;
7321 }
7322 return true;
7323 }
7324
emitDo(ParseNode * pn)7325 bool BytecodeEmitter::emitDo(ParseNode* pn) {
7326 /* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */
7327 unsigned noteIndex;
7328 if (!newSrcNote(SRC_WHILE, ¬eIndex)) return false;
7329 if (!emit1(JSOP_NOP)) return false;
7330
7331 unsigned noteIndex2;
7332 if (!newSrcNote(SRC_WHILE, ¬eIndex2)) return false;
7333
7334 /* Compile the loop body. */
7335 JumpTarget top;
7336 if (!emitLoopHead(pn->pn_left, &top)) return false;
7337
7338 LoopControl loopInfo(this, StatementKind::DoLoop);
7339
7340 JumpList empty;
7341 if (!emitLoopEntry(nullptr, empty)) return false;
7342
7343 if (!emitTree(pn->pn_left)) return false;
7344
7345 // Set the offset for continues.
7346 if (!emitJumpTarget(&loopInfo.continueTarget)) return false;
7347
7348 /* Compile the loop condition, now that continues know where to go. */
7349 if (!emitTree(pn->pn_right)) return false;
7350
7351 JumpList beq;
7352 JumpTarget breakTarget{-1};
7353 if (!emitBackwardJump(JSOP_IFNE, top, &beq, &breakTarget)) return false;
7354
7355 if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset,
7356 breakTarget.offset))
7357 return false;
7358
7359 /*
7360 * Update the annotations with the update and back edge positions, for
7361 * IonBuilder.
7362 *
7363 * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
7364 * note gets bigger.
7365 */
7366 if (!setSrcNoteOffset(noteIndex2, 0, beq.offset - top.offset)) return false;
7367 if (!setSrcNoteOffset(noteIndex, 0,
7368 1 + (loopInfo.continueTarget.offset - top.offset)))
7369 return false;
7370
7371 if (!loopInfo.patchBreaksAndContinues(this)) return false;
7372
7373 return true;
7374 }
7375
emitWhile(ParseNode * pn)7376 bool BytecodeEmitter::emitWhile(ParseNode* pn) {
7377 /*
7378 * Minimize bytecodes issued for one or more iterations by jumping to
7379 * the condition below the body and closing the loop if the condition
7380 * is true with a backward branch. For iteration count i:
7381 *
7382 * i test at the top test at the bottom
7383 * = =============== ==================
7384 * 0 ifeq-pass goto; ifne-fail
7385 * 1 ifeq-fail; goto; ifne-pass goto; ifne-pass; ifne-fail
7386 * 2 2*(ifeq-fail; goto); ifeq-pass goto; 2*ifne-pass; ifne-fail
7387 * . . .
7388 * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail
7389 */
7390
7391 // If we have a single-line while, like "while (x) ;", we want to
7392 // emit the line note before the initial goto, so that the
7393 // debugger sees a single entry point. This way, if there is a
7394 // breakpoint on the line, it will only fire once; and "next"ing
7395 // will skip the whole loop. However, for the multi-line case we
7396 // want to emit the line note after the initial goto, so that
7397 // "cont" stops on each iteration -- but without a stop before the
7398 // first iteration.
7399 if (parser.tokenStream().srcCoords.lineNum(pn->pn_pos.begin) ==
7400 parser.tokenStream().srcCoords.lineNum(pn->pn_pos.end)) {
7401 if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false;
7402 }
7403
7404 JumpTarget top{-1};
7405 if (!emitJumpTarget(&top)) return false;
7406
7407 LoopControl loopInfo(this, StatementKind::WhileLoop);
7408 loopInfo.continueTarget = top;
7409
7410 unsigned noteIndex;
7411 if (!newSrcNote(SRC_WHILE, ¬eIndex)) return false;
7412
7413 JumpList jmp;
7414 if (!emitJump(JSOP_GOTO, &jmp)) return false;
7415
7416 if (!emitLoopHead(pn->pn_right, &top)) return false;
7417
7418 if (!emitTreeInBranch(pn->pn_right)) return false;
7419
7420 if (!emitLoopEntry(pn->pn_left, jmp)) return false;
7421 if (!emitTree(pn->pn_left)) return false;
7422
7423 JumpList beq;
7424 JumpTarget breakTarget{-1};
7425 if (!emitBackwardJump(JSOP_IFNE, top, &beq, &breakTarget)) return false;
7426
7427 if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset,
7428 breakTarget.offset))
7429 return false;
7430
7431 if (!setSrcNoteOffset(noteIndex, 0, beq.offset - jmp.offset)) return false;
7432
7433 if (!loopInfo.patchBreaksAndContinues(this)) return false;
7434
7435 return true;
7436 }
7437
emitBreak(PropertyName * label)7438 bool BytecodeEmitter::emitBreak(PropertyName* label) {
7439 BreakableControl* target;
7440 SrcNoteType noteType;
7441 if (label) {
7442 // Any statement with the matching label may be the break target.
7443 auto hasSameLabel = [label](LabelControl* labelControl) {
7444 return labelControl->label() == label;
7445 };
7446 target = findInnermostNestableControl<LabelControl>(hasSameLabel);
7447 noteType = SRC_BREAK2LABEL;
7448 } else {
7449 auto isNotLabel = [](BreakableControl* control) {
7450 return !control->is<LabelControl>();
7451 };
7452 target = findInnermostNestableControl<BreakableControl>(isNotLabel);
7453 noteType =
7454 (target->kind() == StatementKind::Switch) ? SRC_SWITCHBREAK : SRC_BREAK;
7455 }
7456
7457 return emitGoto(target, &target->breaks, noteType);
7458 }
7459
emitContinue(PropertyName * label)7460 bool BytecodeEmitter::emitContinue(PropertyName* label) {
7461 LoopControl* target = nullptr;
7462 if (label) {
7463 // Find the loop statement enclosed by the matching label.
7464 NestableControl* control = innermostNestableControl;
7465 while (!control->is<LabelControl>() ||
7466 control->as<LabelControl>().label() != label) {
7467 if (control->is<LoopControl>()) target = &control->as<LoopControl>();
7468 control = control->enclosing();
7469 }
7470 } else {
7471 target = findInnermostNestableControl<LoopControl>();
7472 }
7473 return emitGoto(target, &target->continues, SRC_CONTINUE);
7474 }
7475
emitGetFunctionThis(ParseNode * pn)7476 bool BytecodeEmitter::emitGetFunctionThis(ParseNode* pn) {
7477 MOZ_ASSERT(sc->thisBinding() == ThisBinding::Function);
7478 MOZ_ASSERT(pn->isKind(ParseNodeKind::Name));
7479 MOZ_ASSERT(pn->name() == cx->names().dotThis);
7480
7481 if (!emitTree(pn)) return false;
7482 if (sc->needsThisTDZChecks() && !emit1(JSOP_CHECKTHIS)) return false;
7483
7484 return true;
7485 }
7486
emitGetThisForSuperBase(ParseNode * pn)7487 bool BytecodeEmitter::emitGetThisForSuperBase(ParseNode* pn) {
7488 MOZ_ASSERT(pn->isKind(ParseNodeKind::SuperBase));
7489 return emitGetFunctionThis(pn->pn_kid);
7490 }
7491
emitThisLiteral(ParseNode * pn)7492 bool BytecodeEmitter::emitThisLiteral(ParseNode* pn) {
7493 MOZ_ASSERT(pn->isKind(ParseNodeKind::This));
7494
7495 if (ParseNode* thisName = pn->pn_kid) return emitGetFunctionThis(thisName);
7496
7497 if (sc->thisBinding() == ThisBinding::Module) return emit1(JSOP_UNDEFINED);
7498
7499 MOZ_ASSERT(sc->thisBinding() == ThisBinding::Global);
7500 return emit1(JSOP_GLOBALTHIS);
7501 }
7502
emitCheckDerivedClassConstructorReturn()7503 bool BytecodeEmitter::emitCheckDerivedClassConstructorReturn() {
7504 MOZ_ASSERT(lookupName(cx->names().dotThis).hasKnownSlot());
7505 if (!emitGetName(cx->names().dotThis)) return false;
7506 if (!emit1(JSOP_CHECKRETURN)) return false;
7507 return true;
7508 }
7509
emitReturn(ParseNode * pn)7510 bool BytecodeEmitter::emitReturn(ParseNode* pn) {
7511 if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false;
7512
7513 bool needsIteratorResult =
7514 sc->isFunctionBox() && sc->asFunctionBox()->needsIteratorResult();
7515 if (needsIteratorResult) {
7516 if (!emitPrepareIteratorResult()) return false;
7517 }
7518
7519 /* Push a return value */
7520 if (ParseNode* pn2 = pn->pn_kid) {
7521 if (!emitTree(pn2)) return false;
7522
7523 bool isAsyncGenerator =
7524 sc->asFunctionBox()->isAsync() && sc->asFunctionBox()->isGenerator();
7525 if (isAsyncGenerator) {
7526 if (!emitAwaitInInnermostScope()) return false;
7527 }
7528 } else {
7529 /* No explicit return value provided */
7530 if (!emit1(JSOP_UNDEFINED)) return false;
7531 }
7532
7533 if (needsIteratorResult) {
7534 if (!emitFinishIteratorResult(true)) return false;
7535 }
7536
7537 // We know functionBodyEndPos is set because "return" is only
7538 // valid in a function, and so we've passed through
7539 // emitFunctionScript.
7540 MOZ_ASSERT(functionBodyEndPosSet);
7541 if (!updateSourceCoordNotes(functionBodyEndPos)) return false;
7542
7543 /*
7544 * EmitNonLocalJumpFixup may add fixup bytecode to close open try
7545 * blocks having finally clauses and to exit intermingled let blocks.
7546 * We can't simply transfer control flow to our caller in that case,
7547 * because we must gosub to those finally clauses from inner to outer,
7548 * with the correct stack pointer (i.e., after popping any with,
7549 * for/in, etc., slots nested inside the finally's try).
7550 *
7551 * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
7552 * extra JSOP_RETRVAL after the fixups.
7553 */
7554 ptrdiff_t top = offset();
7555
7556 bool needsFinalYield =
7557 sc->isFunctionBox() && sc->asFunctionBox()->needsFinalYield();
7558 bool isDerivedClassConstructor =
7559 sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
7560
7561 if (!emit1((needsFinalYield || isDerivedClassConstructor) ? JSOP_SETRVAL
7562 : JSOP_RETURN))
7563 return false;
7564
7565 // Make sure that we emit this before popping the blocks in
7566 // prepareForNonLocalJump, to ensure that the error is thrown while the
7567 // scope-chain is still intact.
7568 if (isDerivedClassConstructor) {
7569 if (!emitCheckDerivedClassConstructorReturn()) return false;
7570 }
7571
7572 NonLocalExitControl nle(this, NonLocalExitControl::Return);
7573
7574 if (!nle.prepareForNonLocalJumpToOutermost()) return false;
7575
7576 if (needsFinalYield) {
7577 // We know that .generator is on the function scope, as we just exited
7578 // all nested scopes.
7579 NameLocation loc = *locationOfNameBoundInFunctionScope(
7580 cx->names().dotGenerator, varEmitterScope);
7581 if (!emitGetNameAtLocation(cx->names().dotGenerator, loc)) return false;
7582 if (!emitYieldOp(JSOP_FINALYIELDRVAL)) return false;
7583 } else if (isDerivedClassConstructor) {
7584 MOZ_ASSERT(code()[top] == JSOP_SETRVAL);
7585 if (!emit1(JSOP_RETRVAL)) return false;
7586 } else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) != offset()) {
7587 code()[top] = JSOP_SETRVAL;
7588 if (!emit1(JSOP_RETRVAL)) return false;
7589 }
7590
7591 return true;
7592 }
7593
emitGetDotGeneratorInScope(EmitterScope & currentScope)7594 bool BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope& currentScope) {
7595 NameLocation loc = *locationOfNameBoundInFunctionScope(
7596 cx->names().dotGenerator, ¤tScope);
7597 return emitGetNameAtLocation(cx->names().dotGenerator, loc);
7598 }
7599
emitInitialYield(ParseNode * pn)7600 bool BytecodeEmitter::emitInitialYield(ParseNode* pn) {
7601 if (!emitTree(pn->pn_kid)) return false;
7602
7603 if (!emitYieldOp(JSOP_INITIALYIELD)) return false;
7604
7605 if (!emit1(JSOP_POP)) return false;
7606
7607 return true;
7608 }
7609
emitYield(ParseNode * pn)7610 bool BytecodeEmitter::emitYield(ParseNode* pn) {
7611 MOZ_ASSERT(sc->isFunctionBox());
7612 MOZ_ASSERT(pn->isKind(ParseNodeKind::Yield));
7613
7614 bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
7615 if (needsIteratorResult) {
7616 if (!emitPrepareIteratorResult()) return false;
7617 }
7618 if (pn->pn_kid) {
7619 if (!emitTree(pn->pn_kid)) return false;
7620 } else {
7621 if (!emit1(JSOP_UNDEFINED)) return false;
7622 }
7623
7624 // 11.4.3.7 AsyncGeneratorYield step 5.
7625 bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
7626 if (isAsyncGenerator) {
7627 if (!emitAwaitInInnermostScope()) // RESULT
7628 return false;
7629 }
7630
7631 if (needsIteratorResult) {
7632 if (!emitFinishIteratorResult(false)) return false;
7633 }
7634
7635 if (!emitGetDotGeneratorInInnermostScope()) return false;
7636
7637 if (!emitYieldOp(JSOP_YIELD)) return false;
7638
7639 return true;
7640 }
7641
emitAwaitInInnermostScope(ParseNode * pn)7642 bool BytecodeEmitter::emitAwaitInInnermostScope(ParseNode* pn) {
7643 MOZ_ASSERT(sc->isFunctionBox());
7644 MOZ_ASSERT(pn->isKind(ParseNodeKind::Await));
7645
7646 if (!emitTree(pn->pn_kid)) return false;
7647 return emitAwaitInInnermostScope();
7648 }
7649
emitAwaitInScope(EmitterScope & currentScope)7650 bool BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope) {
7651 if (!emitGetDotGeneratorInScope(currentScope)) return false;
7652 if (!emitYieldOp(JSOP_AWAIT)) return false;
7653 return true;
7654 }
7655
emitYieldStar(ParseNode * iter)7656 bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
7657 MOZ_ASSERT(sc->isFunctionBox());
7658 MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
7659
7660 bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
7661
7662 if (!emitTree(iter)) // ITERABLE
7663 return false;
7664 if (isAsyncGenerator) {
7665 if (!emitAsyncIterator()) // NEXT ITER
7666 return false;
7667 } else {
7668 if (!emitIterator()) // NEXT ITER
7669 return false;
7670 }
7671
7672 // Initial send value is undefined.
7673 if (!emit1(JSOP_UNDEFINED)) // NEXT ITER RECEIVED
7674 return false;
7675
7676 int32_t savedDepthTemp;
7677 int32_t startDepth = stackDepth;
7678 MOZ_ASSERT(startDepth >= 3);
7679
7680 TryEmitter tryCatch(this, TryEmitter::TryCatchFinally,
7681 TryEmitter::DontUseRetVal, TryEmitter::DontUseControl);
7682 if (!tryCatch.emitJumpOverCatchAndFinally()) // NEXT ITER RESULT
7683 return false;
7684
7685 JumpTarget tryStart{offset()};
7686 if (!tryCatch.emitTry()) // NEXT ITER RESULT
7687 return false;
7688
7689 MOZ_ASSERT(this->stackDepth == startDepth);
7690
7691 // 11.4.3.7 AsyncGeneratorYield step 5.
7692 if (isAsyncGenerator) {
7693 if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT
7694 return false;
7695 }
7696
7697 // Load the generator object.
7698 if (!emitGetDotGeneratorInInnermostScope()) // NEXT ITER RESULT GENOBJ
7699 return false;
7700
7701 // Yield RESULT as-is, without re-boxing.
7702 if (!emitYieldOp(JSOP_YIELD)) // NEXT ITER RECEIVED
7703 return false;
7704
7705 if (!tryCatch.emitCatch()) // NEXT ITER RESULT
7706 return false;
7707
7708 stackDepth = startDepth; // NEXT ITER RESULT
7709 if (!emit1(JSOP_EXCEPTION)) // NEXT ITER RESULT EXCEPTION
7710 return false;
7711 if (!emitDupAt(2)) // NEXT ITER RESULT EXCEPTION ITER
7712 return false;
7713 if (!emit1(JSOP_DUP)) // NEXT ITER RESULT EXCEPTION ITER ITER
7714 return false;
7715 if (!emitAtomOp(cx->names().throw_,
7716 JSOP_CALLPROP)) // NEXT ITER RESULT EXCEPTION ITER THROW
7717 return false;
7718 if (!emit1(JSOP_DUP)) // NEXT ITER RESULT EXCEPTION ITER THROW THROW
7719 return false;
7720 if (!emit1(JSOP_UNDEFINED)) // NEXT ITER RESULT EXCEPTION ITER THROW THROW
7721 // UNDEFINED
7722 return false;
7723 if (!emit1(JSOP_EQ)) // NEXT ITER RESULT EXCEPTION ITER THROW ?EQL
7724 return false;
7725
7726 IfThenElseEmitter ifThrowMethodIsNotDefined(this);
7727 if (!ifThrowMethodIsNotDefined
7728 .emitIf()) // NEXT ITER RESULT EXCEPTION ITER THROW
7729 return false;
7730 savedDepthTemp = stackDepth;
7731 if (!emit1(JSOP_POP)) // NEXT ITER RESULT EXCEPTION ITER
7732 return false;
7733 // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
7734 //
7735 // If the iterator does not have a "throw" method, it calls IteratorClose
7736 // and then throws a TypeError.
7737 IteratorKind iterKind =
7738 isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
7739 if (!emitIteratorCloseInInnermostScope(
7740 iterKind)) // NEXT ITER RESULT EXCEPTION
7741 return false;
7742 if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
7743 return false;
7744 stackDepth = savedDepthTemp;
7745 if (!ifThrowMethodIsNotDefined
7746 .emitEnd()) // NEXT ITER OLDRESULT EXCEPTION ITER THROW
7747 return false;
7748 // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.4.
7749 // RESULT = ITER.throw(EXCEPTION) // NEXT ITER OLDRESULT
7750 // EXCEPTION ITER THROW
7751 if (!emit1(JSOP_SWAP)) // NEXT ITER OLDRESULT EXCEPTION THROW ITER
7752 return false;
7753 if (!emit2(JSOP_PICK, 2)) // NEXT ITER OLDRESULT THROW ITER EXCEPTION
7754 return false;
7755 if (!emitCall(JSOP_CALL, 1, iter)) // NEXT ITER OLDRESULT RESULT
7756 return false;
7757 checkTypeSet(JSOP_CALL);
7758
7759 if (isAsyncGenerator) {
7760 if (!emitAwaitInInnermostScope()) // NEXT ITER OLDRESULT RESULT
7761 return false;
7762 }
7763
7764 if (!emitCheckIsObj(
7765 CheckIsObjectKind::IteratorThrow)) // NEXT ITER OLDRESULT RESULT
7766 return false;
7767 if (!emit1(JSOP_SWAP)) // NEXT ITER RESULT OLDRESULT
7768 return false;
7769 if (!emit1(JSOP_POP)) // NEXT ITER RESULT
7770 return false;
7771 MOZ_ASSERT(this->stackDepth == startDepth);
7772 JumpList checkResult;
7773 // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.ii.
7774 //
7775 // Note that there is no GOSUB to the finally block here. If the iterator has
7776 // a "throw" method, it does not perform IteratorClose.
7777 if (!emitJump(JSOP_GOTO, &checkResult)) // goto checkResult
7778 return false;
7779
7780 if (!tryCatch.emitFinally()) return false;
7781
7782 // ES 14.4.13, yield * AssignmentExpression, step 5.c
7783 //
7784 // Call iterator.return() for receiving a "forced return" completion from
7785 // the generator.
7786
7787 IfThenElseEmitter ifGeneratorClosing(this);
7788 if (!emit1(JSOP_ISGENCLOSING)) // NEXT ITER RESULT FTYPE FVALUE CLOSING
7789 return false;
7790 if (!ifGeneratorClosing.emitIf()) // NEXT ITER RESULT FTYPE FVALUE
7791 return false;
7792
7793 // Step ii.
7794 //
7795 // Get the "return" method.
7796 if (!emitDupAt(3)) // NEXT ITER RESULT FTYPE FVALUE ITER
7797 return false;
7798 if (!emit1(JSOP_DUP)) // NEXT ITER RESULT FTYPE FVALUE ITER ITER
7799 return false;
7800 if (!emitAtomOp(cx->names().return_,
7801 JSOP_CALLPROP)) // NEXT ITER RESULT FTYPE FVALUE ITER RET
7802 return false;
7803
7804 // Step iii.
7805 //
7806 // Do nothing if "return" is undefined or null.
7807 IfThenElseEmitter ifReturnMethodIsDefined(this);
7808 if (!emitPushNotUndefinedOrNull()) // NEXT ITER RESULT FTYPE FVALUE ITER RET
7809 // NOT-UNDEF-OR-NULL
7810 return false;
7811
7812 // Step iv.
7813 //
7814 // Call "return" with the argument passed to Generator.prototype.return,
7815 // which is currently in rval.value.
7816 if (!ifReturnMethodIsDefined
7817 .emitIfElse()) // NEXT ITER OLDRESULT FTYPE FVALUE ITER RET
7818 return false;
7819 if (!emit1(JSOP_SWAP)) // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER
7820 return false;
7821 if (!emit1(JSOP_GETRVAL)) // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER RVAL
7822 return false;
7823 if (!emitAtomOp(
7824 cx->names().value,
7825 JSOP_GETPROP)) // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER VALUE
7826 return false;
7827 if (!emitCall(JSOP_CALL, 1)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
7828 return false;
7829 checkTypeSet(JSOP_CALL);
7830
7831 if (iterKind == IteratorKind::Async) {
7832 if (!emitAwaitInInnermostScope()) // ... FTYPE FVALUE RESULT
7833 return false;
7834 }
7835
7836 // Step v.
7837 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // NEXT ITER
7838 // OLDRESULT FTYPE
7839 // FVALUE RESULT
7840 return false;
7841
7842 // Steps vi-viii.
7843 //
7844 // Check if the returned object from iterator.return() is done. If not,
7845 // continuing yielding.
7846 IfThenElseEmitter ifReturnDone(this);
7847 if (!emit1(JSOP_DUP)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT RESULT
7848 return false;
7849 if (!emitAtomOp(
7850 cx->names().done,
7851 JSOP_GETPROP)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT DONE
7852 return false;
7853 if (!ifReturnDone.emitIfElse()) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
7854 return false;
7855 if (!emitAtomOp(cx->names().value,
7856 JSOP_GETPROP)) // NEXT ITER OLDRESULT FTYPE FVALUE VALUE
7857 return false;
7858
7859 if (!emitPrepareIteratorResult()) // NEXT ITER OLDRESULT FTYPE FVALUE VALUE
7860 // RESULT
7861 return false;
7862 if (!emit1(JSOP_SWAP)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT VALUE
7863 return false;
7864 if (!emitFinishIteratorResult(
7865 true)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
7866 return false;
7867 if (!emit1(JSOP_SETRVAL)) // NEXT ITER OLDRESULT FTYPE FVALUE
7868 return false;
7869 savedDepthTemp = this->stackDepth;
7870 if (!ifReturnDone.emitElse()) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
7871 return false;
7872 if (!emit2(JSOP_UNPICK, 3)) // NEXT ITER RESULT OLDRESULT FTYPE FVALUE
7873 return false;
7874 if (!emitPopN(3)) // NEXT ITER RESULT
7875 return false;
7876 {
7877 // goto tryStart;
7878 JumpList beq;
7879 JumpTarget breakTarget{-1};
7880 if (!emitBackwardJump(JSOP_GOTO, tryStart, &beq,
7881 &breakTarget)) // NEXT ITER RESULT
7882 return false;
7883 }
7884 this->stackDepth = savedDepthTemp;
7885 if (!ifReturnDone.emitEnd()) return false;
7886
7887 if (!ifReturnMethodIsDefined
7888 .emitElse()) // NEXT ITER RESULT FTYPE FVALUE ITER RET
7889 return false;
7890 if (!emitPopN(2)) // NEXT ITER RESULT FTYPE FVALUE
7891 return false;
7892 if (!ifReturnMethodIsDefined.emitEnd()) return false;
7893
7894 if (!ifGeneratorClosing.emitEnd()) return false;
7895
7896 if (!tryCatch.emitEnd()) return false;
7897
7898 // [stack] NEXT ITER RECEIVED
7899
7900 // After the try-catch-finally block: send the received value to the iterator.
7901 // result = iter.next(received) // NEXT ITER
7902 // RECEIVED
7903 if (!emit2(JSOP_UNPICK, 2)) // RECEIVED NEXT ITER
7904 return false;
7905 if (!emit1(JSOP_DUP2)) // RECEIVED NEXT ITER NEXT ITER
7906 return false;
7907 if (!emit2(JSOP_PICK, 4)) // NEXT ITER NEXT ITER RECEIVED
7908 return false;
7909 if (!emitCall(JSOP_CALL, 1, iter)) // NEXT ITER RESULT
7910 return false;
7911 checkTypeSet(JSOP_CALL);
7912
7913 if (isAsyncGenerator) {
7914 if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT RESULT
7915 return false;
7916 }
7917
7918 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // NEXT ITER RESULT
7919 return false;
7920 MOZ_ASSERT(this->stackDepth == startDepth);
7921
7922 if (!emitJumpTargetAndPatch(checkResult)) // checkResult:
7923 return false;
7924
7925 // if (!result.done) goto tryStart; // NEXT ITER
7926 // RESULT
7927 if (!emit1(JSOP_DUP)) // NEXT ITER RESULT RESULT
7928 return false;
7929 if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // NEXT ITER RESULT DONE
7930 return false;
7931 // if (!DONE) goto tryStart;
7932 {
7933 JumpList beq;
7934 JumpTarget breakTarget{-1};
7935 if (!emitBackwardJump(JSOP_IFEQ, tryStart, &beq,
7936 &breakTarget)) // NEXT ITER RESULT
7937 return false;
7938 }
7939
7940 // result.value
7941 if (!emit2(JSOP_UNPICK, 2)) // RESULT NEXT ITER
7942 return false;
7943 if (!emitPopN(2)) // RESULT
7944 return false;
7945 if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // VALUE
7946 return false;
7947
7948 MOZ_ASSERT(this->stackDepth == startDepth - 2);
7949
7950 return true;
7951 }
7952
emitStatementList(ParseNode * pn)7953 bool BytecodeEmitter::emitStatementList(ParseNode* pn) {
7954 MOZ_ASSERT(pn->isArity(PN_LIST));
7955 for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
7956 if (!emitTree(pn2)) return false;
7957 }
7958 return true;
7959 }
7960
emitExpressionStatement(ParseNode * pn)7961 bool BytecodeEmitter::emitExpressionStatement(ParseNode* pn) {
7962 MOZ_ASSERT(pn->isKind(ParseNodeKind::ExpressionStatement));
7963
7964 if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false;
7965
7966 /*
7967 * Top-level or called-from-a-native JS_Execute/EvaluateScript,
7968 * debugger, and eval frames may need the value of the ultimate
7969 * expression statement as the script's result, despite the fact
7970 * that it appears useless to the compiler.
7971 *
7972 * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
7973 * calling JS_Compile* to suppress JSOP_SETRVAL.
7974 */
7975 bool wantval = false;
7976 bool useful = false;
7977 if (sc->isFunctionBox())
7978 MOZ_ASSERT(!script->noScriptRval());
7979 else
7980 useful = wantval = !script->noScriptRval();
7981
7982 /* Don't eliminate expressions with side effects. */
7983 ParseNode* expr = pn->pn_kid;
7984 if (!useful) {
7985 if (!checkSideEffects(expr, &useful)) return false;
7986
7987 /*
7988 * Don't eliminate apparently useless expressions if they are labeled
7989 * expression statements. The startOffset() test catches the case
7990 * where we are nesting in emitTree for a labeled compound statement.
7991 */
7992 if (innermostNestableControl &&
7993 innermostNestableControl->is<LabelControl>() &&
7994 innermostNestableControl->as<LabelControl>().startOffset() >=
7995 offset()) {
7996 useful = true;
7997 }
7998 }
7999
8000 if (useful) {
8001 JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
8002 ValueUsage valueUsage =
8003 wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
8004 MOZ_ASSERT_IF(expr->isKind(ParseNodeKind::Assign), expr->isOp(JSOP_NOP));
8005 if (!emitTree(expr, valueUsage)) return false;
8006 if (!emit1(op)) return false;
8007 } else if (pn->isDirectivePrologueMember()) {
8008 // Don't complain about directive prologue members; just don't emit
8009 // their code.
8010 } else {
8011 if (JSAtom* atom = pn->isStringExprStatement()) {
8012 // Warn if encountering a non-directive prologue member string
8013 // expression statement, that is inconsistent with the current
8014 // directive prologue. That is, a script *not* starting with
8015 // "use strict" should warn for any "use strict" statements seen
8016 // later in the script, because such statements are misleading.
8017 const char* directive = nullptr;
8018 if (atom == cx->names().useStrict) {
8019 if (!sc->strictScript) directive = js_useStrict_str;
8020 } else if (atom == cx->names().useAsm) {
8021 if (sc->isFunctionBox()) {
8022 if (IsAsmJSModule(sc->asFunctionBox()->function()))
8023 directive = js_useAsm_str;
8024 }
8025 }
8026
8027 if (directive) {
8028 if (!reportExtraWarning(expr, JSMSG_CONTRARY_NONDIRECTIVE, directive))
8029 return false;
8030 }
8031 } else {
8032 if (!reportExtraWarning(expr, JSMSG_USELESS_EXPR)) return false;
8033 }
8034 }
8035
8036 return true;
8037 }
8038
emitDeleteName(ParseNode * node)8039 bool BytecodeEmitter::emitDeleteName(ParseNode* node) {
8040 MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteName));
8041 MOZ_ASSERT(node->isArity(PN_UNARY));
8042
8043 ParseNode* nameExpr = node->pn_kid;
8044 MOZ_ASSERT(nameExpr->isKind(ParseNodeKind::Name));
8045
8046 return emitAtomOp(nameExpr, JSOP_DELNAME);
8047 }
8048
emitDeleteProperty(ParseNode * node)8049 bool BytecodeEmitter::emitDeleteProperty(ParseNode* node) {
8050 MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteProp));
8051 MOZ_ASSERT(node->isArity(PN_UNARY));
8052
8053 ParseNode* propExpr = node->pn_kid;
8054 MOZ_ASSERT(propExpr->isKind(ParseNodeKind::Dot));
8055
8056 if (propExpr->as<PropertyAccess>().isSuper()) {
8057 // Still have to calculate the base, even though we are are going
8058 // to throw unconditionally, as calculating the base could also
8059 // throw.
8060 if (!emit1(JSOP_SUPERBASE)) return false;
8061
8062 return emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER);
8063 }
8064
8065 JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
8066 return emitPropOp(propExpr, delOp);
8067 }
8068
emitDeleteElement(ParseNode * node)8069 bool BytecodeEmitter::emitDeleteElement(ParseNode* node) {
8070 MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteElem));
8071 MOZ_ASSERT(node->isArity(PN_UNARY));
8072
8073 ParseNode* elemExpr = node->pn_kid;
8074 MOZ_ASSERT(elemExpr->isKind(ParseNodeKind::Elem));
8075
8076 if (elemExpr->as<PropertyByValue>().isSuper()) {
8077 // Still have to calculate everything, even though we're gonna throw
8078 // since it may have side effects
8079 if (!emitTree(elemExpr->pn_right)) return false;
8080
8081 if (!emit1(JSOP_SUPERBASE)) return false;
8082 if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
8083 return false;
8084
8085 // Another wrinkle: Balance the stack from the emitter's point of view.
8086 // Execution will not reach here, as the last bytecode threw.
8087 return emit1(JSOP_POP);
8088 }
8089
8090 JSOp delOp = sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
8091 return emitElemOp(elemExpr, delOp);
8092 }
8093
emitDeleteExpression(ParseNode * node)8094 bool BytecodeEmitter::emitDeleteExpression(ParseNode* node) {
8095 MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteExpr));
8096 MOZ_ASSERT(node->isArity(PN_UNARY));
8097
8098 ParseNode* expression = node->pn_kid;
8099
8100 // If useless, just emit JSOP_TRUE; otherwise convert |delete <expr>| to
8101 // effectively |<expr>, true|.
8102 bool useful = false;
8103 if (!checkSideEffects(expression, &useful)) return false;
8104
8105 if (useful) {
8106 if (!emitTree(expression)) return false;
8107 if (!emit1(JSOP_POP)) return false;
8108 }
8109
8110 return emit1(JSOP_TRUE);
8111 }
8112
SelfHostedCallFunctionName(JSAtom * name,JSContext * cx)8113 static const char* SelfHostedCallFunctionName(JSAtom* name, JSContext* cx) {
8114 if (name == cx->names().callFunction) return "callFunction";
8115 if (name == cx->names().callContentFunction) return "callContentFunction";
8116 if (name == cx->names().constructContentFunction)
8117 return "constructContentFunction";
8118
8119 MOZ_CRASH("Unknown self-hosted call function name");
8120 }
8121
emitSelfHostedCallFunction(ParseNode * pn)8122 bool BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) {
8123 // Special-casing of callFunction to emit bytecode that directly
8124 // invokes the callee with the correct |this| object and arguments.
8125 // callFunction(fun, thisArg, arg0, arg1) thus becomes:
8126 // - emit lookup for fun
8127 // - emit lookup for thisArg
8128 // - emit lookups for arg0, arg1
8129 //
8130 // argc is set to the amount of actually emitted args and the
8131 // emitting of args below is disabled by setting emitArgs to false.
8132 ParseNode* pn2 = pn->pn_head;
8133 const char* errorName = SelfHostedCallFunctionName(pn2->name(), cx);
8134
8135 if (pn->pn_count < 3) {
8136 reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, "2", "s");
8137 return false;
8138 }
8139
8140 JSOp callOp = pn->getOp();
8141 if (callOp != JSOP_CALL) {
8142 reportError(pn, JSMSG_NOT_CONSTRUCTOR, errorName);
8143 return false;
8144 }
8145
8146 bool constructing = pn2->name() == cx->names().constructContentFunction;
8147 ParseNode* funNode = pn2->pn_next;
8148 if (constructing) {
8149 callOp = JSOP_NEW;
8150 } else if (funNode->getKind() == ParseNodeKind::Name &&
8151 funNode->name() == cx->names().std_Function_apply) {
8152 callOp = JSOP_FUNAPPLY;
8153 }
8154
8155 if (!emitTree(funNode)) return false;
8156
8157 #ifdef DEBUG
8158 if (emitterMode == BytecodeEmitter::SelfHosting &&
8159 pn2->name() == cx->names().callFunction) {
8160 if (!emit1(JSOP_DEBUGCHECKSELFHOSTED)) return false;
8161 }
8162 #endif
8163
8164 ParseNode* thisOrNewTarget = funNode->pn_next;
8165 if (constructing) {
8166 // Save off the new.target value, but here emit a proper |this| for a
8167 // constructing call.
8168 if (!emit1(JSOP_IS_CONSTRUCTING)) return false;
8169 } else {
8170 // It's |this|, emit it.
8171 if (!emitTree(thisOrNewTarget)) return false;
8172 }
8173
8174 for (ParseNode* argpn = thisOrNewTarget->pn_next; argpn;
8175 argpn = argpn->pn_next) {
8176 if (!emitTree(argpn)) return false;
8177 }
8178
8179 if (constructing) {
8180 if (!emitTree(thisOrNewTarget)) return false;
8181 }
8182
8183 uint32_t argc = pn->pn_count - 3;
8184 if (!emitCall(callOp, argc)) return false;
8185
8186 checkTypeSet(callOp);
8187 return true;
8188 }
8189
emitSelfHostedResumeGenerator(ParseNode * pn)8190 bool BytecodeEmitter::emitSelfHostedResumeGenerator(ParseNode* pn) {
8191 // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'return')
8192 if (pn->pn_count != 4) {
8193 reportError(pn, JSMSG_MORE_ARGS_NEEDED, "resumeGenerator", "1", "s");
8194 return false;
8195 }
8196
8197 ParseNode* funNode = pn->pn_head; // The resumeGenerator node.
8198
8199 ParseNode* genNode = funNode->pn_next;
8200 if (!emitTree(genNode)) return false;
8201
8202 ParseNode* valNode = genNode->pn_next;
8203 if (!emitTree(valNode)) return false;
8204
8205 ParseNode* kindNode = valNode->pn_next;
8206 MOZ_ASSERT(kindNode->isKind(ParseNodeKind::String));
8207 uint16_t operand = GeneratorObject::getResumeKind(cx, kindNode->pn_atom);
8208 MOZ_ASSERT(!kindNode->pn_next);
8209
8210 if (!emitCall(JSOP_RESUME, operand)) return false;
8211
8212 return true;
8213 }
8214
emitSelfHostedForceInterpreter()8215 bool BytecodeEmitter::emitSelfHostedForceInterpreter() {
8216 if (!emit1(JSOP_FORCEINTERPRETER)) return false;
8217 if (!emit1(JSOP_UNDEFINED)) return false;
8218 return true;
8219 }
8220
emitSelfHostedAllowContentIter(ParseNode * pn)8221 bool BytecodeEmitter::emitSelfHostedAllowContentIter(ParseNode* pn) {
8222 if (pn->pn_count != 2) {
8223 reportError(pn, JSMSG_MORE_ARGS_NEEDED, "allowContentIter", "1", "");
8224 return false;
8225 }
8226
8227 // We're just here as a sentinel. Pass the value through directly.
8228 return emitTree(pn->pn_head->pn_next);
8229 }
8230
emitSelfHostedDefineDataProperty(ParseNode * pn)8231 bool BytecodeEmitter::emitSelfHostedDefineDataProperty(ParseNode* pn) {
8232 // Only optimize when 3 arguments are passed (we use 4 to include |this|).
8233 MOZ_ASSERT(pn->pn_count == 4);
8234
8235 ParseNode* funNode = pn->pn_head; // The _DefineDataProperty node.
8236
8237 ParseNode* objNode = funNode->pn_next;
8238 if (!emitTree(objNode)) return false;
8239
8240 ParseNode* idNode = objNode->pn_next;
8241 if (!emitTree(idNode)) return false;
8242
8243 ParseNode* valNode = idNode->pn_next;
8244 if (!emitTree(valNode)) return false;
8245
8246 // This will leave the object on the stack instead of pushing |undefined|,
8247 // but that's fine because the self-hosted code doesn't use the return
8248 // value.
8249 return emit1(JSOP_INITELEM);
8250 }
8251
emitSelfHostedHasOwn(ParseNode * pn)8252 bool BytecodeEmitter::emitSelfHostedHasOwn(ParseNode* pn) {
8253 if (pn->pn_count != 3) {
8254 reportError(pn, JSMSG_MORE_ARGS_NEEDED, "hasOwn", "2", "");
8255 return false;
8256 }
8257
8258 ParseNode* funNode = pn->pn_head; // The hasOwn node.
8259
8260 ParseNode* idNode = funNode->pn_next;
8261 if (!emitTree(idNode)) return false;
8262
8263 ParseNode* objNode = idNode->pn_next;
8264 if (!emitTree(objNode)) return false;
8265
8266 return emit1(JSOP_HASOWN);
8267 }
8268
emitSelfHostedGetPropertySuper(ParseNode * pn)8269 bool BytecodeEmitter::emitSelfHostedGetPropertySuper(ParseNode* pn) {
8270 if (pn->pn_count != 4) {
8271 reportError(pn, JSMSG_MORE_ARGS_NEEDED, "getPropertySuper", "3", "");
8272 return false;
8273 }
8274
8275 ParseNode* funNode = pn->pn_head; // The getPropertySuper node.
8276
8277 ParseNode* objNode = funNode->pn_next;
8278 ParseNode* idNode = objNode->pn_next;
8279 ParseNode* receiverNode = idNode->pn_next;
8280
8281 if (!emitTree(idNode)) return false;
8282
8283 if (!emitTree(receiverNode)) return false;
8284
8285 if (!emitTree(objNode)) return false;
8286
8287 return emitElemOpBase(JSOP_GETELEM_SUPER);
8288 }
8289
isRestParameter(ParseNode * pn)8290 bool BytecodeEmitter::isRestParameter(ParseNode* pn) {
8291 if (!sc->isFunctionBox()) return false;
8292
8293 FunctionBox* funbox = sc->asFunctionBox();
8294 RootedFunction fun(cx, funbox->function());
8295 if (!funbox->hasRest()) return false;
8296
8297 if (!pn->isKind(ParseNodeKind::Name)) {
8298 if (emitterMode == BytecodeEmitter::SelfHosting &&
8299 pn->isKind(ParseNodeKind::Call)) {
8300 ParseNode* pn2 = pn->pn_head;
8301 if (pn2->getKind() == ParseNodeKind::Name &&
8302 pn2->name() == cx->names().allowContentIter) {
8303 return isRestParameter(pn2->pn_next);
8304 }
8305 }
8306 return false;
8307 }
8308
8309 JSAtom* name = pn->name();
8310 Maybe<NameLocation> paramLoc = locationOfNameBoundInFunctionScope(name);
8311 if (paramLoc && lookupName(name) == *paramLoc) {
8312 FunctionScope::Data* bindings = funbox->functionScopeBindings();
8313 if (bindings->nonPositionalFormalStart > 0) {
8314 // |paramName| can be nullptr when the rest destructuring syntax is
8315 // used: `function f(...[]) {}`.
8316 JSAtom* paramName =
8317 bindings->names[bindings->nonPositionalFormalStart - 1].name();
8318 return paramName && name == paramName;
8319 }
8320 }
8321
8322 return false;
8323 }
8324
emitCallee(ParseNode * callee,ParseNode * call,bool * callop)8325 bool BytecodeEmitter::emitCallee(ParseNode* callee, ParseNode* call,
8326 bool* callop) {
8327 switch (callee->getKind()) {
8328 case ParseNodeKind::Name:
8329 if (!emitGetName(callee, *callop)) return false;
8330 break;
8331 case ParseNodeKind::Dot:
8332 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
8333 if (callee->as<PropertyAccess>().isSuper()) {
8334 if (!emitSuperPropOp(callee, JSOP_GETPROP_SUPER,
8335 /* isCall = */ *callop))
8336 return false;
8337 } else {
8338 if (!emitPropOp(callee, *callop ? JSOP_CALLPROP : JSOP_GETPROP))
8339 return false;
8340 }
8341
8342 break;
8343 case ParseNodeKind::Elem:
8344 MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
8345 if (callee->as<PropertyByValue>().isSuper()) {
8346 if (!emitSuperElemOp(callee, JSOP_GETELEM_SUPER,
8347 /* isCall = */ *callop))
8348 return false;
8349 } else {
8350 if (!emitElemOp(callee, *callop ? JSOP_CALLELEM : JSOP_GETELEM))
8351 return false;
8352 if (*callop) {
8353 if (!emit1(JSOP_SWAP)) return false;
8354 }
8355 }
8356
8357 break;
8358 case ParseNodeKind::Function:
8359 /*
8360 * Top level lambdas which are immediately invoked should be
8361 * treated as only running once. Every time they execute we will
8362 * create new types and scripts for their contents, to increase
8363 * the quality of type information within them and enable more
8364 * backend optimizations. Note that this does not depend on the
8365 * lambda being invoked at most once (it may be named or be
8366 * accessed via foo.caller indirection), as multiple executions
8367 * will just cause the inner scripts to be repeatedly cloned.
8368 */
8369 MOZ_ASSERT(!emittingRunOnceLambda);
8370 if (checkRunOnceContext()) {
8371 emittingRunOnceLambda = true;
8372 if (!emitTree(callee)) return false;
8373 emittingRunOnceLambda = false;
8374 } else {
8375 if (!emitTree(callee)) return false;
8376 }
8377 *callop = false;
8378 break;
8379 case ParseNodeKind::SuperBase:
8380 MOZ_ASSERT(call->isKind(ParseNodeKind::SuperCall));
8381 MOZ_ASSERT(parser.isSuperBase(callee));
8382 if (!emit1(JSOP_SUPERFUN)) return false;
8383 break;
8384 default:
8385 if (!emitTree(callee)) return false;
8386 *callop = false; /* trigger JSOP_UNDEFINED after */
8387 break;
8388 }
8389
8390 return true;
8391 }
8392
emitPipeline(ParseNode * pn)8393 bool BytecodeEmitter::emitPipeline(ParseNode* pn) {
8394 MOZ_ASSERT(pn->isArity(PN_LIST));
8395 MOZ_ASSERT(pn->pn_count >= 2);
8396
8397 if (!emitTree(pn->pn_head)) return false;
8398
8399 ParseNode* callee = pn->pn_head->pn_next;
8400
8401 do {
8402 bool callop = true;
8403 if (!emitCallee(callee, pn, &callop)) return false;
8404
8405 // Emit room for |this|
8406 if (!callop) {
8407 if (!emit1(JSOP_UNDEFINED)) return false;
8408 }
8409
8410 if (!emit2(JSOP_PICK, 2)) return false;
8411
8412 if (!emitCall(JSOP_CALL, 1, pn)) return false;
8413
8414 checkTypeSet(JSOP_CALL);
8415 } while ((callee = callee->pn_next));
8416
8417 return true;
8418 }
8419
emitCallOrNew(ParseNode * pn,ValueUsage valueUsage)8420 bool BytecodeEmitter::emitCallOrNew(
8421 ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */) {
8422 bool callop = pn->isKind(ParseNodeKind::Call) ||
8423 pn->isKind(ParseNodeKind::TaggedTemplate);
8424 /*
8425 * Emit callable invocation or operator new (constructor call) code.
8426 * First, emit code for the left operand to evaluate the callable or
8427 * constructable object expression.
8428 *
8429 * For operator new, we emit JSOP_GETPROP instead of JSOP_CALLPROP, etc.
8430 * This is necessary to interpose the lambda-initialized method read
8431 * barrier -- see the code in jsinterp.cpp for JSOP_LAMBDA followed by
8432 * JSOP_{SET,INIT}PROP.
8433 *
8434 * Then (or in a call case that has no explicit reference-base
8435 * object) we emit JSOP_UNDEFINED to produce the undefined |this|
8436 * value required for calls (which non-strict mode functions
8437 * will box into the global object).
8438 */
8439 uint32_t argc = pn->pn_count - 1;
8440
8441 if (argc >= ARGC_LIMIT) {
8442 parser.reportError(callop ? JSMSG_TOO_MANY_FUN_ARGS
8443 : JSMSG_TOO_MANY_CON_ARGS);
8444 return false;
8445 }
8446
8447 ParseNode* pn2 = pn->pn_head;
8448 bool spread = JOF_OPTYPE(pn->getOp()) == JOF_BYTE;
8449
8450 if (pn2->isKind(ParseNodeKind::Name) &&
8451 emitterMode == BytecodeEmitter::SelfHosting && !spread) {
8452 // Calls to "forceInterpreter", "callFunction",
8453 // "callContentFunction", or "resumeGenerator" in self-hosted
8454 // code generate inline bytecode.
8455 if (pn2->name() == cx->names().callFunction ||
8456 pn2->name() == cx->names().callContentFunction ||
8457 pn2->name() == cx->names().constructContentFunction) {
8458 return emitSelfHostedCallFunction(pn);
8459 }
8460 if (pn2->name() == cx->names().resumeGenerator)
8461 return emitSelfHostedResumeGenerator(pn);
8462 if (pn2->name() == cx->names().forceInterpreter)
8463 return emitSelfHostedForceInterpreter();
8464 if (pn2->name() == cx->names().allowContentIter)
8465 return emitSelfHostedAllowContentIter(pn);
8466 if (pn2->name() == cx->names().defineDataPropertyIntrinsic &&
8467 pn->pn_count == 4)
8468 return emitSelfHostedDefineDataProperty(pn);
8469 if (pn2->name() == cx->names().hasOwn) return emitSelfHostedHasOwn(pn);
8470 if (pn2->name() == cx->names().getPropertySuper)
8471 return emitSelfHostedGetPropertySuper(pn);
8472 // Fall through
8473 }
8474
8475 if (!emitCallee(pn2, pn, &callop)) return false;
8476
8477 bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
8478 pn->getOp() == JSOP_SUPERCALL ||
8479 pn->getOp() == JSOP_SPREADSUPERCALL;
8480
8481 // Emit room for |this|.
8482 if (!callop) {
8483 if (isNewOp) {
8484 if (!emit1(JSOP_IS_CONSTRUCTING)) return false;
8485 } else {
8486 if (!emit1(JSOP_UNDEFINED)) return false;
8487 }
8488 }
8489
8490 /*
8491 * Emit code for each argument in order, then emit the JSOP_*CALL or
8492 * JSOP_NEW bytecode with a two-byte immediate telling how many args
8493 * were pushed on the operand stack.
8494 */
8495 if (!spread) {
8496 for (ParseNode* pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
8497 if (!emitTree(pn3)) return false;
8498 }
8499
8500 if (isNewOp) {
8501 if (pn->isKind(ParseNodeKind::SuperCall)) {
8502 if (!emit1(JSOP_NEWTARGET)) return false;
8503 } else {
8504 // Repush the callee as new.target
8505 if (!emitDupAt(argc + 1)) return false;
8506 }
8507 }
8508 } else {
8509 ParseNode* args = pn2->pn_next;
8510 bool emitOptCode = (argc == 1) && isRestParameter(args->pn_kid);
8511 IfThenElseEmitter ifNotOptimizable(this);
8512
8513 if (emitOptCode) {
8514 // Emit a preparation code to optimize the spread call with a rest
8515 // parameter:
8516 //
8517 // function f(...args) {
8518 // g(...args);
8519 // }
8520 //
8521 // If the spread operand is a rest parameter and it's optimizable
8522 // array, skip spread operation and pass it directly to spread call
8523 // operation. See the comment in OptimizeSpreadCall in
8524 // Interpreter.cpp for the optimizable conditons.
8525
8526 if (!emitTree(args->pn_kid)) return false;
8527
8528 if (!emit1(JSOP_OPTIMIZE_SPREADCALL)) return false;
8529
8530 if (!emit1(JSOP_NOT)) return false;
8531
8532 if (!ifNotOptimizable.emitIf()) return false;
8533
8534 if (!emit1(JSOP_POP)) return false;
8535 }
8536
8537 if (!emitArray(args, argc)) return false;
8538
8539 if (emitOptCode) {
8540 if (!ifNotOptimizable.emitEnd()) return false;
8541 }
8542
8543 if (isNewOp) {
8544 if (pn->isKind(ParseNodeKind::SuperCall)) {
8545 if (!emit1(JSOP_NEWTARGET)) return false;
8546 } else {
8547 if (!emitDupAt(2)) return false;
8548 }
8549 }
8550 }
8551
8552 if (!spread) {
8553 if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
8554 if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn)) return false;
8555 checkTypeSet(JSOP_CALL_IGNORES_RV);
8556 } else {
8557 if (!emitCall(pn->getOp(), argc, pn)) return false;
8558 checkTypeSet(pn->getOp());
8559 }
8560 } else {
8561 if (!emit1(pn->getOp())) return false;
8562 checkTypeSet(pn->getOp());
8563 }
8564 if (pn->isOp(JSOP_EVAL) || pn->isOp(JSOP_STRICTEVAL) ||
8565 pn->isOp(JSOP_SPREADEVAL) || pn->isOp(JSOP_STRICTSPREADEVAL)) {
8566 uint32_t lineNum = parser.tokenStream().srcCoords.lineNum(pn->pn_pos.begin);
8567 if (!emitUint32Operand(JSOP_LINENO, lineNum)) return false;
8568 }
8569
8570 return true;
8571 }
8572
8573 static const JSOp ParseNodeKindToJSOp[] = {
8574 // JSOP_NOP is for pipeline operator which does not emit its own JSOp
8575 // but has highest precedence in binary operators
8576 JSOP_NOP, JSOP_OR, JSOP_AND, JSOP_BITOR, JSOP_BITXOR,
8577 JSOP_BITAND, JSOP_STRICTEQ, JSOP_EQ, JSOP_STRICTNE, JSOP_NE,
8578 JSOP_LT, JSOP_LE, JSOP_GT, JSOP_GE, JSOP_INSTANCEOF,
8579 JSOP_IN, JSOP_LSH, JSOP_RSH, JSOP_URSH, JSOP_ADD,
8580 JSOP_SUB, JSOP_MUL, JSOP_DIV, JSOP_MOD, JSOP_POW};
8581
BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk)8582 static inline JSOp BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk) {
8583 MOZ_ASSERT(pnk >= ParseNodeKind::BinOpFirst);
8584 MOZ_ASSERT(pnk <= ParseNodeKind::BinOpLast);
8585 return ParseNodeKindToJSOp[size_t(pnk) - size_t(ParseNodeKind::BinOpFirst)];
8586 }
8587
emitRightAssociative(ParseNode * pn)8588 bool BytecodeEmitter::emitRightAssociative(ParseNode* pn) {
8589 // ** is the only right-associative operator.
8590 MOZ_ASSERT(pn->isKind(ParseNodeKind::Pow));
8591 MOZ_ASSERT(pn->isArity(PN_LIST));
8592
8593 // Right-associative operator chain.
8594 for (ParseNode* subexpr = pn->pn_head; subexpr; subexpr = subexpr->pn_next) {
8595 if (!emitTree(subexpr)) return false;
8596 }
8597 for (uint32_t i = 0; i < pn->pn_count - 1; i++) {
8598 if (!emit1(JSOP_POW)) return false;
8599 }
8600 return true;
8601 }
8602
emitLeftAssociative(ParseNode * pn)8603 bool BytecodeEmitter::emitLeftAssociative(ParseNode* pn) {
8604 MOZ_ASSERT(pn->isArity(PN_LIST));
8605
8606 // Left-associative operator chain.
8607 if (!emitTree(pn->pn_head)) return false;
8608 JSOp op = BinaryOpParseNodeKindToJSOp(pn->getKind());
8609 ParseNode* nextExpr = pn->pn_head->pn_next;
8610 do {
8611 if (!emitTree(nextExpr)) return false;
8612 if (!emit1(op)) return false;
8613 } while ((nextExpr = nextExpr->pn_next));
8614 return true;
8615 }
8616
emitLogical(ParseNode * pn)8617 bool BytecodeEmitter::emitLogical(ParseNode* pn) {
8618 MOZ_ASSERT(pn->isArity(PN_LIST));
8619 MOZ_ASSERT(pn->isKind(ParseNodeKind::Or) || pn->isKind(ParseNodeKind::And));
8620
8621 /*
8622 * JSOP_OR converts the operand on the stack to boolean, leaves the original
8623 * value on the stack and jumps if true; otherwise it falls into the next
8624 * bytecode, which pops the left operand and then evaluates the right operand.
8625 * The jump goes around the right operand evaluation.
8626 *
8627 * JSOP_AND converts the operand on the stack to boolean and jumps if false;
8628 * otherwise it falls into the right operand's bytecode.
8629 */
8630
8631 TDZCheckCache tdzCache(this);
8632
8633 /* Left-associative operator chain: avoid too much recursion. */
8634 ParseNode* pn2 = pn->pn_head;
8635 if (!emitTree(pn2)) return false;
8636 JSOp op = pn->isKind(ParseNodeKind::Or) ? JSOP_OR : JSOP_AND;
8637 JumpList jump;
8638 if (!emitJump(op, &jump)) return false;
8639 if (!emit1(JSOP_POP)) return false;
8640
8641 /* Emit nodes between the head and the tail. */
8642 while ((pn2 = pn2->pn_next)->pn_next) {
8643 if (!emitTree(pn2)) return false;
8644 if (!emitJump(op, &jump)) return false;
8645 if (!emit1(JSOP_POP)) return false;
8646 }
8647 if (!emitTree(pn2)) return false;
8648
8649 if (!emitJumpTargetAndPatch(jump)) return false;
8650 return true;
8651 }
8652
emitSequenceExpr(ParseNode * pn,ValueUsage valueUsage)8653 bool BytecodeEmitter::emitSequenceExpr(
8654 ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */) {
8655 for (ParseNode* child = pn->pn_head;; child = child->pn_next) {
8656 if (!updateSourceCoordNotes(child->pn_pos.begin)) return false;
8657 if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage))
8658 return false;
8659 if (!child->pn_next) break;
8660 if (!emit1(JSOP_POP)) return false;
8661 }
8662 return true;
8663 }
8664
8665 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8666 // the comment on emitSwitch.
emitIncOrDec(ParseNode * pn)8667 MOZ_NEVER_INLINE bool BytecodeEmitter::emitIncOrDec(ParseNode* pn) {
8668 switch (pn->pn_kid->getKind()) {
8669 case ParseNodeKind::Dot:
8670 return emitPropIncDec(pn);
8671 case ParseNodeKind::Elem:
8672 return emitElemIncDec(pn);
8673 case ParseNodeKind::Call:
8674 return emitCallIncDec(pn);
8675 default:
8676 return emitNameIncDec(pn);
8677 }
8678 }
8679
8680 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8681 // the comment on emitSwitch.
emitLabeledStatement(const LabeledStatement * pn)8682 MOZ_NEVER_INLINE bool BytecodeEmitter::emitLabeledStatement(
8683 const LabeledStatement* pn) {
8684 /*
8685 * Emit a JSOP_LABEL instruction. The argument is the offset to the statement
8686 * following the labeled statement.
8687 */
8688 uint32_t index;
8689 if (!makeAtomIndex(pn->label(), &index)) return false;
8690
8691 JumpList top;
8692 if (!emitJump(JSOP_LABEL, &top)) return false;
8693
8694 /* Emit code for the labeled statement. */
8695 LabelControl controlInfo(this, pn->label(), offset());
8696
8697 if (!emitTree(pn->statement())) return false;
8698
8699 /* Patch the JSOP_LABEL offset. */
8700 JumpTarget brk{lastNonJumpTargetOffset()};
8701 patchJumpsToTarget(top, brk);
8702
8703 if (!controlInfo.patchBreaks(this)) return false;
8704
8705 return true;
8706 }
8707
emitConditionalExpression(ConditionalExpression & conditional,ValueUsage valueUsage)8708 bool BytecodeEmitter::emitConditionalExpression(
8709 ConditionalExpression& conditional,
8710 ValueUsage valueUsage /* = ValueUsage::WantValue */) {
8711 /* Emit the condition, then branch if false to the else part. */
8712 if (!emitTree(&conditional.condition())) return false;
8713
8714 IfThenElseEmitter ifThenElse(this);
8715 if (!ifThenElse.emitCond()) return false;
8716
8717 if (!emitTreeInBranch(&conditional.thenExpression(), valueUsage))
8718 return false;
8719
8720 if (!ifThenElse.emitElse()) return false;
8721
8722 if (!emitTreeInBranch(&conditional.elseExpression(), valueUsage))
8723 return false;
8724
8725 if (!ifThenElse.emitEnd()) return false;
8726 MOZ_ASSERT(ifThenElse.pushed() == 1);
8727
8728 return true;
8729 }
8730
emitPropertyList(ParseNode * pn,MutableHandlePlainObject objp,PropListType type)8731 bool BytecodeEmitter::emitPropertyList(ParseNode* pn,
8732 MutableHandlePlainObject objp,
8733 PropListType type) {
8734 for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) {
8735 if (!updateSourceCoordNotes(propdef->pn_pos.begin)) return false;
8736
8737 // Handle __proto__: v specially because *only* this form, and no other
8738 // involving "__proto__", performs [[Prototype]] mutation.
8739 if (propdef->isKind(ParseNodeKind::MutateProto)) {
8740 MOZ_ASSERT(type == ObjectLiteral);
8741 if (!emitTree(propdef->pn_kid)) return false;
8742 objp.set(nullptr);
8743 if (!emit1(JSOP_MUTATEPROTO)) return false;
8744 continue;
8745 }
8746
8747 if (propdef->isKind(ParseNodeKind::Spread)) {
8748 MOZ_ASSERT(type == ObjectLiteral);
8749
8750 if (!emit1(JSOP_DUP)) return false;
8751
8752 if (!emitTree(propdef->pn_kid)) return false;
8753
8754 if (!emitCopyDataProperties(CopyOption::Unfiltered)) return false;
8755
8756 objp.set(nullptr);
8757 continue;
8758 }
8759
8760 bool extraPop = false;
8761 if (type == ClassBody && propdef->as<ClassMethod>().isStatic()) {
8762 extraPop = true;
8763 if (!emit1(JSOP_DUP2)) return false;
8764 if (!emit1(JSOP_POP)) return false;
8765 }
8766
8767 /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
8768 ParseNode* key = propdef->pn_left;
8769 bool isIndex = false;
8770 if (key->isKind(ParseNodeKind::Number)) {
8771 if (!emitNumberOp(key->pn_dval)) return false;
8772 isIndex = true;
8773 } else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
8774 key->isKind(ParseNodeKind::String)) {
8775 // EmitClass took care of constructor already.
8776 if (type == ClassBody && key->pn_atom == cx->names().constructor &&
8777 !propdef->as<ClassMethod>().isStatic()) {
8778 continue;
8779 }
8780 } else {
8781 if (!emitComputedPropertyName(key)) return false;
8782 isIndex = true;
8783 }
8784
8785 /* Emit code for the property initializer. */
8786 if (!emitTree(propdef->pn_right)) return false;
8787
8788 JSOp op = propdef->getOp();
8789 MOZ_ASSERT(op == JSOP_INITPROP || op == JSOP_INITPROP_GETTER ||
8790 op == JSOP_INITPROP_SETTER);
8791
8792 FunctionPrefixKind prefixKind = op == JSOP_INITPROP_GETTER
8793 ? FunctionPrefixKind::Get
8794 : op == JSOP_INITPROP_SETTER
8795 ? FunctionPrefixKind::Set
8796 : FunctionPrefixKind::None;
8797
8798 if (op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER)
8799 objp.set(nullptr);
8800
8801 if (propdef->pn_right->isKind(ParseNodeKind::Function) &&
8802 propdef->pn_right->pn_funbox->needsHomeObject()) {
8803 MOZ_ASSERT(
8804 propdef->pn_right->pn_funbox->function()->allowSuperProperty());
8805 bool isAsync = propdef->pn_right->pn_funbox->isAsync();
8806 if (isAsync) {
8807 if (!emit1(JSOP_SWAP)) return false;
8808 }
8809 if (!emit2(JSOP_INITHOMEOBJECT, isIndex + isAsync)) return false;
8810 if (isAsync) {
8811 if (!emit1(JSOP_POP)) return false;
8812 }
8813 }
8814
8815 // Class methods are not enumerable.
8816 if (type == ClassBody) {
8817 switch (op) {
8818 case JSOP_INITPROP:
8819 op = JSOP_INITHIDDENPROP;
8820 break;
8821 case JSOP_INITPROP_GETTER:
8822 op = JSOP_INITHIDDENPROP_GETTER;
8823 break;
8824 case JSOP_INITPROP_SETTER:
8825 op = JSOP_INITHIDDENPROP_SETTER;
8826 break;
8827 default:
8828 MOZ_CRASH("Invalid op");
8829 }
8830 }
8831
8832 if (isIndex) {
8833 objp.set(nullptr);
8834 switch (op) {
8835 case JSOP_INITPROP:
8836 op = JSOP_INITELEM;
8837 break;
8838 case JSOP_INITHIDDENPROP:
8839 op = JSOP_INITHIDDENELEM;
8840 break;
8841 case JSOP_INITPROP_GETTER:
8842 op = JSOP_INITELEM_GETTER;
8843 break;
8844 case JSOP_INITHIDDENPROP_GETTER:
8845 op = JSOP_INITHIDDENELEM_GETTER;
8846 break;
8847 case JSOP_INITPROP_SETTER:
8848 op = JSOP_INITELEM_SETTER;
8849 break;
8850 case JSOP_INITHIDDENPROP_SETTER:
8851 op = JSOP_INITHIDDENELEM_SETTER;
8852 break;
8853 default:
8854 MOZ_CRASH("Invalid op");
8855 }
8856 if (propdef->pn_right->isDirectRHSAnonFunction()) {
8857 if (!emitDupAt(1)) return false;
8858 if (!emit2(JSOP_SETFUNNAME, uint8_t(prefixKind))) return false;
8859 }
8860 if (!emit1(op)) return false;
8861 } else {
8862 MOZ_ASSERT(key->isKind(ParseNodeKind::ObjectPropertyName) ||
8863 key->isKind(ParseNodeKind::String));
8864
8865 uint32_t index;
8866 if (!makeAtomIndex(key->pn_atom, &index)) return false;
8867
8868 if (objp) {
8869 MOZ_ASSERT(type == ObjectLiteral);
8870 MOZ_ASSERT(!IsHiddenInitOp(op));
8871 MOZ_ASSERT(!objp->inDictionaryMode());
8872 Rooted<jsid> id(cx, AtomToId(key->pn_atom));
8873 if (!NativeDefineDataProperty(cx, objp, id, UndefinedHandleValue,
8874 JSPROP_ENUMERATE)) {
8875 return false;
8876 }
8877 if (objp->inDictionaryMode()) objp.set(nullptr);
8878 }
8879
8880 if (propdef->pn_right->isDirectRHSAnonFunction()) {
8881 RootedAtom keyName(cx, key->pn_atom);
8882 if (!setOrEmitSetFunName(propdef->pn_right, keyName, prefixKind))
8883 return false;
8884 }
8885 if (!emitIndex32(op, index)) return false;
8886 }
8887
8888 if (extraPop) {
8889 if (!emit1(JSOP_POP)) return false;
8890 }
8891 }
8892 return true;
8893 }
8894
8895 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
8896 // the comment on emitSwitch.
emitObject(ParseNode * pn)8897 MOZ_NEVER_INLINE bool BytecodeEmitter::emitObject(ParseNode* pn) {
8898 if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && checkSingletonContext())
8899 return emitSingletonInitialiser(pn);
8900
8901 /*
8902 * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
8903 * a new object and defining (in source order) each property on the object
8904 * (or mutating the object's [[Prototype]], in the case of __proto__).
8905 */
8906 ptrdiff_t offset = this->offset();
8907 if (!emitNewInit(JSProto_Object)) return false;
8908
8909 // Try to construct the shape of the object as we go, so we can emit a
8910 // JSOP_NEWOBJECT with the final shape instead.
8911 // In the case of computed property names and indices, we cannot fix the
8912 // shape at bytecode compile time. When the shape cannot be determined,
8913 // |obj| is nulled out.
8914
8915 // No need to do any guessing for the object kind, since we know the upper
8916 // bound of how many properties we plan to have.
8917 gc::AllocKind kind = gc::GetGCObjectKind(pn->pn_count);
8918 RootedPlainObject obj(
8919 cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
8920 if (!obj) return false;
8921
8922 if (!emitPropertyList(pn, &obj, ObjectLiteral)) return false;
8923
8924 if (obj) {
8925 // The object survived and has a predictable shape: update the original
8926 // bytecode.
8927 if (!replaceNewInitWithNewObject(obj, offset)) return false;
8928 }
8929
8930 return true;
8931 }
8932
replaceNewInitWithNewObject(JSObject * obj,ptrdiff_t offset)8933 bool BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj,
8934 ptrdiff_t offset) {
8935 ObjectBox* objbox = parser.newObjectBox(obj);
8936 if (!objbox) return false;
8937
8938 static_assert(
8939 JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
8940 "newinit and newobject must have equal length to edit in-place");
8941
8942 uint32_t index = objectList.add(objbox);
8943 jsbytecode* code = this->code(offset);
8944
8945 MOZ_ASSERT(code[0] == JSOP_NEWINIT);
8946 code[0] = JSOP_NEWOBJECT;
8947 SET_UINT32(code, index);
8948
8949 return true;
8950 }
8951
emitArrayLiteral(ParseNode * pn)8952 bool BytecodeEmitter::emitArrayLiteral(ParseNode* pn) {
8953 if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head) {
8954 if (checkSingletonContext()) {
8955 // Bake in the object entirely if it will only be created once.
8956 return emitSingletonInitialiser(pn);
8957 }
8958
8959 // If the array consists entirely of primitive values, make a
8960 // template object with copy on write elements that can be reused
8961 // every time the initializer executes. Don't do this if the array is
8962 // small: copying the elements lazily is not worth it in that case.
8963 static const size_t MinElementsForCopyOnWrite = 5;
8964 if (emitterMode != BytecodeEmitter::SelfHosting &&
8965 pn->pn_count >= MinElementsForCopyOnWrite) {
8966 RootedValue value(cx);
8967 if (!pn->getConstantValue(cx, ParseNode::ForCopyOnWriteArray, &value))
8968 return false;
8969 if (!value.isMagic(JS_GENERIC_MAGIC)) {
8970 // Note: the group of the template object might not yet reflect
8971 // that the object has copy on write elements. When the
8972 // interpreter or JIT compiler fetches the template, it should
8973 // use ObjectGroup::getOrFixupCopyOnWriteObject to make sure the
8974 // group for the template is accurate. We don't do this here as we
8975 // want to use ObjectGroup::allocationSiteGroup, which requires a
8976 // finished script.
8977 JSObject* obj = &value.toObject();
8978 MOZ_ASSERT(obj->is<ArrayObject>() &&
8979 obj->as<ArrayObject>().denseElementsAreCopyOnWrite());
8980
8981 ObjectBox* objbox = parser.newObjectBox(obj);
8982 if (!objbox) return false;
8983
8984 return emitObjectOp(objbox, JSOP_NEWARRAY_COPYONWRITE);
8985 }
8986 }
8987 }
8988
8989 return emitArray(pn->pn_head, pn->pn_count);
8990 }
8991
emitArray(ParseNode * pn,uint32_t count)8992 bool BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count) {
8993 /*
8994 * Emit code for [a, b, c] that is equivalent to constructing a new
8995 * array and in source order evaluating each element value and adding
8996 * it to the array, without invoking latent setters. We use the
8997 * JSOP_NEWINIT and JSOP_INITELEM_ARRAY bytecodes to ignore setters and
8998 * to avoid dup'ing and popping the array as each element is added, as
8999 * JSOP_SETELEM/JSOP_SETPROP would do.
9000 */
9001
9002 uint32_t nspread = 0;
9003 for (ParseNode* elt = pn; elt; elt = elt->pn_next) {
9004 if (elt->isKind(ParseNodeKind::Spread)) nspread++;
9005 }
9006
9007 // Array literal's length is limited to NELEMENTS_LIMIT in parser.
9008 static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT <= INT32_MAX,
9009 "array literals' maximum length must not exceed limits "
9010 "required by BaselineCompiler::emit_JSOP_NEWARRAY, "
9011 "BaselineCompiler::emit_JSOP_INITELEM_ARRAY, "
9012 "and DoSetElemFallback's handling of JSOP_INITELEM_ARRAY");
9013 MOZ_ASSERT(count >= nspread);
9014 MOZ_ASSERT(count <= NativeObject::MAX_DENSE_ELEMENTS_COUNT,
9015 "the parser must throw an error if the array exceeds maximum "
9016 "length");
9017
9018 // For arrays with spread, this is a very pessimistic allocation, the
9019 // minimum possible final size.
9020 if (!emitUint32Operand(JSOP_NEWARRAY, count - nspread)) // ARRAY
9021 return false;
9022
9023 ParseNode* pn2 = pn;
9024 uint32_t index;
9025 bool afterSpread = false;
9026 for (index = 0; pn2; index++, pn2 = pn2->pn_next) {
9027 if (!afterSpread && pn2->isKind(ParseNodeKind::Spread)) {
9028 afterSpread = true;
9029 if (!emitNumberOp(index)) // ARRAY INDEX
9030 return false;
9031 }
9032 if (!updateSourceCoordNotes(pn2->pn_pos.begin)) return false;
9033
9034 bool allowSelfHostedIter = false;
9035 if (pn2->isKind(ParseNodeKind::Elision)) {
9036 if (!emit1(JSOP_HOLE)) return false;
9037 } else {
9038 ParseNode* expr;
9039 if (pn2->isKind(ParseNodeKind::Spread)) {
9040 expr = pn2->pn_kid;
9041
9042 if (emitterMode == BytecodeEmitter::SelfHosting &&
9043 expr->isKind(ParseNodeKind::Call) &&
9044 expr->pn_head->name() == cx->names().allowContentIter) {
9045 allowSelfHostedIter = true;
9046 }
9047 } else {
9048 expr = pn2;
9049 }
9050 if (!emitTree(expr)) // ARRAY INDEX? VALUE
9051 return false;
9052 }
9053 if (pn2->isKind(ParseNodeKind::Spread)) {
9054 if (!emitIterator()) // ARRAY INDEX NEXT ITER
9055 return false;
9056 if (!emit2(JSOP_PICK, 3)) // INDEX NEXT ITER ARRAY
9057 return false;
9058 if (!emit2(JSOP_PICK, 3)) // NEXT ITER ARRAY INDEX
9059 return false;
9060 if (!emitSpread(allowSelfHostedIter)) // ARRAY INDEX
9061 return false;
9062 } else if (afterSpread) {
9063 if (!emit1(JSOP_INITELEM_INC)) return false;
9064 } else {
9065 if (!emitUint32Operand(JSOP_INITELEM_ARRAY, index)) return false;
9066 }
9067 }
9068 MOZ_ASSERT(index == count);
9069 if (afterSpread) {
9070 if (!emit1(JSOP_POP)) // ARRAY
9071 return false;
9072 }
9073 return true;
9074 }
9075
UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk)9076 static inline JSOp UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk) {
9077 switch (pnk) {
9078 case ParseNodeKind::Throw:
9079 return JSOP_THROW;
9080 case ParseNodeKind::Void:
9081 return JSOP_VOID;
9082 case ParseNodeKind::Not:
9083 return JSOP_NOT;
9084 case ParseNodeKind::BitNot:
9085 return JSOP_BITNOT;
9086 case ParseNodeKind::Pos:
9087 return JSOP_POS;
9088 case ParseNodeKind::Neg:
9089 return JSOP_NEG;
9090 default:
9091 MOZ_CRASH("unexpected unary op");
9092 }
9093 }
9094
emitUnary(ParseNode * pn)9095 bool BytecodeEmitter::emitUnary(ParseNode* pn) {
9096 if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false;
9097 if (!emitTree(pn->pn_kid)) return false;
9098 return emit1(UnaryOpParseNodeKindToJSOp(pn->getKind()));
9099 }
9100
emitTypeof(ParseNode * node,JSOp op)9101 bool BytecodeEmitter::emitTypeof(ParseNode* node, JSOp op) {
9102 MOZ_ASSERT(op == JSOP_TYPEOF || op == JSOP_TYPEOFEXPR);
9103
9104 if (!updateSourceCoordNotes(node->pn_pos.begin)) return false;
9105
9106 if (!emitTree(node->pn_kid)) return false;
9107
9108 return emit1(op);
9109 }
9110
emitFunctionFormalParametersAndBody(ParseNode * pn)9111 bool BytecodeEmitter::emitFunctionFormalParametersAndBody(ParseNode* pn) {
9112 MOZ_ASSERT(pn->isKind(ParseNodeKind::ParamsBody));
9113
9114 ParseNode* funBody = pn->last();
9115 FunctionBox* funbox = sc->asFunctionBox();
9116
9117 TDZCheckCache tdzCache(this);
9118
9119 if (funbox->hasParameterExprs) {
9120 EmitterScope funEmitterScope(this);
9121 if (!funEmitterScope.enterFunction(this, funbox)) return false;
9122
9123 if (!emitInitializeFunctionSpecialNames()) return false;
9124
9125 if (!emitFunctionFormalParameters(pn)) return false;
9126
9127 {
9128 Maybe<EmitterScope> extraVarEmitterScope;
9129
9130 if (funbox->hasExtraBodyVarScope()) {
9131 extraVarEmitterScope.emplace(this);
9132 if (!extraVarEmitterScope->enterFunctionExtraBodyVar(this, funbox))
9133 return false;
9134
9135 // After emitting expressions for all parameters, copy over any
9136 // formal parameters which have been redeclared as vars. For
9137 // example, in the following, the var y in the body scope is 42:
9138 //
9139 // function f(x, y = 42) { var y; }
9140 //
9141 RootedAtom name(cx);
9142 if (funbox->extraVarScopeBindings() &&
9143 funbox->functionScopeBindings()) {
9144 for (BindingIter bi(*funbox->functionScopeBindings(), true); bi;
9145 bi++) {
9146 name = bi.name();
9147
9148 // There may not be a var binding of the same name.
9149 if (!locationOfNameBoundInScope(name, extraVarEmitterScope.ptr()))
9150 continue;
9151
9152 // The '.this' and '.generator' function special
9153 // bindings should never appear in the extra var
9154 // scope. 'arguments', however, may.
9155 MOZ_ASSERT(name != cx->names().dotThis &&
9156 name != cx->names().dotGenerator);
9157
9158 NameLocation paramLoc =
9159 *locationOfNameBoundInScope(name, &funEmitterScope);
9160 auto emitRhs = [&name, ¶mLoc](BytecodeEmitter* bce,
9161 const NameLocation&, bool) {
9162 return bce->emitGetNameAtLocation(name, paramLoc);
9163 };
9164
9165 if (!emitInitializeName(name, emitRhs)) return false;
9166 if (!emit1(JSOP_POP)) return false;
9167 }
9168 }
9169 }
9170
9171 if (!emitFunctionBody(funBody)) return false;
9172
9173 if (extraVarEmitterScope && !extraVarEmitterScope->leave(this))
9174 return false;
9175 }
9176
9177 return funEmitterScope.leave(this);
9178 }
9179
9180 // No parameter expressions. Enter the function body scope and emit
9181 // everything.
9182 //
9183 // One caveat is that Debugger considers ops in the prologue to be
9184 // unreachable (i.e. cannot set a breakpoint on it). If there are no
9185 // parameter exprs, any unobservable environment ops (like pushing the
9186 // call object, setting '.this', etc) need to go in the prologue, else it
9187 // messes up breakpoint tests.
9188 EmitterScope emitterScope(this);
9189
9190 switchToPrologue();
9191 if (!emitterScope.enterFunction(this, funbox)) return false;
9192
9193 if (!emitInitializeFunctionSpecialNames()) return false;
9194 switchToMain();
9195
9196 if (!emitFunctionFormalParameters(pn)) return false;
9197
9198 if (!emitFunctionBody(funBody)) return false;
9199
9200 return emitterScope.leave(this);
9201 }
9202
emitFunctionFormalParameters(ParseNode * pn)9203 bool BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn) {
9204 ParseNode* funBody = pn->last();
9205 FunctionBox* funbox = sc->asFunctionBox();
9206 EmitterScope* funScope = innermostEmitterScope();
9207
9208 bool hasParameterExprs = funbox->hasParameterExprs;
9209 bool hasRest = funbox->hasRest();
9210
9211 uint16_t argSlot = 0;
9212 for (ParseNode *arg = pn->pn_head; arg != funBody;
9213 arg = arg->pn_next, argSlot++) {
9214 ParseNode* bindingElement = arg;
9215 ParseNode* initializer = nullptr;
9216 if (arg->isKind(ParseNodeKind::Assign)) {
9217 bindingElement = arg->pn_left;
9218 initializer = arg->pn_right;
9219 }
9220
9221 // Left-hand sides are either simple names or destructuring patterns.
9222 MOZ_ASSERT(bindingElement->isKind(ParseNodeKind::Name) ||
9223 bindingElement->isKind(ParseNodeKind::Array) ||
9224 bindingElement->isKind(ParseNodeKind::Object));
9225
9226 // The rest parameter doesn't have an initializer.
9227 bool isRest = hasRest && arg->pn_next == funBody;
9228 MOZ_ASSERT_IF(isRest, !initializer);
9229
9230 bool isDestructuring = !bindingElement->isKind(ParseNodeKind::Name);
9231
9232 // ES 14.1.19 says if BindingElement contains an expression in the
9233 // production FormalParameter : BindingElement, it is evaluated in a
9234 // new var environment. This is needed to prevent vars from escaping
9235 // direct eval in parameter expressions.
9236 Maybe<EmitterScope> paramExprVarScope;
9237 if (funbox->hasDirectEvalInParameterExpr &&
9238 (isDestructuring || initializer)) {
9239 paramExprVarScope.emplace(this);
9240 if (!paramExprVarScope->enterParameterExpressionVar(this)) return false;
9241 }
9242
9243 // First push the RHS if there is a default expression or if it is
9244 // rest.
9245
9246 if (initializer) {
9247 // If we have an initializer, emit the initializer and assign it
9248 // to the argument slot. TDZ is taken care of afterwards.
9249 MOZ_ASSERT(hasParameterExprs);
9250 if (!emitArgOp(JSOP_GETARG, argSlot)) return false;
9251 if (!emit1(JSOP_DUP)) return false;
9252 if (!emit1(JSOP_UNDEFINED)) return false;
9253 if (!emit1(JSOP_STRICTEQ)) return false;
9254 // Emit source note to enable Ion compilation.
9255 if (!newSrcNote(SRC_IF)) return false;
9256 JumpList jump;
9257 if (!emitJump(JSOP_IFEQ, &jump)) return false;
9258 if (!emit1(JSOP_POP)) return false;
9259 if (!emitInitializerInBranch(initializer, bindingElement)) return false;
9260 if (!emitJumpTargetAndPatch(jump)) return false;
9261 } else if (isRest) {
9262 if (!emit1(JSOP_REST)) return false;
9263 checkTypeSet(JSOP_REST);
9264 }
9265
9266 // Initialize the parameter name.
9267
9268 if (isDestructuring) {
9269 // If we had an initializer or the rest parameter, the value is
9270 // already on the stack.
9271 if (!initializer && !isRest && !emitArgOp(JSOP_GETARG, argSlot))
9272 return false;
9273
9274 // If there's an parameter expression var scope, the destructuring
9275 // declaration needs to initialize the name in the function scope,
9276 // which is not the innermost scope.
9277 if (!emitDestructuringOps(bindingElement,
9278 paramExprVarScope
9279 ? DestructuringFormalParameterInVarScope
9280 : DestructuringDeclaration)) {
9281 return false;
9282 }
9283
9284 if (!emit1(JSOP_POP)) return false;
9285 } else {
9286 RootedAtom paramName(cx, bindingElement->name());
9287 NameLocation paramLoc = *locationOfNameBoundInScope(paramName, funScope);
9288
9289 if (hasParameterExprs) {
9290 auto emitRhs = [argSlot, initializer, isRest](
9291 BytecodeEmitter* bce, const NameLocation&, bool) {
9292 // If we had an initializer or a rest parameter, the value is
9293 // already on the stack.
9294 if (!initializer && !isRest)
9295 return bce->emitArgOp(JSOP_GETARG, argSlot);
9296 return true;
9297 };
9298
9299 if (!emitSetOrInitializeNameAtLocation(paramName, paramLoc, emitRhs,
9300 true))
9301 return false;
9302 if (!emit1(JSOP_POP)) return false;
9303 } else if (isRest) {
9304 // The rest value is already on top of the stack.
9305 auto nop = [](BytecodeEmitter*, const NameLocation&, bool) {
9306 return true;
9307 };
9308
9309 if (!emitSetOrInitializeNameAtLocation(paramName, paramLoc, nop, true))
9310 return false;
9311 if (!emit1(JSOP_POP)) return false;
9312 }
9313 }
9314
9315 if (paramExprVarScope) {
9316 if (!paramExprVarScope->leave(this)) return false;
9317 }
9318 }
9319
9320 return true;
9321 }
9322
emitInitializeFunctionSpecialNames()9323 bool BytecodeEmitter::emitInitializeFunctionSpecialNames() {
9324 FunctionBox* funbox = sc->asFunctionBox();
9325
9326 auto emitInitializeFunctionSpecialName =
9327 [](BytecodeEmitter* bce, HandlePropertyName name, JSOp op) {
9328 // A special name must be slotful, either on the frame or on the
9329 // call environment.
9330 MOZ_ASSERT(bce->lookupName(name).hasKnownSlot());
9331
9332 auto emitInitial = [op](BytecodeEmitter* bce, const NameLocation&,
9333 bool) { return bce->emit1(op); };
9334
9335 if (!bce->emitInitializeName(name, emitInitial)) return false;
9336 if (!bce->emit1(JSOP_POP)) return false;
9337
9338 return true;
9339 };
9340
9341 // Do nothing if the function doesn't have an arguments binding.
9342 if (funbox->argumentsHasLocalBinding()) {
9343 if (!emitInitializeFunctionSpecialName(this, cx->names().arguments,
9344 JSOP_ARGUMENTS))
9345 return false;
9346 }
9347
9348 // Do nothing if the function doesn't have a this-binding (this
9349 // happens for instance if it doesn't use this/eval or if it's an
9350 // arrow function).
9351 if (funbox->hasThisBinding()) {
9352 if (!emitInitializeFunctionSpecialName(this, cx->names().dotThis,
9353 JSOP_FUNCTIONTHIS))
9354 return false;
9355 }
9356
9357 return true;
9358 }
9359
emitFunctionBody(ParseNode * funBody)9360 bool BytecodeEmitter::emitFunctionBody(ParseNode* funBody) {
9361 FunctionBox* funbox = sc->asFunctionBox();
9362
9363 if (!emitTree(funBody)) return false;
9364
9365 if (funbox->needsFinalYield()) {
9366 // If we fall off the end of a generator, do a final yield.
9367 bool needsIteratorResult = funbox->needsIteratorResult();
9368 if (needsIteratorResult) {
9369 if (!emitPrepareIteratorResult()) return false;
9370 }
9371
9372 if (!emit1(JSOP_UNDEFINED)) return false;
9373
9374 if (needsIteratorResult) {
9375 if (!emitFinishIteratorResult(true)) return false;
9376 }
9377
9378 if (!emit1(JSOP_SETRVAL)) return false;
9379
9380 if (!emitGetDotGeneratorInInnermostScope()) return false;
9381
9382 // No need to check for finally blocks, etc as in EmitReturn.
9383 if (!emitYieldOp(JSOP_FINALYIELDRVAL)) return false;
9384 } else {
9385 // Non-generator functions just return |undefined|. The
9386 // JSOP_RETRVAL emitted below will do that, except if the
9387 // script has a finally block: there can be a non-undefined
9388 // value in the return value slot. Make sure the return value
9389 // is |undefined|.
9390 if (hasTryFinally) {
9391 if (!emit1(JSOP_UNDEFINED)) return false;
9392 if (!emit1(JSOP_SETRVAL)) return false;
9393 }
9394 }
9395
9396 if (funbox->isDerivedClassConstructor()) {
9397 if (!emitCheckDerivedClassConstructorReturn()) return false;
9398 }
9399
9400 return true;
9401 }
9402
emitLexicalInitialization(ParseNode * pn)9403 bool BytecodeEmitter::emitLexicalInitialization(ParseNode* pn) {
9404 // The caller has pushed the RHS to the top of the stack. Assert that the
9405 // name is lexical and no BIND[G]NAME ops were emitted.
9406 auto assertLexical = [](BytecodeEmitter*, const NameLocation& loc,
9407 bool emittedBindOp) {
9408 MOZ_ASSERT(loc.isLexical());
9409 MOZ_ASSERT(!emittedBindOp);
9410 return true;
9411 };
9412 return emitInitializeName(pn, assertLexical);
9413 }
9414
9415 // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
9416 // (BindingClassDeclarationEvaluation).
emitClass(ParseNode * pn)9417 bool BytecodeEmitter::emitClass(ParseNode* pn) {
9418 ClassNode& classNode = pn->as<ClassNode>();
9419
9420 ClassNames* names = classNode.names();
9421
9422 ParseNode* heritageExpression = classNode.heritage();
9423
9424 ParseNode* classMethods = classNode.methodList();
9425 ParseNode* constructor = nullptr;
9426 for (ParseNode* mn = classMethods->pn_head; mn; mn = mn->pn_next) {
9427 ClassMethod& method = mn->as<ClassMethod>();
9428 ParseNode& methodName = method.name();
9429 if (!method.isStatic() &&
9430 (methodName.isKind(ParseNodeKind::ObjectPropertyName) ||
9431 methodName.isKind(ParseNodeKind::String)) &&
9432 methodName.pn_atom == cx->names().constructor) {
9433 constructor = &method.method();
9434 break;
9435 }
9436 }
9437
9438 bool savedStrictness = sc->setLocalStrictMode(true);
9439
9440 Maybe<TDZCheckCache> tdzCache;
9441 Maybe<EmitterScope> emitterScope;
9442 if (names) {
9443 tdzCache.emplace(this);
9444 emitterScope.emplace(this);
9445 if (!emitterScope->enterLexical(this, ScopeKind::Lexical,
9446 classNode.scopeBindings()))
9447 return false;
9448 }
9449
9450 // Pseudocode for class declarations:
9451 //
9452 // class extends BaseExpression {
9453 // constructor() { ... }
9454 // ...
9455 // }
9456 //
9457 //
9458 // if defined <BaseExpression> {
9459 // let heritage = BaseExpression;
9460 //
9461 // if (heritage !== null) {
9462 // funProto = heritage;
9463 // objProto = heritage.prototype;
9464 // } else {
9465 // funProto = %FunctionPrototype%;
9466 // objProto = null;
9467 // }
9468 // } else {
9469 // objProto = %ObjectPrototype%;
9470 // }
9471 //
9472 // let homeObject = ObjectCreate(objProto);
9473 //
9474 // if defined <constructor> {
9475 // if defined <BaseExpression> {
9476 // cons = DefineMethod(<constructor>, proto=homeObject,
9477 // funProto=funProto);
9478 // } else {
9479 // cons = DefineMethod(<constructor>, proto=homeObject);
9480 // }
9481 // } else {
9482 // if defined <BaseExpression> {
9483 // cons = DefaultDerivedConstructor(proto=homeObject,
9484 // funProto=funProto);
9485 // } else {
9486 // cons = DefaultConstructor(proto=homeObject);
9487 // }
9488 // }
9489 //
9490 // cons.prototype = homeObject;
9491 // homeObject.constructor = cons;
9492 //
9493 // EmitPropertyList(...)
9494
9495 // This is kind of silly. In order to the get the home object defined on
9496 // the constructor, we have to make it second, but we want the prototype
9497 // on top for EmitPropertyList, because we expect static properties to be
9498 // rarer. The result is a few more swaps than we would like. Such is life.
9499 if (heritageExpression) {
9500 IfThenElseEmitter ifThenElse(this);
9501
9502 if (!emitTree(heritageExpression)) // ... HERITAGE
9503 return false;
9504
9505 // Heritage must be null or a non-generator constructor
9506 if (!emit1(JSOP_CHECKCLASSHERITAGE)) // ... HERITAGE
9507 return false;
9508
9509 // [IF] (heritage !== null)
9510 if (!emit1(JSOP_DUP)) // ... HERITAGE HERITAGE
9511 return false;
9512 if (!emit1(JSOP_NULL)) // ... HERITAGE HERITAGE NULL
9513 return false;
9514 if (!emit1(JSOP_STRICTNE)) // ... HERITAGE NE
9515 return false;
9516
9517 // [THEN] funProto = heritage, objProto = heritage.prototype
9518 if (!ifThenElse.emitIfElse()) return false;
9519 if (!emit1(JSOP_DUP)) // ... HERITAGE HERITAGE
9520 return false;
9521 if (!emitAtomOp(cx->names().prototype, JSOP_GETPROP)) // ... HERITAGE PROTO
9522 return false;
9523
9524 // [ELSE] funProto = %FunctionPrototype%, objProto = null
9525 if (!ifThenElse.emitElse()) return false;
9526 if (!emit1(JSOP_POP)) // ...
9527 return false;
9528 if (!emit2(JSOP_BUILTINPROTO, JSProto_Function)) // ... PROTO
9529 return false;
9530 if (!emit1(JSOP_NULL)) // ... PROTO NULL
9531 return false;
9532
9533 // [ENDIF]
9534 if (!ifThenElse.emitEnd()) return false;
9535
9536 if (!emit1(JSOP_OBJWITHPROTO)) // ... HERITAGE HOMEOBJ
9537 return false;
9538 if (!emit1(JSOP_SWAP)) // ... HOMEOBJ HERITAGE
9539 return false;
9540 } else {
9541 if (!emitNewInit(JSProto_Object)) // ... HOMEOBJ
9542 return false;
9543 }
9544
9545 // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
9546 // is not used, an implicit value of %FunctionPrototype% is implied.
9547
9548 if (constructor) {
9549 if (!emitFunction(constructor,
9550 !!heritageExpression)) // ... HOMEOBJ CONSTRUCTOR
9551 return false;
9552 if (constructor->pn_funbox->needsHomeObject()) {
9553 if (!emit2(JSOP_INITHOMEOBJECT, 0)) // ... HOMEOBJ CONSTRUCTOR
9554 return false;
9555 }
9556 } else {
9557 // In the case of default class constructors, emit the start and end
9558 // offsets in the source buffer as source notes so that when we
9559 // actually make the constructor during execution, we can give it the
9560 // correct toString output.
9561 ptrdiff_t classStart = ptrdiff_t(pn->pn_pos.begin);
9562 ptrdiff_t classEnd = ptrdiff_t(pn->pn_pos.end);
9563 if (!newSrcNote3(SRC_CLASS_SPAN, classStart, classEnd)) return false;
9564
9565 JSAtom* name = names ? names->innerBinding()->pn_atom : cx->names().empty;
9566 if (heritageExpression) {
9567 if (!emitAtomOp(name,
9568 JSOP_DERIVEDCONSTRUCTOR)) // ... HOMEOBJ CONSTRUCTOR
9569 return false;
9570 } else {
9571 if (!emitAtomOp(name, JSOP_CLASSCONSTRUCTOR)) // ... HOMEOBJ CONSTRUCTOR
9572 return false;
9573 }
9574 }
9575
9576 if (!emit1(JSOP_SWAP)) // ... CONSTRUCTOR HOMEOBJ
9577 return false;
9578
9579 if (!emit1(JSOP_DUP2)) // ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR HOMEOBJ
9580 return false;
9581 if (!emitAtomOp(cx->names().prototype,
9582 JSOP_INITLOCKEDPROP)) // ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR
9583 return false;
9584 if (!emitAtomOp(cx->names().constructor,
9585 JSOP_INITHIDDENPROP)) // ... CONSTRUCTOR HOMEOBJ
9586 return false;
9587
9588 RootedPlainObject obj(cx);
9589 if (!emitPropertyList(classMethods, &obj,
9590 ClassBody)) // ... CONSTRUCTOR HOMEOBJ
9591 return false;
9592
9593 if (!emit1(JSOP_POP)) // ... CONSTRUCTOR
9594 return false;
9595
9596 if (names) {
9597 ParseNode* innerName = names->innerBinding();
9598 if (!emitLexicalInitialization(innerName)) // ... CONSTRUCTOR
9599 return false;
9600
9601 // Pop the inner scope.
9602 if (!emitterScope->leave(this)) return false;
9603 emitterScope.reset();
9604
9605 ParseNode* outerName = names->outerBinding();
9606 if (outerName) {
9607 if (!emitLexicalInitialization(outerName)) // ... CONSTRUCTOR
9608 return false;
9609 // Only class statements make outer bindings, and they do not leave
9610 // themselves on the stack.
9611 if (!emit1(JSOP_POP)) // ...
9612 return false;
9613 }
9614 }
9615
9616 // The CONSTRUCTOR is left on stack if this is an expression.
9617
9618 MOZ_ALWAYS_TRUE(sc->setLocalStrictMode(savedStrictness));
9619
9620 return true;
9621 }
9622
emitExportDefault(ParseNode * pn)9623 bool BytecodeEmitter::emitExportDefault(ParseNode* pn) {
9624 if (!emitTree(pn->pn_left)) return false;
9625
9626 if (pn->pn_right) {
9627 if (!emitLexicalInitialization(pn->pn_right)) return false;
9628
9629 if (pn->pn_left->isDirectRHSAnonFunction()) {
9630 HandlePropertyName name = cx->names().default_;
9631 if (!setOrEmitSetFunName(pn->pn_left, name, FunctionPrefixKind::None))
9632 return false;
9633 }
9634
9635 if (!emit1(JSOP_POP)) return false;
9636 }
9637
9638 return true;
9639 }
9640
emitTree(ParseNode * pn,ValueUsage valueUsage,EmitLineNumberNote emitLineNote)9641 bool BytecodeEmitter::emitTree(
9642 ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
9643 EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */) {
9644 if (!CheckRecursionLimit(cx)) return false;
9645
9646 EmitLevelManager elm(this);
9647
9648 /* Emit notes to tell the current bytecode's source line number.
9649 However, a couple trees require special treatment; see the
9650 relevant emitter functions for details. */
9651 if (emitLineNote == EMIT_LINENOTE &&
9652 !ParseNodeRequiresSpecialLineNumberNotes(pn)) {
9653 if (!updateLineNumberNotes(pn->pn_pos.begin)) return false;
9654 }
9655
9656 switch (pn->getKind()) {
9657 case ParseNodeKind::Function:
9658 if (!emitFunction(pn)) return false;
9659 break;
9660
9661 case ParseNodeKind::ParamsBody:
9662 if (!emitFunctionFormalParametersAndBody(pn)) return false;
9663 break;
9664
9665 case ParseNodeKind::If:
9666 if (!emitIf(pn)) return false;
9667 break;
9668
9669 case ParseNodeKind::Switch:
9670 if (!emitSwitch(pn)) return false;
9671 break;
9672
9673 case ParseNodeKind::While:
9674 if (!emitWhile(pn)) return false;
9675 break;
9676
9677 case ParseNodeKind::DoWhile:
9678 if (!emitDo(pn)) return false;
9679 break;
9680
9681 case ParseNodeKind::For:
9682 if (!emitFor(pn)) return false;
9683 break;
9684
9685 case ParseNodeKind::Break:
9686 if (!emitBreak(pn->as<BreakStatement>().label())) return false;
9687 break;
9688
9689 case ParseNodeKind::Continue:
9690 if (!emitContinue(pn->as<ContinueStatement>().label())) return false;
9691 break;
9692
9693 case ParseNodeKind::With:
9694 if (!emitWith(pn)) return false;
9695 break;
9696
9697 case ParseNodeKind::Try:
9698 if (!emitTry(pn)) return false;
9699 break;
9700
9701 case ParseNodeKind::Catch:
9702 if (!emitCatch(pn)) return false;
9703 break;
9704
9705 case ParseNodeKind::Var:
9706 if (!emitDeclarationList(pn)) return false;
9707 break;
9708
9709 case ParseNodeKind::Return:
9710 if (!emitReturn(pn)) return false;
9711 break;
9712
9713 case ParseNodeKind::YieldStar:
9714 if (!emitYieldStar(pn->pn_kid)) return false;
9715 break;
9716
9717 case ParseNodeKind::Generator:
9718 if (!emit1(JSOP_GENERATOR)) return false;
9719 break;
9720
9721 case ParseNodeKind::InitialYield:
9722 if (!emitInitialYield(pn)) return false;
9723 break;
9724
9725 case ParseNodeKind::Yield:
9726 if (!emitYield(pn)) return false;
9727 break;
9728
9729 case ParseNodeKind::Await:
9730 if (!emitAwaitInInnermostScope(pn)) return false;
9731 break;
9732
9733 case ParseNodeKind::StatementList:
9734 if (!emitStatementList(pn)) return false;
9735 break;
9736
9737 case ParseNodeKind::EmptyStatement:
9738 break;
9739
9740 case ParseNodeKind::ExpressionStatement:
9741 if (!emitExpressionStatement(pn)) return false;
9742 break;
9743
9744 case ParseNodeKind::Label:
9745 if (!emitLabeledStatement(&pn->as<LabeledStatement>())) return false;
9746 break;
9747
9748 case ParseNodeKind::Comma:
9749 if (!emitSequenceExpr(pn, valueUsage)) return false;
9750 break;
9751
9752 case ParseNodeKind::Assign:
9753 case ParseNodeKind::AddAssign:
9754 case ParseNodeKind::SubAssign:
9755 case ParseNodeKind::BitOrAssign:
9756 case ParseNodeKind::BitXorAssign:
9757 case ParseNodeKind::BitAndAssign:
9758 case ParseNodeKind::LshAssign:
9759 case ParseNodeKind::RshAssign:
9760 case ParseNodeKind::UrshAssign:
9761 case ParseNodeKind::MulAssign:
9762 case ParseNodeKind::DivAssign:
9763 case ParseNodeKind::ModAssign:
9764 case ParseNodeKind::PowAssign:
9765 if (!emitAssignment(pn->pn_left, pn->getKind(), pn->pn_right))
9766 return false;
9767 break;
9768
9769 case ParseNodeKind::Conditional:
9770 if (!emitConditionalExpression(pn->as<ConditionalExpression>(),
9771 valueUsage))
9772 return false;
9773 break;
9774
9775 case ParseNodeKind::Or:
9776 case ParseNodeKind::And:
9777 if (!emitLogical(pn)) return false;
9778 break;
9779
9780 case ParseNodeKind::Add:
9781 case ParseNodeKind::Sub:
9782 case ParseNodeKind::BitOr:
9783 case ParseNodeKind::BitXor:
9784 case ParseNodeKind::BitAnd:
9785 case ParseNodeKind::StrictEq:
9786 case ParseNodeKind::Eq:
9787 case ParseNodeKind::StrictNe:
9788 case ParseNodeKind::Ne:
9789 case ParseNodeKind::Lt:
9790 case ParseNodeKind::Le:
9791 case ParseNodeKind::Gt:
9792 case ParseNodeKind::Ge:
9793 case ParseNodeKind::In:
9794 case ParseNodeKind::InstanceOf:
9795 case ParseNodeKind::Lsh:
9796 case ParseNodeKind::Rsh:
9797 case ParseNodeKind::Ursh:
9798 case ParseNodeKind::Star:
9799 case ParseNodeKind::Div:
9800 case ParseNodeKind::Mod:
9801 if (!emitLeftAssociative(pn)) return false;
9802 break;
9803
9804 case ParseNodeKind::Pow:
9805 if (!emitRightAssociative(pn)) return false;
9806 break;
9807
9808 case ParseNodeKind::Pipeline:
9809 if (!emitPipeline(pn)) return false;
9810 break;
9811
9812 case ParseNodeKind::TypeOfName:
9813 if (!emitTypeof(pn, JSOP_TYPEOF)) return false;
9814 break;
9815
9816 case ParseNodeKind::TypeOfExpr:
9817 if (!emitTypeof(pn, JSOP_TYPEOFEXPR)) return false;
9818 break;
9819
9820 case ParseNodeKind::Throw:
9821 case ParseNodeKind::Void:
9822 case ParseNodeKind::Not:
9823 case ParseNodeKind::BitNot:
9824 case ParseNodeKind::Pos:
9825 case ParseNodeKind::Neg:
9826 if (!emitUnary(pn)) return false;
9827 break;
9828
9829 case ParseNodeKind::PreIncrement:
9830 case ParseNodeKind::PreDecrement:
9831 case ParseNodeKind::PostIncrement:
9832 case ParseNodeKind::PostDecrement:
9833 if (!emitIncOrDec(pn)) return false;
9834 break;
9835
9836 case ParseNodeKind::DeleteName:
9837 if (!emitDeleteName(pn)) return false;
9838 break;
9839
9840 case ParseNodeKind::DeleteProp:
9841 if (!emitDeleteProperty(pn)) return false;
9842 break;
9843
9844 case ParseNodeKind::DeleteElem:
9845 if (!emitDeleteElement(pn)) return false;
9846 break;
9847
9848 case ParseNodeKind::DeleteExpr:
9849 if (!emitDeleteExpression(pn)) return false;
9850 break;
9851
9852 case ParseNodeKind::Dot:
9853 if (pn->as<PropertyAccess>().isSuper()) {
9854 if (!emitSuperPropOp(pn, JSOP_GETPROP_SUPER)) return false;
9855 } else {
9856 if (!emitPropOp(pn, JSOP_GETPROP)) return false;
9857 }
9858 break;
9859
9860 case ParseNodeKind::Elem:
9861 if (pn->as<PropertyByValue>().isSuper()) {
9862 if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER)) return false;
9863 } else {
9864 if (!emitElemOp(pn, JSOP_GETELEM)) return false;
9865 }
9866 break;
9867
9868 case ParseNodeKind::New:
9869 case ParseNodeKind::TaggedTemplate:
9870 case ParseNodeKind::Call:
9871 case ParseNodeKind::SuperCall:
9872 if (!emitCallOrNew(pn, valueUsage)) return false;
9873 break;
9874
9875 case ParseNodeKind::LexicalScope:
9876 if (!emitLexicalScope(pn)) return false;
9877 break;
9878
9879 case ParseNodeKind::Const:
9880 case ParseNodeKind::Let:
9881 if (!emitDeclarationList(pn)) return false;
9882 break;
9883
9884 case ParseNodeKind::Import:
9885 MOZ_ASSERT(sc->isModuleContext());
9886 break;
9887
9888 case ParseNodeKind::Export:
9889 MOZ_ASSERT(sc->isModuleContext());
9890 if (pn->pn_kid->getKind() != ParseNodeKind::ExportSpecList) {
9891 if (!emitTree(pn->pn_kid)) return false;
9892 }
9893 break;
9894
9895 case ParseNodeKind::ExportDefault:
9896 MOZ_ASSERT(sc->isModuleContext());
9897 if (!emitExportDefault(pn)) return false;
9898 break;
9899
9900 case ParseNodeKind::ExportFrom:
9901 MOZ_ASSERT(sc->isModuleContext());
9902 break;
9903
9904 case ParseNodeKind::CallSiteObj:
9905 if (!emitCallSiteObject(pn)) return false;
9906 break;
9907
9908 case ParseNodeKind::Array:
9909 if (!emitArrayLiteral(pn)) return false;
9910 break;
9911
9912 case ParseNodeKind::Object:
9913 if (!emitObject(pn)) return false;
9914 break;
9915
9916 case ParseNodeKind::Name:
9917 if (!emitGetName(pn)) return false;
9918 break;
9919
9920 case ParseNodeKind::TemplateStringList:
9921 if (!emitTemplateString(pn)) return false;
9922 break;
9923
9924 case ParseNodeKind::TemplateString:
9925 case ParseNodeKind::String:
9926 if (!emitAtomOp(pn, JSOP_STRING)) return false;
9927 break;
9928
9929 case ParseNodeKind::Number:
9930 if (!emitNumberOp(pn->pn_dval)) return false;
9931 break;
9932
9933 case ParseNodeKind::RegExp:
9934 if (!emitRegExp(objectList.add(pn->as<RegExpLiteral>().objbox())))
9935 return false;
9936 break;
9937
9938 case ParseNodeKind::True:
9939 case ParseNodeKind::False:
9940 case ParseNodeKind::Null:
9941 case ParseNodeKind::RawUndefined:
9942 if (!emit1(pn->getOp())) return false;
9943 break;
9944
9945 case ParseNodeKind::This:
9946 if (!emitThisLiteral(pn)) return false;
9947 break;
9948
9949 case ParseNodeKind::Debugger:
9950 if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false;
9951 if (!emit1(JSOP_DEBUGGER)) return false;
9952 break;
9953
9954 case ParseNodeKind::Class:
9955 if (!emitClass(pn)) return false;
9956 break;
9957
9958 case ParseNodeKind::NewTarget:
9959 if (!emit1(JSOP_NEWTARGET)) return false;
9960 break;
9961
9962 case ParseNodeKind::SetThis:
9963 if (!emitSetThis(pn)) return false;
9964 break;
9965
9966 case ParseNodeKind::PosHolder:
9967 MOZ_FALLTHROUGH_ASSERT(
9968 "Should never try to emit ParseNodeKind::PosHolder");
9969
9970 default:
9971 MOZ_ASSERT(0);
9972 }
9973
9974 /* bce->emitLevel == 1 means we're last on the stack, so finish up. */
9975 if (emitLevel == 1) {
9976 if (!updateSourceCoordNotes(pn->pn_pos.end)) return false;
9977 }
9978 return true;
9979 }
9980
emitTreeInBranch(ParseNode * pn,ValueUsage valueUsage)9981 bool BytecodeEmitter::emitTreeInBranch(
9982 ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */) {
9983 // Code that may be conditionally executed always need their own TDZ
9984 // cache.
9985 TDZCheckCache tdzCache(this);
9986 return emitTree(pn, valueUsage);
9987 }
9988
AllocSrcNote(JSContext * cx,SrcNotesVector & notes,unsigned * index)9989 static bool AllocSrcNote(JSContext* cx, SrcNotesVector& notes,
9990 unsigned* index) {
9991 size_t oldLength = notes.length();
9992
9993 if (MOZ_UNLIKELY(oldLength + 1 > MaxSrcNotesLength)) {
9994 ReportAllocationOverflow(cx);
9995 return false;
9996 }
9997
9998 if (!notes.growBy(1)) {
9999 return false;
10000 }
10001
10002 *index = oldLength;
10003 return true;
10004 }
10005
newSrcNote(SrcNoteType type,unsigned * indexp)10006 bool BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp) {
10007 SrcNotesVector& notes = this->notes();
10008 unsigned index;
10009 if (!AllocSrcNote(cx, notes, &index)) return false;
10010
10011 /*
10012 * Compute delta from the last annotated bytecode's offset. If it's too
10013 * big to fit in sn, allocate one or more xdelta notes and reset sn.
10014 */
10015 ptrdiff_t offset = this->offset();
10016 ptrdiff_t delta = offset - lastNoteOffset();
10017 current->lastNoteOffset = offset;
10018 if (delta >= SN_DELTA_LIMIT) {
10019 do {
10020 ptrdiff_t xdelta = Min(delta, SN_XDELTA_MASK);
10021 SN_MAKE_XDELTA(¬es[index], xdelta);
10022 delta -= xdelta;
10023 if (!AllocSrcNote(cx, notes, &index)) return false;
10024 } while (delta >= SN_DELTA_LIMIT);
10025 }
10026
10027 /*
10028 * Initialize type and delta, then allocate the minimum number of notes
10029 * needed for type's arity. Usually, we won't need more, but if an offset
10030 * does take two bytes, setSrcNoteOffset will grow notes.
10031 */
10032 SN_MAKE_NOTE(¬es[index], type, delta);
10033 for (int n = (int)js_SrcNoteSpec[type].arity; n > 0; n--) {
10034 if (!newSrcNote(SRC_NULL)) return false;
10035 }
10036
10037 if (indexp) *indexp = index;
10038 return true;
10039 }
10040
newSrcNote2(SrcNoteType type,ptrdiff_t offset,unsigned * indexp)10041 bool BytecodeEmitter::newSrcNote2(SrcNoteType type, ptrdiff_t offset,
10042 unsigned* indexp) {
10043 unsigned index;
10044 if (!newSrcNote(type, &index)) return false;
10045 if (!setSrcNoteOffset(index, 0, offset)) return false;
10046 if (indexp) *indexp = index;
10047 return true;
10048 }
10049
newSrcNote3(SrcNoteType type,ptrdiff_t offset1,ptrdiff_t offset2,unsigned * indexp)10050 bool BytecodeEmitter::newSrcNote3(SrcNoteType type, ptrdiff_t offset1,
10051 ptrdiff_t offset2, unsigned* indexp) {
10052 unsigned index;
10053 if (!newSrcNote(type, &index)) return false;
10054 if (!setSrcNoteOffset(index, 0, offset1)) return false;
10055 if (!setSrcNoteOffset(index, 1, offset2)) return false;
10056 if (indexp) *indexp = index;
10057 return true;
10058 }
10059
addToSrcNoteDelta(jssrcnote * sn,ptrdiff_t delta)10060 bool BytecodeEmitter::addToSrcNoteDelta(jssrcnote* sn, ptrdiff_t delta) {
10061 /*
10062 * Called only from finishTakingSrcNotes to add to main script note
10063 * deltas, and only by a small positive amount.
10064 */
10065 MOZ_ASSERT(current == &main);
10066 MOZ_ASSERT((unsigned)delta < (unsigned)SN_XDELTA_LIMIT);
10067
10068 ptrdiff_t base = SN_DELTA(sn);
10069 ptrdiff_t limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
10070 ptrdiff_t newdelta = base + delta;
10071 if (newdelta < limit) {
10072 SN_SET_DELTA(sn, newdelta);
10073 } else {
10074 jssrcnote xdelta;
10075 SN_MAKE_XDELTA(&xdelta, delta);
10076 if (!main.notes.insert(sn, xdelta)) return false;
10077 }
10078 return true;
10079 }
10080
setSrcNoteOffset(unsigned index,unsigned which,ptrdiff_t offset)10081 bool BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which,
10082 ptrdiff_t offset) {
10083 if (!SN_REPRESENTABLE_OFFSET(offset)) {
10084 parser.reportError(JSMSG_NEED_DIET, js_script_str);
10085 return false;
10086 }
10087
10088 SrcNotesVector& notes = this->notes();
10089
10090 /* Find the offset numbered which (i.e., skip exactly which offsets). */
10091 jssrcnote* sn = ¬es[index];
10092 MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
10093 MOZ_ASSERT((int)which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
10094 for (sn++; which; sn++, which--) {
10095 if (*sn & SN_4BYTE_OFFSET_FLAG) sn += 3;
10096 }
10097
10098 /*
10099 * See if the new offset requires four bytes either by being too big or if
10100 * the offset has already been inflated (in which case, we need to stay big
10101 * to not break the srcnote encoding if this isn't the last srcnote).
10102 */
10103 if (offset > (ptrdiff_t)SN_4BYTE_OFFSET_MASK ||
10104 (*sn & SN_4BYTE_OFFSET_FLAG)) {
10105 /* Maybe this offset was already set to a four-byte value. */
10106 if (!(*sn & SN_4BYTE_OFFSET_FLAG)) {
10107 /* Insert three dummy bytes that will be overwritten shortly. */
10108 if (MOZ_UNLIKELY(notes.length() + 3 > MaxSrcNotesLength)) {
10109 ReportAllocationOverflow(cx);
10110 return false;
10111 }
10112 jssrcnote dummy = 0;
10113 if (!(sn = notes.insert(sn, dummy)) || !(sn = notes.insert(sn, dummy)) ||
10114 !(sn = notes.insert(sn, dummy))) {
10115 return false;
10116 }
10117 }
10118 *sn++ = (jssrcnote)(SN_4BYTE_OFFSET_FLAG | (offset >> 24));
10119 *sn++ = (jssrcnote)(offset >> 16);
10120 *sn++ = (jssrcnote)(offset >> 8);
10121 }
10122 *sn = (jssrcnote)offset;
10123 return true;
10124 }
10125
finishTakingSrcNotes(uint32_t * out)10126 bool BytecodeEmitter::finishTakingSrcNotes(uint32_t* out) {
10127 MOZ_ASSERT(current == &main);
10128
10129 unsigned prologueCount = prologue.notes.length();
10130 if (prologueCount && prologue.currentLine != firstLine) {
10131 switchToPrologue();
10132 if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(firstLine))) return false;
10133 switchToMain();
10134 } else {
10135 /*
10136 * Either no prologue srcnotes, or no line number change over prologue.
10137 * We don't need a SRC_SETLINE, but we may need to adjust the offset
10138 * of the first main note, by adding to its delta and possibly even
10139 * prepending SRC_XDELTA notes to it to account for prologue bytecodes
10140 * that came at and after the last annotated bytecode.
10141 */
10142 ptrdiff_t offset = prologueOffset() - prologue.lastNoteOffset;
10143 MOZ_ASSERT(offset >= 0);
10144 if (offset > 0 && main.notes.length() != 0) {
10145 /* NB: Use as much of the first main note's delta as we can. */
10146 jssrcnote* sn = main.notes.begin();
10147 ptrdiff_t delta = SN_IS_XDELTA(sn)
10148 ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
10149 : SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
10150 if (offset < delta) delta = offset;
10151 for (;;) {
10152 if (!addToSrcNoteDelta(sn, delta)) return false;
10153 offset -= delta;
10154 if (offset == 0) break;
10155 delta = Min(offset, SN_XDELTA_MASK);
10156 sn = main.notes.begin();
10157 }
10158 }
10159 }
10160
10161 // The prologue count might have changed, so we can't reuse prologueCount.
10162 // The + 1 is to account for the final SN_MAKE_TERMINATOR that is appended
10163 // when the notes are copied to their final destination by copySrcNotes.
10164 *out = prologue.notes.length() + main.notes.length() + 1;
10165 return true;
10166 }
10167
copySrcNotes(jssrcnote * destination,uint32_t nsrcnotes)10168 void BytecodeEmitter::copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes) {
10169 unsigned prologueCount = prologue.notes.length();
10170 unsigned mainCount = main.notes.length();
10171 unsigned totalCount = prologueCount + mainCount;
10172 MOZ_ASSERT(totalCount == nsrcnotes - 1);
10173 if (prologueCount)
10174 PodCopy(destination, prologue.notes.begin(), prologueCount);
10175 PodCopy(destination + prologueCount, main.notes.begin(), mainCount);
10176 SN_MAKE_TERMINATOR(&destination[totalCount]);
10177 }
10178
finish(ConstArray * array)10179 void CGConstList::finish(ConstArray* array) {
10180 MOZ_ASSERT(length() == array->length);
10181
10182 for (unsigned i = 0; i < length(); i++) array->vector[i] = list[i];
10183 }
10184
10185 /*
10186 * Find the index of the given object for code generator.
10187 *
10188 * Since the emitter refers to each parsed object only once, for the index we
10189 * use the number of already indexed objects. We also add the object to a list
10190 * to convert the list to a fixed-size array when we complete code generation,
10191 * see js::CGObjectList::finish below.
10192 */
add(ObjectBox * objbox)10193 unsigned CGObjectList::add(ObjectBox* objbox) {
10194 MOZ_ASSERT(!objbox->emitLink);
10195 objbox->emitLink = lastbox;
10196 lastbox = objbox;
10197 return length++;
10198 }
10199
indexOf(JSObject * obj)10200 unsigned CGObjectList::indexOf(JSObject* obj) {
10201 MOZ_ASSERT(length > 0);
10202 unsigned index = length - 1;
10203 for (ObjectBox* box = lastbox; box->object != obj; box = box->emitLink)
10204 index--;
10205 return index;
10206 }
10207
finish(ObjectArray * array)10208 void CGObjectList::finish(ObjectArray* array) {
10209 MOZ_ASSERT(length <= INDEX_LIMIT);
10210 MOZ_ASSERT(length == array->length);
10211
10212 js::GCPtrObject* cursor = array->vector + array->length;
10213 ObjectBox* objbox = lastbox;
10214 do {
10215 --cursor;
10216 MOZ_ASSERT(!*cursor);
10217 MOZ_ASSERT(objbox->object->isTenured());
10218 *cursor = objbox->object;
10219 } while ((objbox = objbox->emitLink) != nullptr);
10220 MOZ_ASSERT(cursor == array->vector);
10221 }
10222
find(uint32_t index)10223 ObjectBox* CGObjectList::find(uint32_t index) {
10224 MOZ_ASSERT(index < length);
10225 ObjectBox* box = lastbox;
10226 for (unsigned n = length - 1; n > index; n--) box = box->emitLink;
10227 return box;
10228 }
10229
finish(ScopeArray * array)10230 void CGScopeList::finish(ScopeArray* array) {
10231 MOZ_ASSERT(length() <= INDEX_LIMIT);
10232 MOZ_ASSERT(length() == array->length);
10233 for (uint32_t i = 0; i < length(); i++) array->vector[i].init(vector[i]);
10234 }
10235
append(JSTryNoteKind kind,uint32_t stackDepth,size_t start,size_t end)10236 bool CGTryNoteList::append(JSTryNoteKind kind, uint32_t stackDepth,
10237 size_t start, size_t end) {
10238 MOZ_ASSERT(start <= end);
10239 MOZ_ASSERT(size_t(uint32_t(start)) == start);
10240 MOZ_ASSERT(size_t(uint32_t(end)) == end);
10241
10242 JSTryNote note;
10243 note.kind = kind;
10244 note.stackDepth = stackDepth;
10245 note.start = uint32_t(start);
10246 note.length = uint32_t(end - start);
10247
10248 return list.append(note);
10249 }
10250
finish(TryNoteArray * array)10251 void CGTryNoteList::finish(TryNoteArray* array) {
10252 MOZ_ASSERT(length() == array->length);
10253
10254 for (unsigned i = 0; i < length(); i++) array->vector[i] = list[i];
10255 }
10256
append(uint32_t scopeIndex,uint32_t offset,bool inPrologue,uint32_t parent)10257 bool CGScopeNoteList::append(uint32_t scopeIndex, uint32_t offset,
10258 bool inPrologue, uint32_t parent) {
10259 CGScopeNote note;
10260 mozilla::PodZero(¬e);
10261
10262 note.index = scopeIndex;
10263 note.start = offset;
10264 note.parent = parent;
10265 note.startInPrologue = inPrologue;
10266
10267 return list.append(note);
10268 }
10269
recordEnd(uint32_t index,uint32_t offset,bool inPrologue)10270 void CGScopeNoteList::recordEnd(uint32_t index, uint32_t offset,
10271 bool inPrologue) {
10272 MOZ_ASSERT(index < length());
10273 MOZ_ASSERT(list[index].length == 0);
10274 list[index].end = offset;
10275 list[index].endInPrologue = inPrologue;
10276 }
10277
finish(ScopeNoteArray * array,uint32_t prologueLength)10278 void CGScopeNoteList::finish(ScopeNoteArray* array, uint32_t prologueLength) {
10279 MOZ_ASSERT(length() == array->length);
10280
10281 for (unsigned i = 0; i < length(); i++) {
10282 if (!list[i].startInPrologue) list[i].start += prologueLength;
10283 if (!list[i].endInPrologue && list[i].end != UINT32_MAX)
10284 list[i].end += prologueLength;
10285 MOZ_ASSERT(list[i].end >= list[i].start);
10286 list[i].length = list[i].end - list[i].start;
10287 array->vector[i] = list[i];
10288 }
10289 }
10290
finish(YieldAndAwaitOffsetArray & array,uint32_t prologueLength)10291 void CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array,
10292 uint32_t prologueLength) {
10293 MOZ_ASSERT(length() == array.length());
10294
10295 for (unsigned i = 0; i < length(); i++) array[i] = prologueLength + list[i];
10296 }
10297
10298 /*
10299 * We should try to get rid of offsetBias (always 0 or 1, where 1 is
10300 * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR.
10301 */
10302 const JSSrcNoteSpec js_SrcNoteSpec[] = {
10303 #define DEFINE_SRC_NOTE_SPEC(sym, name, arity) {name, arity},
10304 FOR_EACH_SRC_NOTE_TYPE(DEFINE_SRC_NOTE_SPEC)
10305 #undef DEFINE_SRC_NOTE_SPEC
10306 };
10307
SrcNoteArity(jssrcnote * sn)10308 static int SrcNoteArity(jssrcnote* sn) {
10309 MOZ_ASSERT(SN_TYPE(sn) < SRC_LAST);
10310 return js_SrcNoteSpec[SN_TYPE(sn)].arity;
10311 }
10312
SrcNoteLength(jssrcnote * sn)10313 JS_FRIEND_API unsigned js::SrcNoteLength(jssrcnote* sn) {
10314 unsigned arity;
10315 jssrcnote* base;
10316
10317 arity = SrcNoteArity(sn);
10318 for (base = sn++; arity; sn++, arity--) {
10319 if (*sn & SN_4BYTE_OFFSET_FLAG) sn += 3;
10320 }
10321 return sn - base;
10322 }
10323
GetSrcNoteOffset(jssrcnote * sn,unsigned which)10324 JS_FRIEND_API ptrdiff_t js::GetSrcNoteOffset(jssrcnote* sn, unsigned which) {
10325 /* Find the offset numbered which (i.e., skip exactly which offsets). */
10326 MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
10327 MOZ_ASSERT((int)which < SrcNoteArity(sn));
10328 for (sn++; which; sn++, which--) {
10329 if (*sn & SN_4BYTE_OFFSET_FLAG) sn += 3;
10330 }
10331 if (*sn & SN_4BYTE_OFFSET_FLAG) {
10332 return (ptrdiff_t)(((uint32_t)(sn[0] & SN_4BYTE_OFFSET_MASK) << 24) |
10333 (sn[1] << 16) | (sn[2] << 8) | sn[3]);
10334 }
10335 return (ptrdiff_t)*sn;
10336 }
10337