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