Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /*
8 : * JS bytecode generation.
9 : */
10 :
11 : #include "frontend/BytecodeEmitter.h"
12 :
13 : #include "mozilla/ArrayUtils.h"
14 : #include "mozilla/DebugOnly.h"
15 : #include "mozilla/FloatingPoint.h"
16 : #include "mozilla/Maybe.h"
17 : #include "mozilla/PodOperations.h"
18 :
19 : #include <string.h>
20 :
21 : #include "jsapi.h"
22 : #include "jsnum.h"
23 : #include "jstypes.h"
24 : #include "jsutil.h"
25 :
26 : #include "ds/Nestable.h"
27 : #include "frontend/Parser.h"
28 : #include "vm/BytecodeUtil.h"
29 : #include "vm/Debugger.h"
30 : #include "vm/GeneratorObject.h"
31 : #include "vm/JSAtom.h"
32 : #include "vm/JSContext.h"
33 : #include "vm/JSFunction.h"
34 : #include "vm/JSScript.h"
35 : #include "vm/Stack.h"
36 : #include "wasm/AsmJS.h"
37 :
38 : #include "frontend/ParseNode-inl.h"
39 : #include "vm/EnvironmentObject-inl.h"
40 : #include "vm/JSAtom-inl.h"
41 : #include "vm/JSScript-inl.h"
42 : #include "vm/NativeObject-inl.h"
43 :
44 : using namespace js;
45 : using namespace js::gc;
46 : using namespace js::frontend;
47 :
48 : using mozilla::AssertedCast;
49 : using mozilla::DebugOnly;
50 : using mozilla::Maybe;
51 : using mozilla::Nothing;
52 : using mozilla::NumberEqualsInt32;
53 : using mozilla::NumberIsInt32;
54 : using mozilla::PodCopy;
55 : using mozilla::Some;
56 : using mozilla::Unused;
57 :
58 : class BreakableControl;
59 : class LabelControl;
60 : class LoopControl;
61 : class ForOfLoopControl;
62 : class TryFinallyControl;
63 :
64 : static bool
65 0 : ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn)
66 : {
67 : // The few node types listed below are exceptions to the usual
68 : // location-source-note-emitting code in BytecodeEmitter::emitTree().
69 : // Single-line `while` loops and C-style `for` loops require careful
70 : // handling to avoid strange stepping behavior.
71 : // Functions usually shouldn't have location information (bug 1431202).
72 :
73 0 : ParseNodeKind kind = pn->getKind();
74 0 : return kind == ParseNodeKind::While ||
75 0 : kind == ParseNodeKind::For ||
76 0 : kind == ParseNodeKind::Function;
77 : }
78 :
79 : // A cache that tracks Temporal Dead Zone (TDZ) checks, so that any use of a
80 : // lexical variable that's dominated by an earlier use, or by evaluation of its
81 : // declaration (which will initialize it, perhaps to |undefined|), doesn't have
82 : // to redundantly check that the lexical variable has been initialized
83 : //
84 : // Each basic block should have a TDZCheckCache in scope. Some NestableControl
85 : // subclasses contain a TDZCheckCache.
86 : //
87 : // When a scope containing lexical variables is entered, all such variables are
88 : // marked as CheckTDZ. When a lexical variable is accessed, its entry is
89 : // checked. If it's CheckTDZ, a JSOP_CHECKLEXICAL is emitted and then the
90 : // entry is marked DontCheckTDZ. If it's DontCheckTDZ, no check is emitted
91 : // because a prior check would have already failed. Finally, because
92 : // evaluating a lexical variable declaration initializes it (after any
93 : // initializer is evaluated), evaluating a lexical declaration marks its entry
94 : // as DontCheckTDZ.
95 147837 : class BytecodeEmitter::TDZCheckCache : public Nestable<BytecodeEmitter::TDZCheckCache>
96 : {
97 : PooledMapPtr<CheckTDZMap> cache_;
98 :
99 : MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
100 69579 : return cache_ || cache_.acquire(bce->cx);
101 : }
102 :
103 : public:
104 : explicit TDZCheckCache(BytecodeEmitter* bce)
105 74835 : : Nestable<TDZCheckCache>(&bce->innermostTDZCheckCache),
106 299340 : cache_(bce->cx->frontendCollectionPool())
107 : { }
108 :
109 : Maybe<MaybeCheckTDZ> needsTDZCheck(BytecodeEmitter* bce, JSAtom* name);
110 : MOZ_MUST_USE bool noteTDZCheck(BytecodeEmitter* bce, JSAtom* name, MaybeCheckTDZ check);
111 : };
112 :
113 3878 : class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl>
114 : {
115 : StatementKind kind_;
116 :
117 : // The innermost scope when this was pushed.
118 : EmitterScope* emitterScope_;
119 :
120 : protected:
121 : NestableControl(BytecodeEmitter* bce, StatementKind kind)
122 3878 : : Nestable<NestableControl>(&bce->innermostNestableControl),
123 : kind_(kind),
124 7756 : emitterScope_(bce->innermostEmitterScopeNoCheck())
125 : { }
126 :
127 : public:
128 : using Nestable<NestableControl>::enclosing;
129 : using Nestable<NestableControl>::findNearest;
130 :
131 : StatementKind kind() const {
132 : return kind_;
133 : }
134 :
135 : EmitterScope* emitterScope() const {
136 : return emitterScope_;
137 : }
138 :
139 : template <typename T>
140 : bool is() const;
141 :
142 : template <typename T>
143 5743 : T& as() {
144 1 : MOZ_ASSERT(this->is<T>());
145 5743 : return static_cast<T&>(*this);
146 : }
147 : };
148 :
149 : // Template specializations are disallowed in different namespaces; specialize
150 : // all the NestableControl subtypes up front.
151 : namespace js {
152 : namespace frontend {
153 :
154 : template <>
155 : bool
156 0 : BytecodeEmitter::NestableControl::is<BreakableControl>() const
157 : {
158 1 : return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
159 : }
160 :
161 : template <>
162 : bool
163 0 : BytecodeEmitter::NestableControl::is<LabelControl>() const
164 : {
165 1 : return kind_ == StatementKind::Label;
166 : }
167 :
168 : template <>
169 : bool
170 0 : BytecodeEmitter::NestableControl::is<LoopControl>() const
171 : {
172 1 : return StatementKindIsLoop(kind_);
173 : }
174 :
175 : template <>
176 : bool
177 0 : BytecodeEmitter::NestableControl::is<ForOfLoopControl>() const
178 : {
179 1407 : return kind_ == StatementKind::ForOfLoop;
180 : }
181 :
182 : template <>
183 : bool
184 0 : BytecodeEmitter::NestableControl::is<TryFinallyControl>() const
185 : {
186 0 : return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
187 : }
188 :
189 : } // namespace frontend
190 : } // namespace js
191 :
192 5608 : class BreakableControl : public BytecodeEmitter::NestableControl
193 : {
194 : public:
195 : // Offset of the last break.
196 : JumpList breaks;
197 :
198 2804 : BreakableControl(BytecodeEmitter* bce, StatementKind kind)
199 8412 : : NestableControl(bce, kind)
200 : {
201 5608 : MOZ_ASSERT(is<BreakableControl>());
202 2804 : }
203 :
204 : MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce) {
205 2561 : return bce->emitJumpTargetAndPatch(breaks);
206 : }
207 : };
208 :
209 0 : class LabelControl : public BreakableControl
210 : {
211 : RootedAtom label_;
212 :
213 : // The code offset when this was pushed. Used for effectfulness checking.
214 : ptrdiff_t startOffset_;
215 :
216 : public:
217 : LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
218 0 : : BreakableControl(bce, StatementKind::Label),
219 : label_(bce->cx, label),
220 0 : startOffset_(startOffset)
221 : { }
222 :
223 : HandleAtom label() const {
224 0 : return label_;
225 : }
226 :
227 : ptrdiff_t startOffset() const {
228 : return startOffset_;
229 : }
230 : };
231 :
232 7221 : class LoopControl : public BreakableControl
233 : {
234 : // Loops' children are emitted in dominance order, so they can always
235 : // have a TDZCheckCache.
236 : BytecodeEmitter::TDZCheckCache tdzCache_;
237 :
238 : // Stack depth when this loop was pushed on the control stack.
239 : int32_t stackDepth_;
240 :
241 : // The loop nesting depth. Used as a hint to Ion.
242 : uint32_t loopDepth_;
243 :
244 : // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
245 : bool canIonOsr_;
246 :
247 : public:
248 : // The target of continue statement jumps, e.g., the update portion of a
249 : // for(;;) loop.
250 : JumpTarget continueTarget;
251 :
252 : // Offset of the last continue in the loop.
253 : JumpList continues;
254 :
255 2407 : LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
256 0 : : BreakableControl(bce, loopKind),
257 : tdzCache_(bce),
258 7221 : continueTarget({ -1 })
259 : {
260 0 : MOZ_ASSERT(is<LoopControl>());
261 :
262 2407 : LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
263 :
264 0 : stackDepth_ = bce->stackDepth;
265 2407 : loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
266 :
267 : int loopSlots;
268 2407 : if (loopKind == StatementKind::Spread) {
269 : // The iterator next method, the iterator, the result array, and
270 : // the current array index are on the stack.
271 : loopSlots = 4;
272 0 : } else if (loopKind == StatementKind::ForOfLoop) {
273 : // The iterator next method, the iterator, and the current value
274 : // are on the stack.
275 : loopSlots = 3;
276 0 : } else if (loopKind == StatementKind::ForInLoop) {
277 : // The iterator and the current value are on the stack.
278 : loopSlots = 2;
279 : } else {
280 : // No additional loop values are on the stack.
281 910 : loopSlots = 0;
282 : }
283 :
284 2407 : MOZ_ASSERT(loopSlots <= stackDepth_);
285 :
286 2407 : if (enclosingLoop) {
287 428 : canIonOsr_ = (enclosingLoop->canIonOsr_ &&
288 214 : stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
289 : } else {
290 0 : canIonOsr_ = stackDepth_ == loopSlots;
291 : }
292 2407 : }
293 :
294 : uint32_t loopDepth() const {
295 : return loopDepth_;
296 : }
297 :
298 : bool canIonOsr() const {
299 : return canIonOsr_;
300 : }
301 :
302 1114 : MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce) {
303 : // This doesn't pop stack values, nor handle any other controls.
304 : // Should be called on the toplevel of the loop.
305 0 : MOZ_ASSERT(bce->stackDepth == stackDepth_);
306 0 : MOZ_ASSERT(bce->innermostNestableControl == this);
307 :
308 0 : if (!bce->newSrcNote(SRC_BREAK))
309 : return false;
310 1114 : if (!bce->emitJump(JSOP_GOTO, &breaks))
311 : return false;
312 :
313 0 : return true;
314 : }
315 :
316 2164 : MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce) {
317 2164 : MOZ_ASSERT(continueTarget.offset != -1);
318 4328 : if (!patchBreaks(bce))
319 : return false;
320 2164 : bce->patchJumpsToTarget(continues, continueTarget);
321 0 : return true;
322 : }
323 : };
324 :
325 0 : class TryFinallyControl : public BytecodeEmitter::NestableControl
326 : {
327 : bool emittingSubroutine_;
328 :
329 : public:
330 : // The subroutine when emitting a finally block.
331 : JumpList gosubs;
332 :
333 1074 : TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
334 1074 : : NestableControl(bce, kind),
335 3222 : emittingSubroutine_(false)
336 : {
337 2148 : MOZ_ASSERT(is<TryFinallyControl>());
338 1074 : }
339 :
340 : void setEmittingSubroutine() {
341 0 : emittingSubroutine_ = true;
342 : }
343 :
344 : bool emittingSubroutine() const {
345 : return emittingSubroutine_;
346 : }
347 : };
348 :
349 : static inline void
350 : MarkAllBindingsClosedOver(LexicalScope::Data& data)
351 : {
352 : TrailingNamesArray& names = data.trailingNames;
353 5671 : for (uint32_t i = 0; i < data.length; i++)
354 10955 : names[i] = BindingName(names[i].name(), true);
355 : }
356 :
357 : // A scope that introduces bindings.
358 69366 : class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterScope>
359 : {
360 : // The cache of bound names that may be looked up in the
361 : // scope. Initially populated as the set of names this scope binds. As
362 : // names are looked up in enclosing scopes, they are cached on the
363 : // current scope.
364 : PooledMapPtr<NameLocationMap> nameCache_;
365 :
366 : // If this scope's cache does not include free names, such as the
367 : // global scope, the NameLocation to return.
368 : Maybe<NameLocation> fallbackFreeNameLocation_;
369 :
370 : // True if there is a corresponding EnvironmentObject on the environment
371 : // chain, false if all bindings are stored in frame slots on the stack.
372 : bool hasEnvironment_;
373 :
374 : // The number of enclosing environments. Used for error checking.
375 : uint8_t environmentChainLength_;
376 :
377 : // The next usable slot on the frame for not-closed over bindings.
378 : //
379 : // The initial frame slot when assigning slots to bindings is the
380 : // enclosing scope's nextFrameSlot. For the first scope in a frame,
381 : // the initial frame slot is 0.
382 : uint32_t nextFrameSlot_;
383 :
384 : // The index in the BytecodeEmitter's interned scope vector, otherwise
385 : // ScopeNote::NoScopeIndex.
386 : uint32_t scopeIndex_;
387 :
388 : // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
389 : // block scope note list. Otherwise ScopeNote::NoScopeNote.
390 : uint32_t noteIndex_;
391 :
392 : MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
393 23123 : return nameCache_.acquire(bce->cx);
394 : }
395 :
396 : template <typename BindingIter>
397 0 : MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi) {
398 0 : if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
399 37330 : bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT)
400 : {
401 0 : bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
402 0 : return false;
403 : }
404 : return true;
405 : }
406 :
407 0 : MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce) {
408 : uint32_t hops;
409 22714 : if (EmitterScope* emitterScope = enclosing(&bce))
410 21901 : hops = emitterScope->environmentChainLength_;
411 : else
412 0 : hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
413 :
414 0 : if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
415 0 : bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
416 0 : return false;
417 : }
418 :
419 0 : environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
420 22714 : return true;
421 : }
422 :
423 0 : void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi) {
424 0 : nextFrameSlot_ = bi.nextFrameSlot();
425 0 : if (nextFrameSlot_ > bce->maxFixedSlots)
426 0 : bce->maxFixedSlots = nextFrameSlot_;
427 0 : MOZ_ASSERT_IF(bce->sc->isFunctionBox() &&
428 : (bce->sc->asFunctionBox()->isGenerator() ||
429 : bce->sc->asFunctionBox()->isAsync()),
430 : bce->maxFixedSlots == 0);
431 19648 : }
432 :
433 0 : MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, JSAtom* name, NameLocation loc) {
434 0 : NameLocationMap& cache = *nameCache_;
435 0 : NameLocationMap::AddPtr p = cache.lookupForAdd(name);
436 0 : MOZ_ASSERT(!p);
437 59923 : if (!cache.add(p, name, loc)) {
438 0 : ReportOutOfMemory(bce->cx);
439 0 : return false;
440 : }
441 : return true;
442 : }
443 :
444 0 : Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce, JSAtom* name) {
445 955346 : if (NameLocationMap::Ptr p = nameCache_->lookup(name))
446 300287 : return Some(p->value().wrapped);
447 194525 : if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name))
448 17125 : return fallbackFreeNameLocation_;
449 : return Nothing();
450 : }
451 :
452 : friend bool BytecodeEmitter::needsImplicitThis();
453 :
454 : EmitterScope* enclosing(BytecodeEmitter** bce) const {
455 : // There is an enclosing scope with access to the same frame.
456 117413 : if (EmitterScope* inFrame = enclosingInFrame())
457 : return inFrame;
458 :
459 : // We are currently compiling the enclosing script, look in the
460 : // enclosing BCE.
461 55013 : if ((*bce)->parent) {
462 52406 : *bce = (*bce)->parent;
463 0 : return (*bce)->innermostEmitterScopeNoCheck();
464 : }
465 :
466 : return nullptr;
467 : }
468 :
469 23123 : Scope* enclosingScope(BytecodeEmitter* bce) const {
470 23123 : if (EmitterScope* es = enclosing(&bce))
471 21902 : return es->scope(bce);
472 :
473 : // The enclosing script is already compiled or the current script is the
474 : // global script.
475 1221 : return bce->sc->compilationEnclosingScope();
476 : }
477 :
478 : static bool nameCanBeFree(BytecodeEmitter* bce, JSAtom* name) {
479 : // '.generator' cannot be accessed by name.
480 51375 : return name != bce->cx->names().dotGenerator;
481 : }
482 :
483 : static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops);
484 : NameLocation searchAndCache(BytecodeEmitter* bce, JSAtom* name);
485 :
486 : template <typename ScopeCreator>
487 : MOZ_MUST_USE bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
488 : template <typename ScopeCreator>
489 : MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope);
490 : MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
491 :
492 : MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
493 : uint32_t slotEnd);
494 :
495 : public:
496 : explicit EmitterScope(BytecodeEmitter* bce)
497 23123 : : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
498 23123 : nameCache_(bce->cx->frontendCollectionPool()),
499 : hasEnvironment_(false),
500 : environmentChainLength_(0),
501 : nextFrameSlot_(0),
502 : scopeIndex_(ScopeNote::NoScopeIndex),
503 115615 : noteIndex_(ScopeNote::NoScopeNoteIndex)
504 : { }
505 :
506 : void dump(BytecodeEmitter* bce);
507 :
508 : MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
509 : Handle<LexicalScope::Data*> bindings);
510 : MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
511 : MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
512 : MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox);
513 : MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
514 : MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc);
515 : MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
516 : MOZ_MUST_USE bool enterModule(BytecodeEmitter* module, ModuleSharedContext* modulesc);
517 : MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce);
518 : MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce);
519 :
520 : MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false);
521 :
522 83033 : uint32_t index() const {
523 83033 : MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, "Did you forget to intern a Scope?");
524 83033 : return scopeIndex_;
525 : }
526 :
527 : uint32_t noteIndex() const {
528 : return noteIndex_;
529 : }
530 :
531 67311 : Scope* scope(const BytecodeEmitter* bce) const {
532 201935 : return bce->scopeList.vector[index()];
533 : }
534 :
535 : bool hasEnvironment() const {
536 : return hasEnvironment_;
537 : }
538 :
539 : // The first frame slot used.
540 : uint32_t frameSlotStart() const {
541 9664 : if (EmitterScope* inFrame = enclosingInFrame())
542 9664 : return inFrame->nextFrameSlot_;
543 : return 0;
544 : }
545 :
546 : // The last frame slot used + 1.
547 : uint32_t frameSlotEnd() const {
548 : return nextFrameSlot_;
549 : }
550 :
551 : EmitterScope* enclosingInFrame() const {
552 244032 : return Nestable<EmitterScope>::enclosing();
553 : }
554 :
555 1 : NameLocation lookup(BytecodeEmitter* bce, JSAtom* name) {
556 377147 : if (Maybe<NameLocation> loc = lookupInCache(bce, name))
557 1 : return *loc;
558 1 : return searchAndCache(bce, name);
559 : }
560 :
561 : Maybe<NameLocation> locationBoundInScope(JSAtom* name, EmitterScope* target);
562 : };
563 :
564 : void
565 0 : BytecodeEmitter::EmitterScope::dump(BytecodeEmitter* bce)
566 : {
567 0 : fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce)->kind()), this);
568 :
569 0 : for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
570 0 : const NameLocation& l = r.front().value();
571 :
572 0 : JSAutoByteString bytes;
573 0 : if (!AtomToPrintableString(bce->cx, r.front().key(), &bytes))
574 0 : return;
575 0 : if (l.kind() != NameLocation::Kind::Dynamic)
576 0 : fprintf(stdout, " %s %s ", BindingKindString(l.bindingKind()), bytes.ptr());
577 : else
578 0 : fprintf(stdout, " %s ", bytes.ptr());
579 :
580 0 : switch (l.kind()) {
581 : case NameLocation::Kind::Dynamic:
582 0 : fprintf(stdout, "dynamic\n");
583 : break;
584 : case NameLocation::Kind::Global:
585 0 : fprintf(stdout, "global\n");
586 : break;
587 : case NameLocation::Kind::Intrinsic:
588 0 : fprintf(stdout, "intrinsic\n");
589 : break;
590 : case NameLocation::Kind::NamedLambdaCallee:
591 0 : fprintf(stdout, "named lambda callee\n");
592 : break;
593 : case NameLocation::Kind::Import:
594 0 : fprintf(stdout, "import\n");
595 : break;
596 : case NameLocation::Kind::ArgumentSlot:
597 0 : fprintf(stdout, "arg slot=%u\n", l.argumentSlot());
598 : break;
599 : case NameLocation::Kind::FrameSlot:
600 0 : fprintf(stdout, "frame slot=%u\n", l.frameSlot());
601 : break;
602 : case NameLocation::Kind::EnvironmentCoordinate:
603 0 : fprintf(stdout, "environment hops=%u slot=%u\n",
604 0 : l.environmentCoordinate().hops(), l.environmentCoordinate().slot());
605 0 : break;
606 : case NameLocation::Kind::DynamicAnnexBVar:
607 0 : fprintf(stdout, "dynamic annex b var\n");
608 : break;
609 : }
610 : }
611 :
612 0 : fprintf(stdout, "\n");
613 : }
614 :
615 : template <typename ScopeCreator>
616 : bool
617 23123 : BytecodeEmitter::EmitterScope::internScope(BytecodeEmitter* bce, ScopeCreator createScope)
618 : {
619 46246 : RootedScope enclosing(bce->cx, enclosingScope(bce));
620 0 : Scope* scope = createScope(bce->cx, enclosing);
621 0 : if (!scope)
622 : return false;
623 23123 : hasEnvironment_ = scope->hasEnvironment();
624 46246 : scopeIndex_ = bce->scopeList.length();
625 46246 : return bce->scopeList.append(scope);
626 : }
627 :
628 : template <typename ScopeCreator>
629 : bool
630 0 : BytecodeEmitter::EmitterScope::internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope)
631 : {
632 0 : MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX, "There can be only one body scope");
633 0 : bce->bodyScopeIndex = bce->scopeList.length();
634 13449 : return internScope(bce, createScope);
635 : }
636 :
637 : bool
638 0 : BytecodeEmitter::EmitterScope::appendScopeNote(BytecodeEmitter* bce)
639 : {
640 0 : MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),
641 : "Scope notes are not needed for body-level scopes.");
642 16888 : noteIndex_ = bce->scopeNoteList.length();
643 16888 : return bce->scopeNoteList.append(index(), bce->offset(), bce->inPrologue(),
644 1 : enclosingInFrame() ? enclosingInFrame()->noteIndex()
645 1 : : ScopeNote::NoScopeNoteIndex);
646 : }
647 :
648 : #ifdef DEBUG
649 : static bool
650 573 : NameIsOnEnvironment(Scope* scope, JSAtom* name)
651 : {
652 1 : for (BindingIter bi(scope); bi; bi++) {
653 : // If found, the name must already be on the environment or an import,
654 : // or else there is a bug in the closed-over name analysis in the
655 : // Parser.
656 0 : if (bi.name() == name) {
657 0 : BindingLocation::Kind kind = bi.location().kind();
658 :
659 0 : if (bi.hasArgumentSlot()) {
660 0 : JSScript* script = scope->as<FunctionScope>().script();
661 0 : if (!script->strict() && !script->functionHasParameterExprs()) {
662 : // Check for duplicate positional formal parameters.
663 0 : for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
664 0 : if (bi2.name() == name)
665 0 : kind = bi2.location().kind();
666 : }
667 : }
668 : }
669 :
670 0 : return kind == BindingLocation::Kind::Global ||
671 0 : kind == BindingLocation::Kind::Environment ||
672 0 : kind == BindingLocation::Kind::Import;
673 : }
674 : }
675 :
676 : // If not found, assume it's on the global or dynamically accessed.
677 0 : return true;
678 : }
679 : #endif
680 :
681 : /* static */ NameLocation
682 0 : BytecodeEmitter::EmitterScope::searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops)
683 : {
684 1 : for (ScopeIter si(scope); si; si++) {
685 1 : MOZ_ASSERT(NameIsOnEnvironment(si.scope(), name));
686 :
687 573 : bool hasEnv = si.hasSyntacticEnvironment();
688 :
689 1 : switch (si.kind()) {
690 : case ScopeKind::Function:
691 0 : if (hasEnv) {
692 0 : JSScript* script = si.scope()->as<FunctionScope>().script();
693 0 : if (script->funHasExtensibleScope())
694 1 : return NameLocation::Dynamic();
695 :
696 0 : for (BindingIter bi(si.scope()); bi; bi++) {
697 0 : if (bi.name() != name)
698 0 : continue;
699 :
700 0 : BindingLocation bindLoc = bi.location();
701 0 : if (bi.hasArgumentSlot() &&
702 0 : !script->strict() &&
703 0 : !script->functionHasParameterExprs())
704 : {
705 : // Check for duplicate positional formal parameters.
706 0 : for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
707 0 : if (bi2.name() == name)
708 0 : bindLoc = bi2.location();
709 : }
710 : }
711 :
712 0 : MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
713 0 : return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
714 : }
715 : }
716 : break;
717 :
718 : case ScopeKind::FunctionBodyVar:
719 : case ScopeKind::ParameterExpressionVar:
720 : case ScopeKind::Lexical:
721 : case ScopeKind::NamedLambda:
722 : case ScopeKind::StrictNamedLambda:
723 : case ScopeKind::SimpleCatch:
724 : case ScopeKind::Catch:
725 0 : if (hasEnv) {
726 0 : for (BindingIter bi(si.scope()); bi; bi++) {
727 0 : if (bi.name() != name)
728 0 : continue;
729 :
730 : // The name must already have been marked as closed
731 : // over. If this assertion is hit, there is a bug in the
732 : // name analysis.
733 0 : BindingLocation bindLoc = bi.location();
734 0 : MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
735 0 : return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
736 : }
737 : }
738 : break;
739 :
740 : case ScopeKind::Module:
741 0 : if (hasEnv) {
742 0 : for (BindingIter bi(si.scope()); bi; bi++) {
743 0 : if (bi.name() != name)
744 0 : continue;
745 :
746 0 : BindingLocation bindLoc = bi.location();
747 :
748 : // Imports are on the environment but are indirect
749 : // bindings and must be accessed dynamically instead of
750 : // using an EnvironmentCoordinate.
751 0 : if (bindLoc.kind() == BindingLocation::Kind::Import) {
752 0 : MOZ_ASSERT(si.kind() == ScopeKind::Module);
753 0 : return NameLocation::Import();
754 : }
755 :
756 0 : MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
757 0 : return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
758 : }
759 : }
760 : break;
761 :
762 : case ScopeKind::Eval:
763 : case ScopeKind::StrictEval:
764 : // As an optimization, if the eval doesn't have its own var
765 : // environment and its immediate enclosing scope is a global
766 : // scope, all accesses are global.
767 0 : if (!hasEnv && si.scope()->enclosing()->is<GlobalScope>())
768 0 : return NameLocation::Global(BindingKind::Var);
769 : return NameLocation::Dynamic();
770 :
771 : case ScopeKind::Global:
772 1 : return NameLocation::Global(BindingKind::Var);
773 :
774 : case ScopeKind::With:
775 : case ScopeKind::NonSyntactic:
776 : return NameLocation::Dynamic();
777 :
778 : case ScopeKind::WasmInstance:
779 : case ScopeKind::WasmFunction:
780 0 : MOZ_CRASH("No direct eval inside wasm functions");
781 : }
782 :
783 0 : if (hasEnv) {
784 0 : MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
785 0 : hops++;
786 : }
787 : }
788 :
789 0 : MOZ_CRASH("Malformed scope chain");
790 : }
791 :
792 : NameLocation
793 41459 : BytecodeEmitter::EmitterScope::searchAndCache(BytecodeEmitter* bce, JSAtom* name)
794 : {
795 82917 : Maybe<NameLocation> loc;
796 0 : uint8_t hops = hasEnvironment() ? 1 : 0;
797 0 : DebugOnly<bool> inCurrentScript = enclosingInFrame();
798 :
799 : // Start searching in the current compilation.
800 0 : for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) {
801 0 : loc = es->lookupInCache(bce, name);
802 71003 : if (loc) {
803 40886 : if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate)
804 8422 : *loc = loc->addHops(hops);
805 : break;
806 : }
807 :
808 0 : if (es->hasEnvironment())
809 0 : hops++;
810 :
811 : #ifdef DEBUG
812 30117 : if (!es->enclosingInFrame())
813 34362 : inCurrentScript = false;
814 : #endif
815 : }
816 :
817 : // If the name is not found in the current compilation, walk the Scope
818 : // chain encompassing the compilation.
819 41460 : if (!loc) {
820 0 : inCurrentScript = false;
821 0 : loc = Some(searchInEnclosingScope(name, bce->sc->compilationEnclosingScope(), hops));
822 : }
823 :
824 : // Each script has its own frame. A free name that is accessed
825 : // from an inner script must not be a frame slot access. If this
826 : // assertion is hit, it is a bug in the free name analysis in the
827 : // parser.
828 41460 : MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot);
829 :
830 : // It is always correct to not cache the location. Ignore OOMs to make
831 : // lookups infallible.
832 0 : if (!putNameInCache(bce, name, *loc))
833 0 : bce->cx->recoverFromOutOfMemory();
834 :
835 82916 : return *loc;
836 : }
837 :
838 : Maybe<NameLocation>
839 16171 : BytecodeEmitter::EmitterScope::locationBoundInScope(JSAtom* name, EmitterScope* target)
840 : {
841 : // The target scope must be an intra-frame enclosing scope of this
842 : // one. Count the number of extra hops to reach it.
843 0 : uint8_t extraHops = 0;
844 0 : for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
845 1590 : if (es->hasEnvironment())
846 0 : extraHops++;
847 : }
848 :
849 : // Caches are prepopulated with bound names. So if the name is bound in a
850 : // particular scope, it must already be in the cache. Furthermore, don't
851 : // consult the fallback location as we only care about binding names.
852 0 : Maybe<NameLocation> loc;
853 64684 : if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) {
854 16080 : NameLocation l = p->value().wrapped;
855 16081 : if (l.kind() == NameLocation::Kind::EnvironmentCoordinate)
856 13808 : loc = Some(l.addHops(extraHops));
857 : else
858 22956 : loc = Some(l);
859 : }
860 16171 : return loc;
861 : }
862 :
863 : bool
864 10013 : BytecodeEmitter::EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
865 : uint32_t slotEnd)
866 : {
867 : // Lexical bindings throw ReferenceErrors if they are used before
868 : // initialization. See ES6 8.1.1.1.6.
869 : //
870 : // For completeness, lexical bindings are initialized in ES6 by calling
871 : // InitializeBinding, after which touching the binding will no longer
872 : // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
873 : // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
874 10013 : if (slotStart != slotEnd) {
875 8147 : if (!bce->emit1(JSOP_UNINITIALIZED))
876 : return false;
877 1 : for (uint32_t slot = slotStart; slot < slotEnd; slot++) {
878 12510 : if (!bce->emitLocalOp(JSOP_INITLEXICAL, slot))
879 : return false;
880 : }
881 8147 : if (!bce->emit1(JSOP_POP))
882 : return false;
883 : }
884 :
885 : return true;
886 : }
887 :
888 : bool
889 0 : BytecodeEmitter::EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce)
890 : {
891 2440 : return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
892 : }
893 :
894 : bool
895 8385 : BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
896 : Handle<LexicalScope::Data*> bindings)
897 : {
898 8385 : MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
899 8385 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
900 :
901 8385 : if (!ensureCache(bce))
902 : return false;
903 :
904 : // Marks all names as closed over if the context requires it. This
905 : // cannot be done in the Parser as we may not know if the context requires
906 : // all bindings to be closed over until after parsing is finished. For
907 : // example, legacy generators require all bindings to be closed over but
908 : // it is unknown if a function is a legacy generator until the first
909 : // 'yield' expression is parsed.
910 : //
911 : // This is not a problem with other scopes, as all other scopes with
912 : // bindings are body-level. At the time of their creation, whether or not
913 : // the context requires all bindings to be closed over is already known.
914 0 : if (bce->sc->allBindingsClosedOver())
915 1268 : MarkAllBindingsClosedOver(*bindings);
916 :
917 : // Resolve bindings.
918 8385 : TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
919 8385 : uint32_t firstFrameSlot = frameSlotStart();
920 8385 : BindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false);
921 0 : for (; bi; bi++) {
922 13665 : if (!checkSlotLimits(bce, bi))
923 0 : return false;
924 :
925 13665 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
926 13665 : if (!putNameInCache(bce, bi.name(), loc))
927 : return false;
928 :
929 0 : if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
930 : return false;
931 : }
932 :
933 8385 : updateFrameFixedSlots(bce, bi);
934 :
935 : // Create and intern the VM scope.
936 : auto createScope = [kind, bindings, firstFrameSlot](JSContext* cx,
937 : HandleScope enclosing)
938 : {
939 : return LexicalScope::create(cx, kind, bindings, firstFrameSlot, enclosing);
940 16770 : };
941 8385 : if (!internScope(bce, createScope))
942 : return false;
943 :
944 8385 : if (ScopeKindIsInBody(kind) && hasEnvironment()) {
945 : // After interning the VM scope we can get the scope index.
946 1906 : if (!bce->emitInternedScopeOp(index(), JSOP_PUSHLEXICALENV))
947 : return false;
948 : }
949 :
950 : // Lexical scopes need notes to be mapped from a pc.
951 8385 : if (!appendScopeNote(bce))
952 : return false;
953 :
954 : // Put frame slots in TDZ. Environment slots are poisoned during
955 : // environment creation.
956 : //
957 : // This must be done after appendScopeNote to be considered in the extent
958 : // of the scope.
959 0 : if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd()))
960 : return false;
961 :
962 8385 : return checkEnvironmentChainLength(bce);
963 : }
964 :
965 : bool
966 0 : BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
967 : {
968 1230 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
969 2460 : MOZ_ASSERT(funbox->namedLambdaBindings());
970 :
971 0 : if (!ensureCache(bce))
972 : return false;
973 :
974 : // See comment in enterLexical about allBindingsClosedOver.
975 0 : if (funbox->allBindingsClosedOver())
976 0 : MarkAllBindingsClosedOver(*funbox->namedLambdaBindings());
977 :
978 0 : BindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT, /* isNamedLambda = */ true);
979 1230 : MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee);
980 :
981 : // The lambda name, if not closed over, is accessed via JSOP_CALLEE and
982 : // not a frame slot. Do not update frame slot information.
983 0 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
984 0 : if (!putNameInCache(bce, bi.name(), loc))
985 : return false;
986 :
987 0 : bi++;
988 1230 : MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope");
989 :
990 1230 : auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
991 : ScopeKind scopeKind =
992 2460 : funbox->strict() ? ScopeKind::StrictNamedLambda : ScopeKind::NamedLambda;
993 0 : return LexicalScope::create(cx, scopeKind, funbox->namedLambdaBindings(),
994 2460 : LOCALNO_LIMIT, enclosing);
995 0 : };
996 1230 : if (!internScope(bce, createScope))
997 : return false;
998 :
999 1230 : return checkEnvironmentChainLength(bce);
1000 : }
1001 :
1002 : bool
1003 0 : BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
1004 : {
1005 0 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1006 :
1007 0 : if (!ensureCache(bce))
1008 : return false;
1009 :
1010 : // Parameter expressions var scopes have no pre-set bindings and are
1011 : // always extensible, as they are needed for eval.
1012 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1013 :
1014 : // Create and intern the VM scope.
1015 0 : uint32_t firstFrameSlot = frameSlotStart();
1016 0 : auto createScope = [firstFrameSlot](JSContext* cx, HandleScope enclosing) {
1017 0 : return VarScope::create(cx, ScopeKind::ParameterExpressionVar,
1018 : /* data = */ nullptr, firstFrameSlot,
1019 : /* needsEnvironment = */ true, enclosing);
1020 0 : };
1021 0 : if (!internScope(bce, createScope))
1022 : return false;
1023 :
1024 0 : MOZ_ASSERT(hasEnvironment());
1025 0 : if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1026 : return false;
1027 :
1028 : // The extra var scope needs a note to be mapped from a pc.
1029 0 : if (!appendScopeNote(bce))
1030 : return false;
1031 :
1032 0 : return checkEnvironmentChainLength(bce);
1033 : }
1034 :
1035 : bool
1036 0 : BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
1037 : {
1038 0 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1039 :
1040 : // If there are parameter expressions, there is an extra var scope.
1041 0 : if (!funbox->hasExtraBodyVarScope())
1042 0 : bce->setVarEmitterScope(this);
1043 :
1044 0 : if (!ensureCache(bce))
1045 : return false;
1046 :
1047 : // Resolve body-level bindings, if there are any.
1048 13041 : auto bindings = funbox->functionScopeBindings();
1049 13041 : Maybe<uint32_t> lastLexicalSlot;
1050 13041 : if (bindings) {
1051 22474 : NameLocationMap& cache = *nameCache_;
1052 :
1053 0 : BindingIter bi(*bindings, funbox->hasParameterExprs);
1054 0 : for (; bi; bi++) {
1055 0 : if (!checkSlotLimits(bce, bi))
1056 0 : return false;
1057 :
1058 23549 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1059 47099 : NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
1060 :
1061 : // The only duplicate bindings that occur are simple formal
1062 : // parameters, in which case the last position counts, so update the
1063 : // location.
1064 23550 : if (p) {
1065 0 : MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
1066 0 : MOZ_ASSERT(!funbox->hasDestructuringArgs);
1067 0 : MOZ_ASSERT(!funbox->hasRest());
1068 0 : p->value() = loc;
1069 0 : continue;
1070 : }
1071 :
1072 47100 : if (!cache.add(p, bi.name(), loc)) {
1073 0 : ReportOutOfMemory(bce->cx);
1074 0 : return false;
1075 : }
1076 : }
1077 :
1078 11237 : updateFrameFixedSlots(bce, bi);
1079 : } else {
1080 0 : nextFrameSlot_ = 0;
1081 : }
1082 :
1083 : // If the function's scope may be extended at runtime due to sloppy direct
1084 : // eval and there is no extra var scope, any names beyond the function
1085 : // scope must be accessed dynamically as we don't know if the name will
1086 : // become a 'var' binding due to direct eval.
1087 0 : if (!funbox->hasParameterExprs && funbox->hasExtensibleScope())
1088 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1089 :
1090 : // In case of parameter expressions, the parameters are lexical
1091 : // bindings and have TDZ.
1092 13041 : if (funbox->hasParameterExprs && nextFrameSlot_) {
1093 0 : uint32_t paramFrameSlotEnd = 0;
1094 2812 : for (BindingIter bi(*bindings, true); bi; bi++) {
1095 2470 : if (!BindingKindIsLexical(bi.kind()))
1096 : break;
1097 :
1098 0 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1099 0 : if (loc.kind() == NameLocation::Kind::FrameSlot) {
1100 0 : MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot());
1101 0 : paramFrameSlotEnd = loc.frameSlot() + 1;
1102 : }
1103 : }
1104 :
1105 0 : if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd))
1106 : return false;
1107 : }
1108 :
1109 : // Create and intern the VM scope.
1110 26082 : auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
1111 39123 : RootedFunction fun(cx, funbox->function());
1112 0 : return FunctionScope::create(cx, funbox->functionScopeBindings(),
1113 13041 : funbox->hasParameterExprs,
1114 0 : funbox->needsCallObjectRegardlessOfBindings(),
1115 0 : fun, enclosing);
1116 13041 : };
1117 0 : if (!internBodyScope(bce, createScope))
1118 : return false;
1119 :
1120 13041 : return checkEnvironmentChainLength(bce);
1121 : }
1122 :
1123 : bool
1124 59 : BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox)
1125 : {
1126 59 : MOZ_ASSERT(funbox->hasParameterExprs);
1127 0 : MOZ_ASSERT(funbox->extraVarScopeBindings() ||
1128 : funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
1129 0 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1130 :
1131 : // The extra var scope is never popped once it's entered. It replaces the
1132 : // function scope as the var emitter scope.
1133 59 : bce->setVarEmitterScope(this);
1134 :
1135 0 : if (!ensureCache(bce))
1136 : return false;
1137 :
1138 : // Resolve body-level bindings, if there are any.
1139 0 : uint32_t firstFrameSlot = frameSlotStart();
1140 118 : if (auto bindings = funbox->extraVarScopeBindings()) {
1141 0 : BindingIter bi(*bindings, firstFrameSlot);
1142 258 : for (; bi; bi++) {
1143 116 : if (!checkSlotLimits(bce, bi))
1144 0 : return false;
1145 :
1146 116 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1147 116 : if (!putNameInCache(bce, bi.name(), loc))
1148 : return false;
1149 : }
1150 :
1151 26 : updateFrameFixedSlots(bce, bi);
1152 : } else {
1153 0 : nextFrameSlot_ = firstFrameSlot;
1154 : }
1155 :
1156 : // If the extra var scope may be extended at runtime due to sloppy
1157 : // direct eval, any names beyond the var scope must be accessed
1158 : // dynamically as we don't know if the name will become a 'var' binding
1159 : // due to direct eval.
1160 59 : if (funbox->hasExtensibleScope())
1161 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1162 :
1163 : // Create and intern the VM scope.
1164 118 : auto createScope = [funbox, firstFrameSlot](JSContext* cx, HandleScope enclosing) {
1165 236 : return VarScope::create(cx, ScopeKind::FunctionBodyVar,
1166 : funbox->extraVarScopeBindings(), firstFrameSlot,
1167 0 : funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(),
1168 : enclosing);
1169 177 : };
1170 0 : if (!internScope(bce, createScope))
1171 : return false;
1172 :
1173 59 : if (hasEnvironment()) {
1174 38 : if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1175 : return false;
1176 : }
1177 :
1178 : // The extra var scope needs a note to be mapped from a pc.
1179 59 : if (!appendScopeNote(bce))
1180 : return false;
1181 :
1182 59 : return checkEnvironmentChainLength(bce);
1183 : }
1184 :
1185 : class DynamicBindingIter : public BindingIter
1186 : {
1187 : public:
1188 : explicit DynamicBindingIter(GlobalSharedContext* sc)
1189 831 : : BindingIter(*sc->bindings)
1190 : { }
1191 :
1192 0 : explicit DynamicBindingIter(EvalSharedContext* sc)
1193 0 : : BindingIter(*sc->bindings, /* strict = */ false)
1194 : {
1195 0 : MOZ_ASSERT(!sc->strict());
1196 0 : }
1197 :
1198 2472 : JSOp bindingOp() const {
1199 2472 : switch (kind()) {
1200 : case BindingKind::Var:
1201 : return JSOP_DEFVAR;
1202 : case BindingKind::Let:
1203 0 : return JSOP_DEFLET;
1204 : case BindingKind::Const:
1205 0 : return JSOP_DEFCONST;
1206 : default:
1207 0 : MOZ_CRASH("Bad BindingKind");
1208 : }
1209 : }
1210 : };
1211 :
1212 : bool
1213 390 : BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
1214 : {
1215 390 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1216 :
1217 390 : bce->setVarEmitterScope(this);
1218 :
1219 390 : if (!ensureCache(bce))
1220 : return false;
1221 :
1222 0 : if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
1223 : // In self-hosting, it is incorrect to consult the global scope because
1224 : // self-hosted scripts are cloned into their target compartments before
1225 : // they are run. Instead of Global, Intrinsic is used for all names.
1226 : //
1227 : // Intrinsic lookups are redirected to the special intrinsics holder
1228 : // in the global object, into which any missing values are cloned
1229 : // lazily upon first access.
1230 0 : fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic());
1231 :
1232 0 : auto createScope = [](JSContext* cx, HandleScope enclosing) {
1233 0 : MOZ_ASSERT(!enclosing);
1234 2 : return &cx->global()->emptyGlobalScope();
1235 : };
1236 1 : return internBodyScope(bce, createScope);
1237 : }
1238 :
1239 : // Resolve binding names and emit DEF{VAR,LET,CONST} prologue ops.
1240 0 : if (globalsc->bindings) {
1241 7187 : for (DynamicBindingIter bi(globalsc); bi; bi++) {
1242 3455 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1243 3455 : JSAtom* name = bi.name();
1244 3455 : if (!putNameInCache(bce, name, loc))
1245 0 : return false;
1246 :
1247 : // Define the name in the prologue. Do not emit DEFVAR for
1248 : // functions that we'll emit DEFFUN for.
1249 0 : if (bi.isTopLevelFunction())
1250 983 : continue;
1251 :
1252 2472 : if (!bce->emitAtomOp(name, bi.bindingOp()))
1253 : return false;
1254 : }
1255 : }
1256 :
1257 : // Note that to save space, we don't add free names to the cache for
1258 : // global scopes. They are assumed to be global vars in the syntactic
1259 : // global scope, dynamic accesses under non-syntactic global scope.
1260 389 : if (globalsc->scopeKind() == ScopeKind::Global)
1261 0 : fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1262 : else
1263 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1264 :
1265 0 : auto createScope = [globalsc](JSContext* cx, HandleScope enclosing) {
1266 389 : MOZ_ASSERT(!enclosing);
1267 0 : return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
1268 389 : };
1269 389 : return internBodyScope(bce, createScope);
1270 : }
1271 :
1272 : bool
1273 18 : BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
1274 : {
1275 0 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1276 :
1277 0 : bce->setVarEmitterScope(this);
1278 :
1279 0 : if (!ensureCache(bce))
1280 : return false;
1281 :
1282 : // For simplicity, treat all free name lookups in eval scripts as dynamic.
1283 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1284 :
1285 : // Create the `var` scope. Note that there is also a lexical scope, created
1286 : // separately in emitScript().
1287 18 : auto createScope = [evalsc](JSContext* cx, HandleScope enclosing) {
1288 36 : ScopeKind scopeKind = evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval;
1289 36 : return EvalScope::create(cx, scopeKind, evalsc->bindings, enclosing);
1290 18 : };
1291 18 : if (!internBodyScope(bce, createScope))
1292 : return false;
1293 :
1294 0 : if (hasEnvironment()) {
1295 0 : if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1296 : return false;
1297 : } else {
1298 : // Resolve binding names and emit DEFVAR prologue ops if we don't have
1299 : // an environment (i.e., a sloppy eval not in a parameter expression).
1300 : // Eval scripts always have their own lexical scope, but non-strict
1301 : // scopes may introduce 'var' bindings to the nearest var scope.
1302 : //
1303 : // TODO: We may optimize strict eval bindings in the future to be on
1304 : // the frame. For now, handle everything dynamically.
1305 0 : if (!hasEnvironment() && evalsc->bindings) {
1306 0 : for (DynamicBindingIter bi(evalsc); bi; bi++) {
1307 0 : MOZ_ASSERT(bi.bindingOp() == JSOP_DEFVAR);
1308 :
1309 0 : if (bi.isTopLevelFunction())
1310 : continue;
1311 :
1312 0 : if (!bce->emitAtomOp(bi.name(), JSOP_DEFVAR))
1313 0 : return false;
1314 : }
1315 : }
1316 :
1317 : // As an optimization, if the eval does not have its own var
1318 : // environment and is directly enclosed in a global scope, then all
1319 : // free name lookups are global.
1320 0 : if (scope(bce)->enclosing()->is<GlobalScope>())
1321 0 : fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1322 : }
1323 :
1324 : return true;
1325 : }
1326 :
1327 : bool
1328 0 : BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
1329 : {
1330 0 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1331 :
1332 0 : bce->setVarEmitterScope(this);
1333 :
1334 0 : if (!ensureCache(bce))
1335 : return false;
1336 :
1337 : // Resolve body-level bindings, if there are any.
1338 0 : TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
1339 0 : Maybe<uint32_t> firstLexicalFrameSlot;
1340 0 : if (ModuleScope::Data* bindings = modulesc->bindings) {
1341 : BindingIter bi(*bindings);
1342 0 : for (; bi; bi++) {
1343 0 : if (!checkSlotLimits(bce, bi))
1344 0 : return false;
1345 :
1346 0 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1347 0 : if (!putNameInCache(bce, bi.name(), loc))
1348 : return false;
1349 :
1350 0 : if (BindingKindIsLexical(bi.kind())) {
1351 0 : if (loc.kind() == NameLocation::Kind::FrameSlot && !firstLexicalFrameSlot)
1352 0 : firstLexicalFrameSlot = Some(loc.frameSlot());
1353 :
1354 0 : if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
1355 : return false;
1356 : }
1357 : }
1358 :
1359 0 : updateFrameFixedSlots(bce, bi);
1360 : } else {
1361 0 : nextFrameSlot_ = 0;
1362 : }
1363 :
1364 : // Modules are toplevel, so any free names are global.
1365 0 : fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1366 :
1367 : // Put lexical frame slots in TDZ. Environment slots are poisoned during
1368 : // environment creation.
1369 0 : if (firstLexicalFrameSlot) {
1370 0 : if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd()))
1371 : return false;
1372 : }
1373 :
1374 : // Create and intern the VM scope.
1375 0 : auto createScope = [modulesc](JSContext* cx, HandleScope enclosing) {
1376 0 : return ModuleScope::create(cx, modulesc->bindings, modulesc->module(), enclosing);
1377 0 : };
1378 0 : if (!internBodyScope(bce, createScope))
1379 : return false;
1380 :
1381 0 : return checkEnvironmentChainLength(bce);
1382 : }
1383 :
1384 : bool
1385 0 : BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
1386 : {
1387 0 : MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
1388 :
1389 0 : if (!ensureCache(bce))
1390 : return false;
1391 :
1392 : // 'with' make all accesses dynamic and unanalyzable.
1393 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1394 :
1395 : auto createScope = [](JSContext* cx, HandleScope enclosing) {
1396 : return WithScope::create(cx, enclosing);
1397 0 : };
1398 0 : if (!internScope(bce, createScope))
1399 : return false;
1400 :
1401 0 : if (!bce->emitInternedScopeOp(index(), JSOP_ENTERWITH))
1402 : return false;
1403 :
1404 0 : if (!appendScopeNote(bce))
1405 : return false;
1406 :
1407 0 : return checkEnvironmentChainLength(bce);
1408 : }
1409 :
1410 : bool
1411 28441 : BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
1412 : {
1413 : // If we aren't leaving the scope due to a non-local jump (e.g., break),
1414 : // we must be the innermost scope.
1415 0 : MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
1416 :
1417 28441 : ScopeKind kind = scope(bce)->kind();
1418 28441 : switch (kind) {
1419 : case ScopeKind::Lexical:
1420 : case ScopeKind::SimpleCatch:
1421 : case ScopeKind::Catch:
1422 13703 : if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV))
1423 : return false;
1424 : break;
1425 :
1426 : case ScopeKind::With:
1427 0 : if (!bce->emit1(JSOP_LEAVEWITH))
1428 : return false;
1429 : break;
1430 :
1431 : case ScopeKind::ParameterExpressionVar:
1432 0 : MOZ_ASSERT(hasEnvironment());
1433 0 : if (!bce->emit1(JSOP_POPVARENV))
1434 : return false;
1435 : break;
1436 :
1437 : case ScopeKind::Function:
1438 : case ScopeKind::FunctionBodyVar:
1439 : case ScopeKind::NamedLambda:
1440 : case ScopeKind::StrictNamedLambda:
1441 : case ScopeKind::Eval:
1442 : case ScopeKind::StrictEval:
1443 : case ScopeKind::Global:
1444 : case ScopeKind::NonSyntactic:
1445 : case ScopeKind::Module:
1446 : break;
1447 :
1448 : case ScopeKind::WasmInstance:
1449 : case ScopeKind::WasmFunction:
1450 0 : MOZ_CRASH("No wasm function scopes in JS");
1451 : }
1452 :
1453 : // Finish up the scope if we are leaving it in LIFO fashion.
1454 28440 : if (!nonLocal) {
1455 : // Popping scopes due to non-local jumps generate additional scope
1456 : // notes. See NonLocalExitControl::prepareForNonLocalJump.
1457 0 : if (ScopeKindIsInBody(kind)) {
1458 : // The extra function var scope is never popped once it's pushed,
1459 : // so its scope note extends until the end of any possible code.
1460 8444 : uint32_t offset = kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
1461 8444 : bce->scopeNoteList.recordEnd(noteIndex_, offset, bce->inPrologue());
1462 : }
1463 : }
1464 :
1465 : return true;
1466 : }
1467 :
1468 : Maybe<MaybeCheckTDZ>
1469 0 : BytecodeEmitter::TDZCheckCache::needsTDZCheck(BytecodeEmitter* bce, JSAtom* name)
1470 : {
1471 0 : if (!ensureCache(bce))
1472 : return Nothing();
1473 :
1474 116734 : CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
1475 38912 : if (p)
1476 0 : return Some(p->value().wrapped);
1477 :
1478 19386 : MaybeCheckTDZ rv = CheckTDZ;
1479 42351 : for (TDZCheckCache* it = enclosing(); it; it = it->enclosing()) {
1480 40229 : if (it->cache_) {
1481 99716 : if (CheckTDZMap::Ptr p2 = it->cache_->lookup(name)) {
1482 17264 : rv = p2->value();
1483 17264 : break;
1484 : }
1485 : }
1486 : }
1487 :
1488 0 : if (!cache_->add(p, name, rv)) {
1489 0 : ReportOutOfMemory(bce->cx);
1490 : return Nothing();
1491 : }
1492 :
1493 : return Some(rv);
1494 : }
1495 :
1496 : bool
1497 0 : BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
1498 : MaybeCheckTDZ check)
1499 : {
1500 30668 : if (!ensureCache(bce))
1501 : return false;
1502 :
1503 92004 : CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
1504 30668 : if (p) {
1505 14089 : MOZ_ASSERT(!check, "TDZ only needs to be checked once per binding per basic block.");
1506 14089 : p->value() = check;
1507 : } else {
1508 49737 : if (!cache_->add(p, name, check)) {
1509 0 : ReportOutOfMemory(bce->cx);
1510 0 : return false;
1511 : }
1512 : }
1513 :
1514 : return true;
1515 : }
1516 :
1517 : // Class for emitting bytecode for blocks like try-catch-finally.
1518 : //
1519 : // Usage: (check for the return value is omitted for simplicity)
1520 : //
1521 : // `try { try_block } catch (ex) { catch_block }`
1522 : // TryEmitter tryCatch(this, TryEmitter::Kind::TryCatch,
1523 : // TryEmitter::ControlKind::Syntactic);
1524 : // tryCatch.emitTry();
1525 : // emit(try_block);
1526 : // tryCatch.emitCatch();
1527 : // emit(ex and catch_block); // use JSOP_EXCEPTION to get exception
1528 : // tryCatch.emitEnd();
1529 : //
1530 : // `try { try_block } finally { finally_block }`
1531 : // TryEmitter tryCatch(this, TryEmitter::Kind::TryFinally,
1532 : // TryEmitter::ControlKind::Syntactic);
1533 : // tryCatch.emitTry();
1534 : // emit(try_block);
1535 : // // finally_pos: The "{" character's position in the source code text.
1536 : // tryCatch.emitFinally(Some(finally_pos));
1537 : // emit(finally_block);
1538 : // tryCatch.emitEnd();
1539 : //
1540 : // `try { try_block } catch (ex) {catch_block} finally { finally_block }`
1541 : // TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
1542 : // TryEmitter::ControlKind::Syntactic);
1543 : // tryCatch.emitTry();
1544 : // emit(try_block);
1545 : // tryCatch.emitCatch();
1546 : // emit(ex and catch_block);
1547 : // tryCatch.emitFinally(Some(finally_pos));
1548 : // emit(finally_block);
1549 : // tryCatch.emitEnd();
1550 : //
1551 6622 : class MOZ_STACK_CLASS TryEmitter
1552 : {
1553 : public:
1554 : enum class Kind {
1555 : TryCatch,
1556 : TryCatchFinally,
1557 : TryFinally
1558 : };
1559 :
1560 : // Syntactic try-catch-finally and internally used non-syntactic
1561 : // try-catch-finally behave differently for 2 points.
1562 : //
1563 : // The first one is whether TryFinallyControl is used or not.
1564 : // See the comment for `controlInfo_`.
1565 : //
1566 : // The second one is whether the catch and finally blocks handle the frame's
1567 : // return value. For syntactic try-catch-finally, the bytecode marked with
1568 : // "*" are emitted to clear return value with `undefined` before the catch
1569 : // block and the finally block, and also to save/restore the return value
1570 : // before/after the finally block.
1571 : //
1572 : // JSOP_TRY
1573 : //
1574 : // try_body...
1575 : //
1576 : // JSOP_GOSUB finally
1577 : // JSOP_JUMPTARGET
1578 : // JSOP_GOTO end:
1579 : //
1580 : // catch:
1581 : // JSOP_JUMPTARGET
1582 : // * JSOP_UNDEFINED
1583 : // * JSOP_SETRVAL
1584 : //
1585 : // catch_body...
1586 : //
1587 : // JSOP_GOSUB finally
1588 : // JSOP_JUMPTARGET
1589 : // JSOP_GOTO end
1590 : //
1591 : // finally:
1592 : // JSOP_JUMPTARGET
1593 : // * JSOP_GETRVAL
1594 : // * JSOP_UNDEFINED
1595 : // * JSOP_SETRVAL
1596 : //
1597 : // finally_body...
1598 : //
1599 : // * JSOP_SETRVAL
1600 : // JSOP_NOP
1601 : //
1602 : // end:
1603 : // JSOP_JUMPTARGET
1604 : //
1605 : // For syntactic try-catch-finally, Syntactic should be used.
1606 : // For non-syntactic try-catch-finally, NonSyntactic should be used.
1607 : enum class ControlKind {
1608 : Syntactic,
1609 : NonSyntactic
1610 : };
1611 :
1612 : private:
1613 : BytecodeEmitter* bce_;
1614 : Kind kind_;
1615 : ControlKind controlKind_;
1616 :
1617 : // Track jumps-over-catches and gosubs-to-finally for later fixup.
1618 : //
1619 : // When a finally block is active, non-local jumps (including
1620 : // jumps-over-catches) result in a GOSUB being written into the bytecode
1621 : // stream and fixed-up later.
1622 : //
1623 : // For non-syntactic try-catch-finally, all that handling is skipped.
1624 : // The non-syntactic try-catch-finally must:
1625 : // * have only one catch block
1626 : // * have JSOP_GOTO at the end of catch-block
1627 : // * have no non-local-jump
1628 : // * don't use finally block for normal completion of try-block and
1629 : // catch-block
1630 : //
1631 : // Additionally, a finally block may be emitted for non-syntactic
1632 : // try-catch-finally, even if the kind is TryCatch, because GOSUBs are not
1633 : // emitted.
1634 : Maybe<TryFinallyControl> controlInfo_;
1635 :
1636 : // The stack depth before emitting JSOP_TRY.
1637 : int depth_;
1638 :
1639 : // The source note index for SRC_TRY.
1640 : unsigned noteIndex_;
1641 :
1642 : // The offset after JSOP_TRY.
1643 : ptrdiff_t tryStart_;
1644 :
1645 : // JSOP_JUMPTARGET after the entire try-catch-finally block.
1646 : JumpList catchAndFinallyJump_;
1647 :
1648 : // The offset of JSOP_GOTO at the end of the try block.
1649 : JumpTarget tryEnd_;
1650 :
1651 : // The offset of JSOP_JUMPTARGET at the beginning of the finally block.
1652 : JumpTarget finallyStart_;
1653 :
1654 : #ifdef DEBUG
1655 : // The state of this emitter.
1656 : //
1657 : // +-------+ emitTry +-----+ emitCatch +-------+ emitEnd +-----+
1658 : // | Start |-------->| Try |-+---------->| Catch |-+->+--------->| End |
1659 : // +-------+ +-----+ | +-------+ | ^ +-----+
1660 : // | | |
1661 : // | +------------------+ +----+
1662 : // | | |
1663 : // | v emitFinally +---------+ |
1664 : // +->+------------>| Finally |--+
1665 : // +---------+
1666 : enum class State {
1667 : // The initial state.
1668 : Start,
1669 :
1670 : // After calling emitTry.
1671 : Try,
1672 :
1673 : // After calling emitCatch.
1674 : Catch,
1675 :
1676 : // After calling emitFinally.
1677 : Finally,
1678 :
1679 : // After calling emitEnd.
1680 : End
1681 : };
1682 : State state_;
1683 : #endif
1684 :
1685 : bool hasCatch() const {
1686 3449 : return kind_ == Kind::TryCatch || kind_ == Kind::TryCatchFinally;
1687 : }
1688 : bool hasFinally() const {
1689 0 : return kind_ == Kind::TryCatchFinally || kind_ == Kind::TryFinally;
1690 : }
1691 :
1692 : public:
1693 0 : TryEmitter(BytecodeEmitter* bce, Kind kind, ControlKind controlKind)
1694 0 : : bce_(bce),
1695 : kind_(kind),
1696 : controlKind_(controlKind),
1697 : depth_(0),
1698 : noteIndex_(0),
1699 : tryStart_(0)
1700 : #ifdef DEBUG
1701 9933 : , state_(State::Start)
1702 : #endif
1703 : {
1704 3302 : if (controlKind_ == ControlKind::Syntactic)
1705 0 : controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
1706 0 : finallyStart_.offset = 0;
1707 3302 : }
1708 :
1709 : // Emits JSOP_GOTO to the end of try-catch-finally.
1710 : // Used in `yield*`.
1711 : MOZ_MUST_USE bool emitJumpOverCatchAndFinally() {
1712 9 : if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1713 : return false;
1714 : return true;
1715 : }
1716 :
1717 3311 : MOZ_MUST_USE bool emitTry() {
1718 0 : MOZ_ASSERT(state_ == State::Start);
1719 :
1720 : // Since an exception can be thrown at any place inside the try block,
1721 : // we need to restore the stack and the scope chain before we transfer
1722 : // the control to the exception handler.
1723 : //
1724 : // For that we store in a try note associated with the catch or
1725 : // finally block the stack depth upon the try entry. The interpreter
1726 : // uses this depth to properly unwind the stack and the scope chain.
1727 0 : depth_ = bce_->stackDepth;
1728 :
1729 : // Record the try location, then emit the try block.
1730 3311 : if (!bce_->newSrcNote(SRC_TRY, ¬eIndex_))
1731 : return false;
1732 0 : if (!bce_->emit1(JSOP_TRY))
1733 : return false;
1734 3311 : tryStart_ = bce_->offset();
1735 :
1736 : #ifdef DEBUG
1737 0 : state_ = State::Try;
1738 : #endif
1739 3311 : return true;
1740 : }
1741 :
1742 : private:
1743 3311 : MOZ_MUST_USE bool emitTryEnd() {
1744 3311 : MOZ_ASSERT(state_ == State::Try);
1745 3311 : MOZ_ASSERT(depth_ == bce_->stackDepth);
1746 :
1747 : // GOSUB to finally, if present.
1748 6731 : if (hasFinally() && controlInfo_) {
1749 0 : if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
1750 : return false;
1751 : }
1752 :
1753 : // Source note points to the jump at the end of the try block.
1754 3311 : if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
1755 : return false;
1756 :
1757 : // Emit jump over catch and/or finally.
1758 0 : if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1759 : return false;
1760 :
1761 0 : if (!bce_->emitJumpTarget(&tryEnd_))
1762 : return false;
1763 :
1764 3311 : return true;
1765 : }
1766 :
1767 : public:
1768 0 : MOZ_MUST_USE bool emitCatch() {
1769 3240 : MOZ_ASSERT(state_ == State::Try);
1770 0 : if (!emitTryEnd())
1771 : return false;
1772 :
1773 3240 : MOZ_ASSERT(bce_->stackDepth == depth_);
1774 :
1775 0 : if (controlKind_ == ControlKind::Syntactic) {
1776 : // Clear the frame's return value that might have been set by the
1777 : // try block:
1778 : //
1779 : // eval("try { 1; throw 2 } catch(e) {}"); // undefined, not 1
1780 1003 : if (!bce_->emit1(JSOP_UNDEFINED))
1781 : return false;
1782 0 : if (!bce_->emit1(JSOP_SETRVAL))
1783 : return false;
1784 : }
1785 :
1786 : #ifdef DEBUG
1787 3240 : state_ = State::Catch;
1788 : #endif
1789 0 : return true;
1790 : }
1791 :
1792 : private:
1793 3240 : MOZ_MUST_USE bool emitCatchEnd() {
1794 0 : MOZ_ASSERT(state_ == State::Catch);
1795 :
1796 6480 : if (!controlInfo_)
1797 : return true;
1798 :
1799 : // gosub <finally>, if required.
1800 2006 : if (hasFinally()) {
1801 29 : if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
1802 : return false;
1803 29 : MOZ_ASSERT(bce_->stackDepth == depth_);
1804 :
1805 : // Jump over the finally block.
1806 0 : if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1807 : return false;
1808 : }
1809 :
1810 : return true;
1811 : }
1812 :
1813 : public:
1814 : // If `finallyPos` is specified, it's an offset of the finally block's
1815 : // "{" character in the source code text, to improve line:column number in
1816 : // the error reporting.
1817 : // For non-syntactic try-catch-finally, `finallyPos` can be omitted.
1818 138 : MOZ_MUST_USE bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
1819 : // If we are using controlInfo_ (i.e., emitting a syntactic try
1820 : // blocks), we must have specified up front if there will be a finally
1821 : // close. For internal non-syntactic try blocks, like those emitted for
1822 : // yield* and IteratorClose inside for-of loops, we can emitFinally even
1823 : // without specifying up front, since the internal non-syntactic try
1824 : // blocks emit no GOSUBs.
1825 0 : if (!controlInfo_) {
1826 0 : if (kind_ == Kind::TryCatch)
1827 29 : kind_ = Kind::TryCatchFinally;
1828 : } else {
1829 200 : MOZ_ASSERT(hasFinally());
1830 : }
1831 :
1832 0 : if (!hasCatch()) {
1833 71 : MOZ_ASSERT(state_ == State::Try);
1834 71 : if (!emitTryEnd())
1835 : return false;
1836 : } else {
1837 67 : MOZ_ASSERT(state_ == State::Catch);
1838 0 : if (!emitCatchEnd())
1839 : return false;
1840 : }
1841 :
1842 138 : MOZ_ASSERT(bce_->stackDepth == depth_);
1843 :
1844 0 : if (!bce_->emitJumpTarget(&finallyStart_))
1845 : return false;
1846 :
1847 0 : if (controlInfo_) {
1848 : // Fix up the gosubs that might have been emitted before non-local
1849 : // jumps to the finally code.
1850 0 : bce_->patchJumpsToTarget(controlInfo_->gosubs, finallyStart_);
1851 :
1852 : // Indicate that we're emitting a subroutine body.
1853 100 : controlInfo_->setEmittingSubroutine();
1854 : }
1855 138 : if (finallyPos) {
1856 100 : if (!bce_->updateSourceCoordNotes(finallyPos.value()))
1857 : return false;
1858 : }
1859 138 : if (!bce_->emit1(JSOP_FINALLY))
1860 : return false;
1861 :
1862 138 : if (controlKind_ == ControlKind::Syntactic) {
1863 100 : if (!bce_->emit1(JSOP_GETRVAL))
1864 : return false;
1865 :
1866 : // Clear the frame's return value to make break/continue return
1867 : // correct value even if there's no other statement before them:
1868 : //
1869 : // eval("x: try { 1 } finally { break x; }"); // undefined, not 1
1870 100 : if (!bce_->emit1(JSOP_UNDEFINED))
1871 : return false;
1872 0 : if (!bce_->emit1(JSOP_SETRVAL))
1873 : return false;
1874 : }
1875 :
1876 : #ifdef DEBUG
1877 138 : state_ = State::Finally;
1878 : #endif
1879 0 : return true;
1880 : }
1881 :
1882 : private:
1883 0 : MOZ_MUST_USE bool emitFinallyEnd() {
1884 138 : MOZ_ASSERT(state_ == State::Finally);
1885 :
1886 138 : if (controlKind_ == ControlKind::Syntactic) {
1887 0 : if (!bce_->emit1(JSOP_SETRVAL))
1888 : return false;
1889 : }
1890 :
1891 138 : if (!bce_->emit1(JSOP_RETSUB))
1892 : return false;
1893 :
1894 0 : bce_->hasTryFinally = true;
1895 138 : return true;
1896 : }
1897 :
1898 : public:
1899 3311 : MOZ_MUST_USE bool emitEnd() {
1900 6622 : if (!hasFinally()) {
1901 3173 : MOZ_ASSERT(state_ == State::Catch);
1902 0 : if (!emitCatchEnd())
1903 : return false;
1904 : } else {
1905 138 : MOZ_ASSERT(state_ == State::Finally);
1906 0 : if (!emitFinallyEnd())
1907 : return false;
1908 : }
1909 :
1910 3311 : MOZ_ASSERT(bce_->stackDepth == depth_);
1911 :
1912 : // ReconstructPCStack needs a NOP here to mark the end of the last
1913 : // catch block.
1914 3311 : if (!bce_->emit1(JSOP_NOP))
1915 : return false;
1916 :
1917 : // Fix up the end-of-try/catch jumps to come here.
1918 3311 : if (!bce_->emitJumpTargetAndPatch(catchAndFinallyJump_))
1919 : return false;
1920 :
1921 : // Add the try note last, to let post-order give us the right ordering
1922 : // (first to last for a given nesting level, inner to outer by level).
1923 6622 : if (hasCatch()) {
1924 3240 : if (!bce_->tryNoteList.append(JSTRY_CATCH, depth_, tryStart_, tryEnd_.offset))
1925 : return false;
1926 : }
1927 :
1928 : // If we've got a finally, mark try+catch region with additional
1929 : // trynote to catch exceptions (re)thrown from a catch block or
1930 : // for the try{}finally{} case.
1931 6622 : if (hasFinally()) {
1932 138 : if (!bce_->tryNoteList.append(JSTRY_FINALLY, depth_, tryStart_, finallyStart_.offset))
1933 : return false;
1934 : }
1935 :
1936 : #ifdef DEBUG
1937 3311 : state_ = State::End;
1938 : #endif
1939 3311 : return true;
1940 : }
1941 : };
1942 :
1943 : // Class for emitting bytecode for blocks like if-then-else.
1944 : //
1945 : // This class can be used to emit single if-then-else block, or cascading
1946 : // else-if blocks.
1947 : //
1948 : // Usage: (check for the return value is omitted for simplicity)
1949 : //
1950 : // `if (cond) then_block`
1951 : // IfEmitter ifThen(this);
1952 : // emit(cond);
1953 : // ifThen.emitThen();
1954 : // emit(then_block);
1955 : // ifThen.emitEnd();
1956 : //
1957 : // `if (cond) then_block else else_block`
1958 : // IfEmitter ifThenElse(this);
1959 : // emit(cond);
1960 : // ifThenElse.emitThenElse();
1961 : // emit(then_block);
1962 : // ifThenElse.emitElse();
1963 : // emit(else_block);
1964 : // ifThenElse.emitEnd();
1965 : //
1966 : // `if (c1) b1 else if (c2) b2 else if (c3) b3 else b4`
1967 : // IfEmitter ifThenElse(this);
1968 : // emit(c1);
1969 : // ifThenElse.emitThenElse();
1970 : // emit(b1);
1971 : // ifThenElse.emitElseIf();
1972 : // emit(c2);
1973 : // ifThenElse.emitThenElse();
1974 : // emit(b2);
1975 : // ifThenElse.emitElseIf();
1976 : // emit(c3);
1977 : // ifThenElse.emitThenElse();
1978 : // emit(b3);
1979 : // ifThenElse.emitElse();
1980 : // emit(b4);
1981 : // ifThenElse.emitEnd();
1982 : //
1983 : // `cond ? then_expr : else_expr`
1984 : // IfEmitter condElse(this);
1985 : // emit(cond);
1986 : // condElse.emitCond();
1987 : // emit(then_block);
1988 : // condElse.emitElse();
1989 : // emit(else_block);
1990 : // condElse.emitEnd();
1991 : //
1992 38954 : class MOZ_STACK_CLASS IfEmitter
1993 : {
1994 : public:
1995 : // Whether the then-clause, the else-clause, or else-if condition may
1996 : // contain declaration or access to lexical variables, which means they
1997 : // should have their own TDZCheckCache. Basically TDZCheckCache should be
1998 : // created for each basic block, which then-clause, else-clause, and
1999 : // else-if condition are, but for internally used branches which are
2000 : // known not to touch lexical variables we can skip creating TDZCheckCache
2001 : // for them.
2002 : //
2003 : // See the comment for TDZCheckCache class for more details.
2004 : enum class Kind {
2005 : // For syntactic branches (if, if-else, and conditional expression),
2006 : // which basically may contain declaration or accesses to lexical
2007 : // variables inside then-clause, else-clause, and else-if condition.
2008 : MayContainLexicalAccessInBranch,
2009 :
2010 : // For internally used branches which don't touch lexical variables
2011 : // inside then-clause, else-clause, nor else-if condition.
2012 : NoLexicalAccessInBranch
2013 : };
2014 :
2015 : private:
2016 : using TDZCheckCache = BytecodeEmitter::TDZCheckCache;
2017 :
2018 : BytecodeEmitter* bce_;
2019 :
2020 : // Jump around the then clause, to the beginning of the else clause.
2021 : JumpList jumpAroundThen_;
2022 :
2023 : // Jump around the else clause, to the end of the entire branch.
2024 : JumpList jumpsAroundElse_;
2025 :
2026 : // The stack depth before emitting the then block.
2027 : // Used for restoring stack depth before emitting the else block.
2028 : // Also used for assertion to make sure then and else blocks pushed the
2029 : // same number of values.
2030 : int32_t thenDepth_;
2031 :
2032 : Kind kind_;
2033 : Maybe<TDZCheckCache> tdzCache_;
2034 :
2035 : #ifdef DEBUG
2036 : // The number of values pushed in the then and else blocks.
2037 : int32_t pushed_;
2038 : bool calculatedPushed_;
2039 :
2040 : // The state of this emitter.
2041 : //
2042 : // +-------+ emitCond +------+ emitElse +------+ emitEnd +-----+
2043 : // | Start |-+--------->| Cond |--------->| Else |------>+------->| End |
2044 : // +-------+ | +------+ +------+ ^ +-----+
2045 : // | |
2046 : // v emitThen +------+ |
2047 : // +->+--------->| Then |------------------------>+
2048 : // ^ | +------+ ^
2049 : // | | |
2050 : // | | +---+
2051 : // | | |
2052 : // | | emitThenElse +----------+ emitElse +------+ |
2053 : // | +------------->| ThenElse |-+--------->| Else |-+
2054 : // | +----------+ | +------+
2055 : // | |
2056 : // | | emitElseIf +--------+
2057 : // | +----------->| ElseIf |-+
2058 : // | +--------+ |
2059 : // | |
2060 : // +------------------------------------------------------+
2061 : enum class State {
2062 : // The initial state.
2063 : Start,
2064 :
2065 : // After calling emitThen.
2066 : Then,
2067 :
2068 : // After calling emitCond.
2069 : Cond,
2070 :
2071 : // After calling emitThenElse.
2072 : ThenElse,
2073 :
2074 : // After calling emitElse.
2075 : Else,
2076 :
2077 : // After calling emitElseIf.
2078 : ElseIf,
2079 :
2080 : // After calling emitEnd.
2081 : End
2082 : };
2083 : State state_;
2084 : #endif
2085 :
2086 : protected:
2087 : // For InternalIfEmitter.
2088 : IfEmitter(BytecodeEmitter* bce, Kind kind)
2089 0 : : bce_(bce)
2090 : , thenDepth_(0)
2091 : , kind_(kind)
2092 : #ifdef DEBUG
2093 : , pushed_(0)
2094 : , calculatedPushed_(false)
2095 77908 : , state_(State::Start)
2096 : #endif
2097 : {}
2098 :
2099 : public:
2100 : explicit IfEmitter(BytecodeEmitter* bce)
2101 27610 : : IfEmitter(bce, Kind::MayContainLexicalAccessInBranch)
2102 : {}
2103 :
2104 : private:
2105 0 : MOZ_MUST_USE bool emitIfInternal(SrcNoteType type) {
2106 19750 : MOZ_ASSERT_IF(state_ == State::ElseIf, tdzCache_.isSome());
2107 19750 : MOZ_ASSERT_IF(state_ != State::ElseIf, tdzCache_.isNothing());
2108 :
2109 : // The end of TDZCheckCache for cond for else-if.
2110 19750 : if (kind_ == Kind::MayContainLexicalAccessInBranch)
2111 0 : tdzCache_.reset();
2112 :
2113 : // Emit an annotated branch-if-false around the then part.
2114 0 : if (!bce_->newSrcNote(type))
2115 : return false;
2116 0 : if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_))
2117 : return false;
2118 :
2119 : // To restore stack depth in else part, save depth of the then part.
2120 : #ifdef DEBUG
2121 : // If DEBUG, this is also necessary to calculate |pushed_|.
2122 0 : thenDepth_ = bce_->stackDepth;
2123 : #else
2124 : if (type == SRC_COND || type == SRC_IF_ELSE)
2125 : thenDepth_ = bce_->stackDepth;
2126 : #endif
2127 :
2128 : // Enclose then-branch with TDZCheckCache.
2129 19750 : if (kind_ == Kind::MayContainLexicalAccessInBranch)
2130 14487 : tdzCache_.emplace(bce_);
2131 :
2132 : return true;
2133 : }
2134 :
2135 25046 : void calculateOrCheckPushed() {
2136 : #ifdef DEBUG
2137 25046 : if (!calculatedPushed_) {
2138 19068 : pushed_ = bce_->stackDepth - thenDepth_;
2139 19068 : calculatedPushed_ = true;
2140 : } else {
2141 5978 : MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_);
2142 : }
2143 : #endif
2144 25046 : }
2145 :
2146 : public:
2147 0 : MOZ_MUST_USE bool emitThen() {
2148 13772 : MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
2149 13772 : if (!emitIfInternal(SRC_IF))
2150 : return false;
2151 :
2152 : #ifdef DEBUG
2153 13772 : state_ = State::Then;
2154 : #endif
2155 13772 : return true;
2156 : }
2157 :
2158 0 : MOZ_MUST_USE bool emitCond() {
2159 971 : MOZ_ASSERT(state_ == State::Start);
2160 0 : if (!emitIfInternal(SRC_COND))
2161 : return false;
2162 :
2163 : #ifdef DEBUG
2164 0 : state_ = State::Cond;
2165 : #endif
2166 0 : return true;
2167 : }
2168 :
2169 5007 : MOZ_MUST_USE bool emitThenElse() {
2170 0 : MOZ_ASSERT(state_ == State::Start || state_ == State::ElseIf);
2171 5007 : if (!emitIfInternal(SRC_IF_ELSE))
2172 : return false;
2173 :
2174 : #ifdef DEBUG
2175 0 : state_ = State::ThenElse;
2176 : #endif
2177 5006 : return true;
2178 : }
2179 :
2180 : private:
2181 5978 : MOZ_MUST_USE bool emitElseInternal() {
2182 0 : calculateOrCheckPushed();
2183 :
2184 : // The end of TDZCheckCache for then-clause.
2185 5978 : if (kind_ == Kind::MayContainLexicalAccessInBranch) {
2186 3025 : MOZ_ASSERT(tdzCache_.isSome());
2187 0 : tdzCache_.reset();
2188 : }
2189 :
2190 : // Emit a jump from the end of our then part around the else part. The
2191 : // patchJumpsToTarget call at the bottom of this function will fix up
2192 : // the offset with jumpsAroundElse value.
2193 5978 : if (!bce_->emitJump(JSOP_GOTO, &jumpsAroundElse_))
2194 : return false;
2195 :
2196 : // Ensure the branch-if-false comes here, then emit the else.
2197 5978 : if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
2198 : return false;
2199 :
2200 : // Clear jumpAroundThen_ offset, to tell emitEnd there was an else part.
2201 5978 : jumpAroundThen_ = JumpList();
2202 :
2203 : // Restore stack depth of the then part.
2204 5978 : bce_->stackDepth = thenDepth_;
2205 : #ifdef DEBUG
2206 5978 : state_ = State::Else;
2207 : #endif
2208 5978 : return true;
2209 : }
2210 :
2211 : public:
2212 5296 : MOZ_MUST_USE bool emitElse() {
2213 5296 : MOZ_ASSERT(state_ == State::ThenElse || state_ == State::Cond);
2214 :
2215 5296 : if (!emitElseInternal())
2216 : return false;
2217 :
2218 : // Enclose else-branch with TDZCheckCache.
2219 5296 : if (kind_ == Kind::MayContainLexicalAccessInBranch)
2220 2343 : tdzCache_.emplace(bce_);
2221 :
2222 : #ifdef DEBUG
2223 5296 : state_ = State::Else;
2224 : #endif
2225 5296 : return true;
2226 : }
2227 :
2228 682 : MOZ_MUST_USE bool emitElseIf() {
2229 682 : MOZ_ASSERT(state_ == State::ThenElse);
2230 :
2231 682 : if (!emitElseInternal())
2232 : return false;
2233 :
2234 : // Enclose cond for else-if with TDZCheckCache.
2235 682 : if (kind_ == Kind::MayContainLexicalAccessInBranch)
2236 682 : tdzCache_.emplace(bce_);
2237 :
2238 : #ifdef DEBUG
2239 682 : state_ = State::ElseIf;
2240 : #endif
2241 682 : return true;
2242 : }
2243 :
2244 19068 : MOZ_MUST_USE bool emitEnd() {
2245 19068 : MOZ_ASSERT(state_ == State::Then || state_ == State::Else);
2246 : // If there was an else part for the last branch, jumpAroundThen_ is
2247 : // already fixed up when emitting the else part.
2248 19068 : MOZ_ASSERT_IF(state_ == State::Then, jumpAroundThen_.offset != -1);
2249 19068 : MOZ_ASSERT_IF(state_ == State::Else, jumpAroundThen_.offset == -1);
2250 :
2251 : // The end of TDZCheckCache for then or else-clause.
2252 19068 : if (kind_ == Kind::MayContainLexicalAccessInBranch) {
2253 13805 : MOZ_ASSERT(tdzCache_.isSome());
2254 13805 : tdzCache_.reset();
2255 : }
2256 :
2257 19068 : calculateOrCheckPushed();
2258 :
2259 19068 : if (jumpAroundThen_.offset != -1) {
2260 : // No else part for the last branch, fixup the branch-if-false to
2261 : // come here.
2262 13772 : if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
2263 : return false;
2264 : }
2265 :
2266 : // Patch all the jumps around else parts.
2267 19068 : if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_))
2268 : return false;
2269 :
2270 : #ifdef DEBUG
2271 19068 : state_ = State::End;
2272 : #endif
2273 19068 : return true;
2274 : }
2275 :
2276 : #ifdef DEBUG
2277 : // Returns the number of values pushed onto the value stack inside
2278 : // `then_block` and `else_block`.
2279 : // Can be used in assertion after emitting if-then-else.
2280 : int32_t pushed() const {
2281 : return pushed_;
2282 : }
2283 :
2284 : // Returns the number of values popped onto the value stack inside
2285 : // `then_block` and `else_block`.
2286 : // Can be used in assertion after emitting if-then-else.
2287 : int32_t popped() const {
2288 : return -pushed_;
2289 : }
2290 : #endif
2291 : };
2292 :
2293 : // Class for emitting bytecode for blocks like if-then-else which doesn't touch
2294 : // lexical variables.
2295 : //
2296 : // See the comments above NoLexicalAccessInBranch for more details when to use
2297 : // this instead of IfEmitter.
2298 11317 : class MOZ_STACK_CLASS InternalIfEmitter : public IfEmitter
2299 : {
2300 : public:
2301 : explicit InternalIfEmitter(BytecodeEmitter* bce)
2302 11344 : : IfEmitter(bce, Kind::NoLexicalAccessInBranch)
2303 : {}
2304 : };
2305 :
2306 0 : class ForOfLoopControl : public LoopControl
2307 : {
2308 : using EmitterScope = BytecodeEmitter::EmitterScope;
2309 :
2310 : // The stack depth of the iterator.
2311 : int32_t iterDepth_;
2312 :
2313 : // for-of loops, when throwing from non-iterator code (i.e. from the body
2314 : // or from evaluating the LHS of the loop condition), need to call
2315 : // IteratorClose. This is done by enclosing non-iterator code with
2316 : // try-catch and call IteratorClose in `catch` block.
2317 : // If IteratorClose itself throws, we must not re-call IteratorClose. Since
2318 : // non-local jumps like break and return call IteratorClose, whenever a
2319 : // non-local jump is emitted, we must tell catch block not to perform
2320 : // IteratorClose.
2321 : //
2322 : // for (x of y) {
2323 : // // Operations for iterator (IteratorNext etc) are outside of
2324 : // // try-block.
2325 : // try {
2326 : // ...
2327 : // if (...) {
2328 : // // Before non-local jump, clear iterator on the stack to tell
2329 : // // catch block not to perform IteratorClose.
2330 : // tmpIterator = iterator;
2331 : // iterator = undefined;
2332 : // IteratorClose(tmpIterator, { break });
2333 : // break;
2334 : // }
2335 : // ...
2336 : // } catch (e) {
2337 : // // Just throw again when iterator is cleared by non-local jump.
2338 : // if (iterator === undefined)
2339 : // throw e;
2340 : // IteratorClose(iterator, { throw, e });
2341 : // }
2342 : // }
2343 : Maybe<TryEmitter> tryCatch_;
2344 :
2345 : // Used to track if any yields were emitted between calls to to
2346 : // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
2347 : uint32_t numYieldsAtBeginCodeNeedingIterClose_;
2348 :
2349 : bool allowSelfHosted_;
2350 :
2351 : IteratorKind iterKind_;
2352 :
2353 : public:
2354 : ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
2355 : IteratorKind iterKind)
2356 1114 : : LoopControl(bce, StatementKind::ForOfLoop),
2357 : iterDepth_(iterDepth),
2358 : numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
2359 : allowSelfHosted_(allowSelfHosted),
2360 0 : iterKind_(iterKind)
2361 : {
2362 : }
2363 :
2364 1114 : bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
2365 1114 : tryCatch_.emplace(bce, TryEmitter::Kind::TryCatch, TryEmitter::ControlKind::NonSyntactic);
2366 :
2367 0 : if (!tryCatch_->emitTry())
2368 : return false;
2369 :
2370 0 : MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
2371 1114 : numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
2372 :
2373 1114 : return true;
2374 : }
2375 :
2376 1114 : bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
2377 0 : if (!tryCatch_->emitCatch()) // ITER ...
2378 : return false;
2379 :
2380 1114 : if (!bce->emit1(JSOP_EXCEPTION)) // ITER ... EXCEPTION
2381 : return false;
2382 1114 : unsigned slotFromTop = bce->stackDepth - iterDepth_;
2383 0 : if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
2384 : return false;
2385 :
2386 : // If ITER is undefined, it means the exception is thrown by
2387 : // IteratorClose for non-local jump, and we should't perform
2388 : // IteratorClose again here.
2389 1114 : if (!bce->emit1(JSOP_UNDEFINED)) // ITER ... EXCEPTION ITER UNDEF
2390 : return false;
2391 1114 : if (!bce->emit1(JSOP_STRICTNE)) // ITER ... EXCEPTION NE
2392 : return false;
2393 :
2394 1114 : InternalIfEmitter ifIteratorIsNotClosed(bce);
2395 1114 : if (!ifIteratorIsNotClosed.emitThen()) // ITER ... EXCEPTION
2396 : return false;
2397 :
2398 1114 : MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
2399 1114 : if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
2400 : return false;
2401 1114 : if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Throw))
2402 : return false; // ITER ... EXCEPTION
2403 :
2404 1114 : if (!ifIteratorIsNotClosed.emitEnd()) // ITER ... EXCEPTION
2405 : return false;
2406 :
2407 1114 : if (!bce->emit1(JSOP_THROW)) // ITER ...
2408 : return false;
2409 :
2410 : // If any yields were emitted, then this for-of loop is inside a star
2411 : // generator and must handle the case of Generator.return. Like in
2412 : // yield*, it is handled with a finally block.
2413 1114 : uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
2414 0 : if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
2415 58 : if (!tryCatch_->emitFinally())
2416 0 : return false;
2417 :
2418 58 : InternalIfEmitter ifGeneratorClosing(bce);
2419 0 : if (!bce->emit1(JSOP_ISGENCLOSING)) // ITER ... FTYPE FVALUE CLOSING
2420 : return false;
2421 29 : if (!ifGeneratorClosing.emitThen()) // ITER ... FTYPE FVALUE
2422 : return false;
2423 0 : if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
2424 : return false;
2425 29 : if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Normal))
2426 : return false; // ITER ... FTYPE FVALUE
2427 29 : if (!ifGeneratorClosing.emitEnd()) // ITER ... FTYPE FVALUE
2428 : return false;
2429 : }
2430 :
2431 1114 : if (!tryCatch_->emitEnd())
2432 : return false;
2433 :
2434 1114 : tryCatch_.reset();
2435 1114 : numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
2436 :
2437 1114 : return true;
2438 : }
2439 :
2440 0 : bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
2441 : CompletionKind completionKind = CompletionKind::Normal) {
2442 0 : return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(), completionKind);
2443 : }
2444 :
2445 1290 : bool emitIteratorCloseInScope(BytecodeEmitter* bce,
2446 : EmitterScope& currentScope,
2447 : CompletionKind completionKind = CompletionKind::Normal) {
2448 1290 : ptrdiff_t start = bce->offset();
2449 1290 : if (!bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
2450 1290 : allowSelfHosted_))
2451 : {
2452 : return false;
2453 : }
2454 0 : ptrdiff_t end = bce->offset();
2455 1290 : return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
2456 : }
2457 :
2458 147 : bool emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
2459 : EmitterScope& currentScope,
2460 : bool isTarget) {
2461 : // Pop unnecessary value from the stack. Effectively this means
2462 : // leaving try-catch block. However, the performing IteratorClose can
2463 : // reach the depth for try-catch, and effectively re-enter the
2464 : // try-catch block.
2465 0 : if (!bce->emit1(JSOP_POP)) // NEXT ITER
2466 : return false;
2467 :
2468 : // Pop the iterator's next method.
2469 0 : if (!bce->emit1(JSOP_SWAP)) // ITER NEXT
2470 : return false;
2471 0 : if (!bce->emit1(JSOP_POP)) // ITER
2472 : return false;
2473 :
2474 : // Clear ITER slot on the stack to tell catch block to avoid performing
2475 : // IteratorClose again.
2476 1 : if (!bce->emit1(JSOP_UNDEFINED)) // ITER UNDEF
2477 : return false;
2478 0 : if (!bce->emit1(JSOP_SWAP)) // UNDEF ITER
2479 : return false;
2480 :
2481 147 : if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) // UNDEF
2482 : return false;
2483 :
2484 147 : if (isTarget) {
2485 : // At the level of the target block, there's bytecode after the
2486 : // loop that will pop the next method, the iterator, and the
2487 : // value, so push two undefineds to balance the stack.
2488 44 : if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF
2489 : return false;
2490 44 : if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF UNDEF
2491 : return false;
2492 : } else {
2493 103 : if (!bce->emit1(JSOP_POP)) //
2494 : return false;
2495 : }
2496 :
2497 : return true;
2498 : }
2499 : };
2500 :
2501 :
2502 13449 : BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
2503 : SharedContext* sc, HandleScript script,
2504 : Handle<LazyScript*> lazyScript,
2505 0 : uint32_t lineNum, EmitterMode emitterMode)
2506 : : sc(sc),
2507 13449 : cx(sc->context),
2508 : parent(parent),
2509 : script(cx, script),
2510 : lazyScript(cx, lazyScript),
2511 0 : prologue(cx, lineNum),
2512 : main(cx, lineNum),
2513 : current(&main),
2514 13449 : atomIndices(cx->frontendCollectionPool()),
2515 : firstLine(lineNum),
2516 : maxFixedSlots(0),
2517 : maxStackDepth(0),
2518 : stackDepth(0),
2519 : emitLevel(0),
2520 : bodyScopeIndex(UINT32_MAX),
2521 : varEmitterScope(nullptr),
2522 : innermostNestableControl(nullptr),
2523 : innermostEmitterScope_(nullptr),
2524 : innermostTDZCheckCache(nullptr),
2525 : #ifdef DEBUG
2526 : unstableEmitterScope(false),
2527 : #endif
2528 0 : constList(cx),
2529 : scopeList(cx),
2530 0 : tryNoteList(cx),
2531 : scopeNoteList(cx),
2532 : yieldAndAwaitOffsetList(cx),
2533 : typesetCount(0),
2534 : hasSingletons(false),
2535 : hasTryFinally(false),
2536 : emittingRunOnceLambda(false),
2537 : emitterMode(emitterMode),
2538 : scriptStartOffsetSet(false),
2539 201731 : functionBodyEndPosSet(false)
2540 : {
2541 0 : MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
2542 13448 : }
2543 :
2544 0 : BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
2545 : BCEParserHandle* handle, SharedContext* sc,
2546 : HandleScript script, Handle<LazyScript*> lazyScript,
2547 0 : uint32_t lineNum, EmitterMode emitterMode)
2548 0 : : BytecodeEmitter(parent, sc, script, lazyScript, lineNum, emitterMode)
2549 : {
2550 12227 : parser = handle;
2551 0 : }
2552 :
2553 0 : BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
2554 : const EitherParser& parser, SharedContext* sc,
2555 : HandleScript script, Handle<LazyScript*> lazyScript,
2556 1221 : uint32_t lineNum, EmitterMode emitterMode)
2557 0 : : BytecodeEmitter(parent, sc, script, lazyScript, lineNum, emitterMode)
2558 : {
2559 0 : ep_.emplace(parser);
2560 1221 : this->parser = ep_.ptr();
2561 1221 : }
2562 :
2563 : void
2564 0 : BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition)
2565 : {
2566 0 : setScriptStartOffsetIfUnset(bodyPosition);
2567 12227 : setFunctionBodyEndPos(bodyPosition);
2568 0 : }
2569 :
2570 : bool
2571 0 : BytecodeEmitter::init()
2572 : {
2573 0 : return atomIndices.acquire(cx);
2574 : }
2575 :
2576 : template <typename T>
2577 : T*
2578 : BytecodeEmitter::findInnermostNestableControl() const
2579 : {
2580 12658 : return NestableControl::findNearest<T>(innermostNestableControl);
2581 : }
2582 :
2583 : template <typename T, typename Predicate /* (T*) -> bool */>
2584 : T*
2585 : BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
2586 : {
2587 0 : return NestableControl::findNearest<T>(innermostNestableControl, predicate);
2588 : }
2589 :
2590 : NameLocation
2591 0 : BytecodeEmitter::lookupName(JSAtom* name)
2592 : {
2593 167850 : return innermostEmitterScope()->lookup(this, name);
2594 : }
2595 :
2596 : Maybe<NameLocation>
2597 0 : BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
2598 : {
2599 13490 : return innermostEmitterScope()->locationBoundInScope(name, target);
2600 : }
2601 :
2602 : Maybe<NameLocation>
2603 2682 : BytecodeEmitter::locationOfNameBoundInFunctionScope(JSAtom* name, EmitterScope* source)
2604 : {
2605 2682 : EmitterScope* funScope = source;
2606 5862 : while (!funScope->scope(this)->is<FunctionScope>())
2607 0 : funScope = funScope->enclosingInFrame();
2608 0 : return source->locationBoundInScope(name, funScope);
2609 : }
2610 :
2611 : bool
2612 0 : BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset)
2613 : {
2614 885534 : *offset = code().length();
2615 :
2616 0 : if (!code().growBy(delta)) {
2617 0 : ReportOutOfMemory(cx);
2618 0 : return false;
2619 : }
2620 : return true;
2621 : }
2622 :
2623 : void
2624 885628 : BytecodeEmitter::updateDepth(ptrdiff_t target)
2625 : {
2626 0 : jsbytecode* pc = code(target);
2627 :
2628 885626 : int nuses = StackUses(pc);
2629 885646 : int ndefs = StackDefs(pc);
2630 :
2631 885663 : stackDepth -= nuses;
2632 885663 : MOZ_ASSERT(stackDepth >= 0);
2633 0 : stackDepth += ndefs;
2634 :
2635 885663 : if ((uint32_t)stackDepth > maxStackDepth)
2636 0 : maxStackDepth = stackDepth;
2637 0 : }
2638 :
2639 : #ifdef DEBUG
2640 : bool
2641 834951 : BytecodeEmitter::checkStrictOrSloppy(JSOp op)
2642 : {
2643 842633 : if (IsCheckStrictOp(op) && !sc->strict())
2644 : return false;
2645 836961 : if (IsCheckSloppyOp(op) && sc->strict())
2646 : return false;
2647 0 : return true;
2648 : }
2649 : #endif
2650 :
2651 : bool
2652 0 : BytecodeEmitter::emit1(JSOp op)
2653 : {
2654 0 : MOZ_ASSERT(checkStrictOrSloppy(op));
2655 :
2656 : ptrdiff_t offset;
2657 411873 : if (!emitCheck(1, &offset))
2658 : return false;
2659 :
2660 1 : jsbytecode* code = this->code(offset);
2661 411896 : code[0] = jsbytecode(op);
2662 0 : updateDepth(offset);
2663 0 : return true;
2664 : }
2665 :
2666 : bool
2667 0 : BytecodeEmitter::emit2(JSOp op, uint8_t op1)
2668 : {
2669 15074 : MOZ_ASSERT(checkStrictOrSloppy(op));
2670 :
2671 : ptrdiff_t offset;
2672 0 : if (!emitCheck(2, &offset))
2673 : return false;
2674 :
2675 0 : jsbytecode* code = this->code(offset);
2676 0 : code[0] = jsbytecode(op);
2677 15074 : code[1] = jsbytecode(op1);
2678 0 : updateDepth(offset);
2679 15074 : return true;
2680 : }
2681 :
2682 : bool
2683 50676 : BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2)
2684 : {
2685 50676 : MOZ_ASSERT(checkStrictOrSloppy(op));
2686 :
2687 : /* These should filter through emitVarOp. */
2688 0 : MOZ_ASSERT(!IsArgOp(op));
2689 0 : MOZ_ASSERT(!IsLocalOp(op));
2690 :
2691 : ptrdiff_t offset;
2692 0 : if (!emitCheck(3, &offset))
2693 : return false;
2694 :
2695 50676 : jsbytecode* code = this->code(offset);
2696 0 : code[0] = jsbytecode(op);
2697 50676 : code[1] = op1;
2698 0 : code[2] = op2;
2699 50676 : updateDepth(offset);
2700 0 : return true;
2701 : }
2702 :
2703 : bool
2704 161925 : BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset)
2705 : {
2706 161925 : MOZ_ASSERT(checkStrictOrSloppy(op));
2707 161925 : ptrdiff_t length = 1 + ptrdiff_t(extra);
2708 :
2709 : ptrdiff_t off;
2710 161925 : if (!emitCheck(length, &off))
2711 : return false;
2712 :
2713 0 : jsbytecode* code = this->code(off);
2714 161933 : code[0] = jsbytecode(op);
2715 : /* The remaining |extra| bytes are set by the caller */
2716 :
2717 : /*
2718 : * Don't updateDepth if op's use-count comes from the immediate
2719 : * operand yet to be stored in the extra bytes after op.
2720 : */
2721 161933 : if (CodeSpec[op].nuses >= 0)
2722 161933 : updateDepth(off);
2723 :
2724 161933 : if (offset)
2725 0 : *offset = off;
2726 : return true;
2727 : }
2728 :
2729 : bool
2730 0 : BytecodeEmitter::emitJumpTarget(JumpTarget* target)
2731 : {
2732 76277 : ptrdiff_t off = offset();
2733 :
2734 : // Alias consecutive jump targets.
2735 0 : if (off == current->lastTarget.offset + ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
2736 5165 : target->offset = current->lastTarget.offset;
2737 5165 : return true;
2738 : }
2739 :
2740 0 : target->offset = off;
2741 0 : current->lastTarget.offset = off;
2742 71113 : if (!emit1(JSOP_JUMPTARGET))
2743 : return false;
2744 71114 : return true;
2745 : }
2746 :
2747 : void
2748 0 : JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset)
2749 : {
2750 91762 : SET_JUMP_OFFSET(&code[jumpOffset], offset - jumpOffset);
2751 45881 : offset = jumpOffset;
2752 0 : }
2753 :
2754 : void
2755 0 : JumpList::patchAll(jsbytecode* code, JumpTarget target)
2756 : {
2757 : ptrdiff_t delta;
2758 0 : for (ptrdiff_t jumpOffset = offset; jumpOffset != -1; jumpOffset += delta) {
2759 45882 : jsbytecode* pc = &code[jumpOffset];
2760 0 : MOZ_ASSERT(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL);
2761 1 : delta = GET_JUMP_OFFSET(pc);
2762 1 : MOZ_ASSERT(delta < 0);
2763 45882 : ptrdiff_t span = target.offset - jumpOffset;
2764 91764 : SET_JUMP_OFFSET(pc, span);
2765 : }
2766 0 : }
2767 :
2768 : bool
2769 0 : BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump)
2770 : {
2771 : ptrdiff_t offset;
2772 45881 : if (!emitCheck(5, &offset))
2773 : return false;
2774 :
2775 0 : jsbytecode* code = this->code(offset);
2776 45881 : code[0] = jsbytecode(op);
2777 0 : MOZ_ASSERT(-1 <= jump->offset && jump->offset < offset);
2778 91762 : jump->push(this->code(0), offset);
2779 0 : updateDepth(offset);
2780 1 : return true;
2781 : }
2782 :
2783 : bool
2784 0 : BytecodeEmitter::emitJump(JSOp op, JumpList* jump)
2785 : {
2786 0 : if (!emitJumpNoFallthrough(op, jump))
2787 : return false;
2788 43457 : if (BytecodeFallsThrough(op)) {
2789 : JumpTarget fallthrough;
2790 1 : if (!emitJumpTarget(&fallthrough))
2791 0 : return false;
2792 : }
2793 : return true;
2794 : }
2795 :
2796 : bool
2797 2425 : BytecodeEmitter::emitBackwardJump(JSOp op, JumpTarget target, JumpList* jump, JumpTarget* fallthrough)
2798 : {
2799 2425 : if (!emitJumpNoFallthrough(op, jump))
2800 : return false;
2801 2425 : patchJumpsToTarget(*jump, target);
2802 :
2803 : // Unconditionally create a fallthrough for closing iterators, and as a
2804 : // target for break statements.
2805 2425 : if (!emitJumpTarget(fallthrough))
2806 : return false;
2807 2425 : return true;
2808 : }
2809 :
2810 : void
2811 0 : BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target)
2812 : {
2813 0 : MOZ_ASSERT(-1 <= jump.offset && jump.offset <= offset());
2814 1 : MOZ_ASSERT(0 <= target.offset && target.offset <= offset());
2815 1 : MOZ_ASSERT_IF(jump.offset != -1 && target.offset + 4 <= offset(),
2816 : BytecodeIsJumpTarget(JSOp(*code(target.offset))));
2817 45834 : jump.patchAll(code(0), target);
2818 0 : }
2819 :
2820 : bool
2821 52838 : BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump)
2822 : {
2823 52838 : if (jump.offset == -1)
2824 : return true;
2825 : JumpTarget target;
2826 38378 : if (!emitJumpTarget(&target))
2827 : return false;
2828 38379 : patchJumpsToTarget(jump, target);
2829 38379 : return true;
2830 : }
2831 :
2832 : bool
2833 0 : BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn)
2834 : {
2835 0 : if (pn && !updateSourceCoordNotes(pn->pn_pos.begin))
2836 : return false;
2837 97728 : return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
2838 : }
2839 :
2840 : bool
2841 10136 : BytecodeEmitter::emitDupAt(unsigned slotFromTop)
2842 : {
2843 10136 : MOZ_ASSERT(slotFromTop < unsigned(stackDepth));
2844 :
2845 10136 : if (slotFromTop == 0)
2846 1072 : return emit1(JSOP_DUP);
2847 :
2848 9064 : if (slotFromTop >= JS_BIT(24)) {
2849 0 : reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
2850 0 : return false;
2851 : }
2852 :
2853 : ptrdiff_t off;
2854 9064 : if (!emitN(JSOP_DUPAT, 3, &off))
2855 : return false;
2856 :
2857 0 : jsbytecode* pc = code(off);
2858 9064 : SET_UINT24(pc, slotFromTop);
2859 9064 : return true;
2860 : }
2861 :
2862 : bool
2863 0 : BytecodeEmitter::emitPopN(unsigned n)
2864 : {
2865 0 : MOZ_ASSERT(n != 0);
2866 :
2867 0 : if (n == 1)
2868 0 : return emit1(JSOP_POP);
2869 :
2870 : // 2 JSOP_POPs (2 bytes) are shorter than JSOP_POPN (3 bytes).
2871 2807 : if (n == 2)
2872 1441 : return emit1(JSOP_POP) && emit1(JSOP_POP);
2873 :
2874 1366 : return emitUint16Operand(JSOP_POPN, n);
2875 : }
2876 :
2877 : bool
2878 0 : BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind)
2879 : {
2880 4158 : return emit2(JSOP_CHECKISOBJ, uint8_t(kind));
2881 : }
2882 :
2883 : bool
2884 0 : BytecodeEmitter::emitCheckIsCallable(CheckIsCallableKind kind)
2885 : {
2886 0 : return emit2(JSOP_CHECKISCALLABLE, uint8_t(kind));
2887 : }
2888 :
2889 : static inline unsigned
2890 : LengthOfSetLine(unsigned line)
2891 : {
2892 131006 : return 1 /* SRC_SETLINE */ + (line > SN_4BYTE_OFFSET_MASK ? 4 : 1);
2893 : }
2894 :
2895 : /* Updates line number notes, not column notes. */
2896 : bool
2897 0 : BytecodeEmitter::updateLineNumberNotes(uint32_t offset)
2898 : {
2899 0 : ErrorReporter* er = &parser->errorReporter();
2900 : bool onThisLine;
2901 0 : if (!er->isOnThisLine(offset, currentLine(), &onThisLine)) {
2902 0 : er->reportErrorNoOffset(JSMSG_OUT_OF_MEMORY);
2903 0 : return false;
2904 : }
2905 :
2906 640259 : if (!onThisLine) {
2907 131002 : unsigned line = er->lineAt(offset);
2908 0 : unsigned delta = line - currentLine();
2909 :
2910 : /*
2911 : * Encode any change in the current source line number by using
2912 : * either several SRC_NEWLINE notes or just one SRC_SETLINE note,
2913 : * whichever consumes less space.
2914 : *
2915 : * NB: We handle backward line number deltas (possible with for
2916 : * loops where the update part is emitted after the body, but its
2917 : * line number is <= any line number in the body) here by letting
2918 : * unsigned delta_ wrap to a very large number, which triggers a
2919 : * SRC_SETLINE.
2920 : */
2921 131006 : current->currentLine = line;
2922 0 : current->lastColumn = 0;
2923 0 : if (delta >= LengthOfSetLine(line)) {
2924 0 : if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(line)))
2925 : return false;
2926 : } else {
2927 130411 : do {
2928 130414 : if (!newSrcNote(SRC_NEWLINE))
2929 : return false;
2930 : } while (--delta != 0);
2931 : }
2932 : }
2933 : return true;
2934 : }
2935 :
2936 : /* Updates the line number and column number information in the source notes. */
2937 : bool
2938 184122 : BytecodeEmitter::updateSourceCoordNotes(uint32_t offset)
2939 : {
2940 184122 : if (!updateLineNumberNotes(offset))
2941 : return false;
2942 :
2943 184121 : uint32_t columnIndex = parser->errorReporter().columnAt(offset);
2944 0 : ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(current->lastColumn);
2945 184123 : if (colspan != 0) {
2946 : // If the column span is so large that we can't store it, then just
2947 : // discard this information. This can happen with minimized or otherwise
2948 : // machine-generated code. Even gigantic column numbers are still
2949 : // valuable if you have a source map to relate them to something real;
2950 : // but it's better to fail soft here.
2951 137854 : if (!SN_REPRESENTABLE_COLSPAN(colspan))
2952 : return true;
2953 137854 : if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan)))
2954 : return false;
2955 137858 : current->lastColumn = columnIndex;
2956 : }
2957 : return true;
2958 : }
2959 :
2960 : bool
2961 2407 : BytecodeEmitter::emitLoopHead(ParseNode* nextpn, JumpTarget* top)
2962 : {
2963 2407 : if (nextpn) {
2964 : /*
2965 : * Try to give the JSOP_LOOPHEAD the same line number as the next
2966 : * instruction. nextpn is often a block, in which case the next
2967 : * instruction typically comes from the first statement inside.
2968 : */
2969 910 : if (nextpn->isKind(ParseNodeKind::LexicalScope))
2970 843 : nextpn = nextpn->scopeBody();
2971 1753 : MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList), nextpn->isArity(PN_LIST));
2972 910 : if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_head)
2973 842 : nextpn = nextpn->pn_head;
2974 910 : if (!updateSourceCoordNotes(nextpn->pn_pos.begin))
2975 : return false;
2976 : }
2977 :
2978 2407 : *top = { offset() };
2979 2407 : return emit1(JSOP_LOOPHEAD);
2980 : }
2981 :
2982 : bool
2983 0 : BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump)
2984 : {
2985 0 : if (nextpn) {
2986 : /* Update the line number, as for LOOPHEAD. */
2987 0 : if (nextpn->isKind(ParseNodeKind::LexicalScope))
2988 8 : nextpn = nextpn->scopeBody();
2989 1742 : MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList), nextpn->isArity(PN_LIST));
2990 0 : if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_head)
2991 0 : nextpn = nextpn->pn_head;
2992 0 : if (!updateSourceCoordNotes(nextpn->pn_pos.begin))
2993 : return false;
2994 : }
2995 :
2996 2407 : JumpTarget entry{ offset() };
2997 2407 : patchJumpsToTarget(entryJump, entry);
2998 :
2999 0 : LoopControl& loopInfo = innermostNestableControl->as<LoopControl>();
3000 2407 : MOZ_ASSERT(loopInfo.loopDepth() > 0);
3001 :
3002 2407 : uint8_t loopDepthAndFlags = PackLoopEntryDepthHintAndFlags(loopInfo.loopDepth(),
3003 4814 : loopInfo.canIonOsr());
3004 0 : return emit2(JSOP_LOOPENTRY, loopDepthAndFlags);
3005 : }
3006 :
3007 : void
3008 0 : BytecodeEmitter::checkTypeSet(JSOp op)
3009 : {
3010 296303 : if (CodeSpec[op].format & JOF_TYPESET) {
3011 198026 : if (typesetCount < UINT16_MAX)
3012 0 : typesetCount++;
3013 : }
3014 0 : }
3015 :
3016 : bool
3017 1813 : BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t operand)
3018 : {
3019 1813 : MOZ_ASSERT(operand <= UINT16_MAX);
3020 0 : if (!emit3(op, UINT16_LO(operand), UINT16_HI(operand)))
3021 : return false;
3022 : checkTypeSet(op);
3023 : return true;
3024 : }
3025 :
3026 : bool
3027 0 : BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand)
3028 : {
3029 : ptrdiff_t off;
3030 7215 : if (!emitN(op, 4, &off))
3031 : return false;
3032 0 : SET_UINT32(code(off), operand);
3033 : checkTypeSet(op);
3034 : return true;
3035 : }
3036 :
3037 : namespace {
3038 :
3039 : class NonLocalExitControl
3040 : {
3041 : public:
3042 : enum Kind
3043 : {
3044 : // IteratorClose is handled especially inside the exception unwinder.
3045 : Throw,
3046 :
3047 : // A 'continue' statement does not call IteratorClose for the loop it
3048 : // is continuing, i.e. excluding the target loop.
3049 : Continue,
3050 :
3051 : // A 'break' or 'return' statement does call IteratorClose for the
3052 : // loop it is breaking out of or returning from, i.e. including the
3053 : // target loop.
3054 : Break,
3055 : Return
3056 : };
3057 :
3058 : private:
3059 : BytecodeEmitter* bce_;
3060 : const uint32_t savedScopeNoteIndex_;
3061 : const int savedDepth_;
3062 : uint32_t openScopeNoteIndex_;
3063 : Kind kind_;
3064 :
3065 : NonLocalExitControl(const NonLocalExitControl&) = delete;
3066 :
3067 : MOZ_MUST_USE bool leaveScope(BytecodeEmitter::EmitterScope* scope);
3068 :
3069 : public:
3070 : NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
3071 0 : : bce_(bce),
3072 25692 : savedScopeNoteIndex_(bce->scopeNoteList.length()),
3073 0 : savedDepth_(bce->stackDepth),
3074 12846 : openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
3075 0 : kind_(kind)
3076 : { }
3077 :
3078 25692 : ~NonLocalExitControl() {
3079 36328 : for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length(); n++)
3080 10636 : bce_->scopeNoteList.recordEnd(n, bce_->offset(), bce_->inPrologue());
3081 12846 : bce_->stackDepth = savedDepth_;
3082 0 : }
3083 :
3084 : MOZ_MUST_USE bool prepareForNonLocalJump(BytecodeEmitter::NestableControl* target);
3085 :
3086 : MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
3087 0 : return prepareForNonLocalJump(nullptr);
3088 : }
3089 : };
3090 :
3091 : bool
3092 5318 : NonLocalExitControl::leaveScope(BytecodeEmitter::EmitterScope* es)
3093 : {
3094 5318 : if (!es->leave(bce_, /* nonLocal = */ true))
3095 : return false;
3096 :
3097 : // As we pop each scope due to the non-local jump, emit notes that
3098 : // record the extent of the enclosing scope. These notes will have
3099 : // their ends recorded in ~NonLocalExitControl().
3100 0 : uint32_t enclosingScopeIndex = ScopeNote::NoScopeIndex;
3101 5318 : if (es->enclosingInFrame())
3102 5318 : enclosingScopeIndex = es->enclosingInFrame()->index();
3103 10636 : if (!bce_->scopeNoteList.append(enclosingScopeIndex, bce_->offset(), bce_->inPrologue(),
3104 : openScopeNoteIndex_))
3105 : return false;
3106 0 : openScopeNoteIndex_ = bce_->scopeNoteList.length() - 1;
3107 :
3108 5318 : return true;
3109 : }
3110 :
3111 : /*
3112 : * Emit additional bytecode(s) for non-local jumps.
3113 : */
3114 : bool
3115 0 : NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* target)
3116 : {
3117 : using NestableControl = BytecodeEmitter::NestableControl;
3118 : using EmitterScope = BytecodeEmitter::EmitterScope;
3119 :
3120 0 : EmitterScope* es = bce_->innermostEmitterScope();
3121 12846 : int npops = 0;
3122 :
3123 38538 : AutoCheckUnstableEmitterScope cues(bce_);
3124 :
3125 : // For 'continue', 'break', and 'return' statements, emit IteratorClose
3126 : // bytecode inline. 'continue' statements do not call IteratorClose for
3127 : // the loop they are continuing.
3128 0 : bool emitIteratorClose = kind_ == Continue || kind_ == Break || kind_ == Return;
3129 0 : bool emitIteratorCloseAtTarget = emitIteratorClose && kind_ != Continue;
3130 :
3131 26008 : auto flushPops = [&npops](BytecodeEmitter* bce) {
3132 13004 : if (npops && !bce->emitPopN(npops))
3133 : return false;
3134 13004 : npops = 0;
3135 13004 : return true;
3136 12846 : };
3137 :
3138 : // Walk the nestable control stack and patch jumps.
3139 0 : for (NestableControl* control = bce_->innermostNestableControl;
3140 14066 : control != target;
3141 1220 : control = control->enclosing())
3142 : {
3143 : // Walk the scope stack and leave the scopes we entered. Leaving a scope
3144 : // may emit administrative ops like JSOP_POPLEXICALENV but never anything
3145 : // that manipulates the stack.
3146 2160 : for (; es != control->emitterScope(); es = es->enclosingInFrame()) {
3147 470 : if (!leaveScope(es))
3148 : return false;
3149 : }
3150 :
3151 1220 : switch (control->kind()) {
3152 : case StatementKind::Finally: {
3153 0 : TryFinallyControl& finallyControl = control->as<TryFinallyControl>();
3154 49 : if (finallyControl.emittingSubroutine()) {
3155 : /*
3156 : * There's a [exception or hole, retsub pc-index] pair and the
3157 : * possible return value on the stack that we need to pop.
3158 : */
3159 0 : npops += 3;
3160 : } else {
3161 49 : if (!flushPops(bce_))
3162 : return false;
3163 0 : if (!bce_->emitJump(JSOP_GOSUB, &finallyControl.gosubs)) // ...
3164 : return false;
3165 : }
3166 : break;
3167 : }
3168 :
3169 : case StatementKind::ForOfLoop:
3170 103 : if (emitIteratorClose) {
3171 0 : if (!flushPops(bce_))
3172 : return false;
3173 :
3174 0 : ForOfLoopControl& loopinfo = control->as<ForOfLoopControl>();
3175 0 : if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
3176 : /* isTarget = */ false))
3177 : { // ...
3178 : return false;
3179 : }
3180 : } else {
3181 : // The iterator next method, the iterator, and the current
3182 : // value are on the stack.
3183 0 : npops += 3;
3184 : }
3185 : break;
3186 :
3187 : case StatementKind::ForInLoop:
3188 0 : if (!flushPops(bce_))
3189 : return false;
3190 :
3191 : // The iterator and the current value are on the stack.
3192 6 : if (!bce_->emit1(JSOP_POP)) // ... ITER
3193 : return false;
3194 0 : if (!bce_->emit1(JSOP_ENDITER)) // ...
3195 : return false;
3196 : break;
3197 :
3198 : default:
3199 : break;
3200 : }
3201 : }
3202 :
3203 0 : if (!flushPops(bce_))
3204 : return false;
3205 :
3206 0 : if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
3207 44 : ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
3208 44 : if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
3209 : /* isTarget = */ true))
3210 : { // ... UNDEF UNDEF UNDEF
3211 : return false;
3212 : }
3213 : }
3214 :
3215 0 : EmitterScope* targetEmitterScope = target ? target->emitterScope() : bce_->varEmitterScope;
3216 22542 : for (; es != targetEmitterScope; es = es->enclosingInFrame()) {
3217 0 : if (!leaveScope(es))
3218 : return false;
3219 : }
3220 :
3221 : return true;
3222 : }
3223 :
3224 : } // anonymous namespace
3225 :
3226 : bool
3227 1525 : BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist, SrcNoteType noteType)
3228 : {
3229 : NonLocalExitControl nle(this, noteType == SRC_CONTINUE
3230 : ? NonLocalExitControl::Continue
3231 0 : : NonLocalExitControl::Break);
3232 :
3233 1525 : if (!nle.prepareForNonLocalJump(target))
3234 : return false;
3235 :
3236 1525 : if (noteType != SRC_NULL) {
3237 0 : if (!newSrcNote(noteType))
3238 : return false;
3239 : }
3240 :
3241 1525 : return emitJump(JSOP_GOTO, jumplist);
3242 : }
3243 :
3244 : Scope*
3245 0 : BytecodeEmitter::innermostScope() const
3246 : {
3247 0 : return innermostEmitterScope()->scope(this);
3248 : }
3249 :
3250 : bool
3251 1 : BytecodeEmitter::emitIndex32(JSOp op, uint32_t index)
3252 : {
3253 0 : MOZ_ASSERT(checkStrictOrSloppy(op));
3254 :
3255 30915 : const size_t len = 1 + UINT32_INDEX_LEN;
3256 30915 : MOZ_ASSERT(len == size_t(CodeSpec[op].length));
3257 :
3258 : ptrdiff_t offset;
3259 0 : if (!emitCheck(len, &offset))
3260 : return false;
3261 :
3262 30914 : jsbytecode* code = this->code(offset);
3263 30914 : code[0] = jsbytecode(op);
3264 30914 : SET_UINT32_INDEX(code, index);
3265 1 : checkTypeSet(op);
3266 30914 : updateDepth(offset);
3267 0 : return true;
3268 : }
3269 :
3270 : bool
3271 0 : BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index)
3272 : {
3273 0 : MOZ_ASSERT(checkStrictOrSloppy(op));
3274 :
3275 164733 : const size_t len = CodeSpec[op].length;
3276 164733 : MOZ_ASSERT(len >= 1 + UINT32_INDEX_LEN);
3277 :
3278 : ptrdiff_t offset;
3279 164733 : if (!emitCheck(len, &offset))
3280 : return false;
3281 :
3282 164734 : jsbytecode* code = this->code(offset);
3283 164734 : code[0] = jsbytecode(op);
3284 164734 : SET_UINT32_INDEX(code, index);
3285 0 : checkTypeSet(op);
3286 164734 : updateDepth(offset);
3287 0 : return true;
3288 : }
3289 :
3290 : bool
3291 153046 : BytecodeEmitter::emitAtomOp(JSAtom* atom, JSOp op)
3292 : {
3293 0 : MOZ_ASSERT(atom);
3294 153046 : MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
3295 :
3296 : // .generator lookups should be emitted as JSOP_GETALIASEDVAR instead of
3297 : // JSOP_GETNAME etc, to bypass |with| objects on the scope chain.
3298 : // It's safe to emit .this lookups though because |with| objects skip
3299 : // those.
3300 215258 : MOZ_ASSERT_IF(op == JSOP_GETNAME || op == JSOP_GETGNAME,
3301 : atom != cx->names().dotGenerator);
3302 :
3303 252628 : if (op == JSOP_GETPROP && atom == cx->names().length) {
3304 : /* Specialize length accesses for the interpreter. */
3305 0 : op = JSOP_LENGTH;
3306 : }
3307 :
3308 : uint32_t index;
3309 0 : if (!makeAtomIndex(atom, &index))
3310 : return false;
3311 :
3312 0 : return emitIndexOp(op, index);
3313 : }
3314 :
3315 : bool
3316 104131 : BytecodeEmitter::emitAtomOp(ParseNode* pn, JSOp op)
3317 : {
3318 0 : MOZ_ASSERT(pn->pn_atom != nullptr);
3319 104131 : return emitAtomOp(pn->pn_atom, op);
3320 : }
3321 :
3322 : bool
3323 1962 : BytecodeEmitter::emitInternedScopeOp(uint32_t index, JSOp op)
3324 : {
3325 1962 : MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE);
3326 0 : MOZ_ASSERT(index < scopeList.length());
3327 0 : return emitIndex32(op, index);
3328 : }
3329 :
3330 : bool
3331 1 : BytecodeEmitter::emitInternedObjectOp(uint32_t index, JSOp op)
3332 : {
3333 1 : MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
3334 166 : MOZ_ASSERT(index < objectList.length);
3335 0 : return emitIndex32(op, index);
3336 : }
3337 :
3338 : bool
3339 0 : BytecodeEmitter::emitObjectOp(ObjectBox* objbox, JSOp op)
3340 : {
3341 159 : return emitInternedObjectOp(objectList.add(objbox), op);
3342 : }
3343 :
3344 : bool
3345 7 : BytecodeEmitter::emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op)
3346 : {
3347 7 : uint32_t index = objectList.add(objbox1);
3348 0 : objectList.add(objbox2);
3349 7 : return emitInternedObjectOp(index, op);
3350 : }
3351 :
3352 : bool
3353 0 : BytecodeEmitter::emitRegExp(uint32_t index)
3354 : {
3355 0 : return emitIndex32(JSOP_REGEXP, index);
3356 : }
3357 :
3358 : bool
3359 86521 : BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot)
3360 : {
3361 86521 : MOZ_ASSERT(JOF_OPTYPE(op) != JOF_ENVCOORD);
3362 86521 : MOZ_ASSERT(IsLocalOp(op));
3363 :
3364 : ptrdiff_t off;
3365 86521 : if (!emitN(op, LOCALNO_LEN, &off))
3366 : return false;
3367 :
3368 173050 : SET_LOCALNO(code(off), slot);
3369 0 : return true;
3370 : }
3371 :
3372 : bool
3373 23280 : BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot)
3374 : {
3375 23280 : MOZ_ASSERT(IsArgOp(op));
3376 : ptrdiff_t off;
3377 0 : if (!emitN(op, ARGNO_LEN, &off))
3378 : return false;
3379 :
3380 46560 : SET_ARGNO(code(off), slot);
3381 23280 : return true;
3382 : }
3383 :
3384 : bool
3385 0 : BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec)
3386 : {
3387 0 : MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ENVCOORD);
3388 :
3389 33344 : unsigned n = ENVCOORD_HOPS_LEN + ENVCOORD_SLOT_LEN;
3390 33344 : MOZ_ASSERT(int(n) + 1 /* op */ == CodeSpec[op].length);
3391 :
3392 : ptrdiff_t off;
3393 1 : if (!emitN(op, n, &off))
3394 : return false;
3395 :
3396 33344 : jsbytecode* pc = code(off);
3397 66688 : SET_ENVCOORD_HOPS(pc, ec.hops());
3398 0 : pc += ENVCOORD_HOPS_LEN;
3399 0 : SET_ENVCOORD_SLOT(pc, ec.slot());
3400 0 : pc += ENVCOORD_SLOT_LEN;
3401 : checkTypeSet(op);
3402 : return true;
3403 : }
3404 :
3405 : static JSOp
3406 0 : GetIncDecInfo(ParseNodeKind kind, bool* post)
3407 : {
3408 648 : MOZ_ASSERT(kind == ParseNodeKind::PostIncrement ||
3409 : kind == ParseNodeKind::PreIncrement ||
3410 : kind == ParseNodeKind::PostDecrement ||
3411 : kind == ParseNodeKind::PreDecrement);
3412 648 : *post = kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind::PostDecrement;
3413 : return (kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind::PreIncrement)
3414 648 : ? JSOP_ADD
3415 648 : : JSOP_SUB;
3416 : }
3417 :
3418 : JSOp
3419 0 : BytecodeEmitter::strictifySetNameOp(JSOp op)
3420 : {
3421 0 : switch (op) {
3422 : case JSOP_SETNAME:
3423 0 : if (sc->strict())
3424 159 : op = JSOP_STRICTSETNAME;
3425 : break;
3426 : case JSOP_SETGNAME:
3427 0 : if (sc->strict())
3428 0 : op = JSOP_STRICTSETGNAME;
3429 : break;
3430 : default:;
3431 : }
3432 0 : return op;
3433 : }
3434 :
3435 : bool
3436 31591 : BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
3437 : {
3438 0 : if (!CheckRecursionLimit(cx))
3439 : return false;
3440 :
3441 : restart:
3442 :
3443 31595 : switch (pn->getKind()) {
3444 : // Trivial cases with no side effects.
3445 : case ParseNodeKind::EmptyStatement:
3446 : case ParseNodeKind::String:
3447 : case ParseNodeKind::TemplateString:
3448 : case ParseNodeKind::RegExp:
3449 : case ParseNodeKind::True:
3450 : case ParseNodeKind::False:
3451 : case ParseNodeKind::Null:
3452 : case ParseNodeKind::RawUndefined:
3453 : case ParseNodeKind::Elision:
3454 : case ParseNodeKind::Generator:
3455 : case ParseNodeKind::Number:
3456 : case ParseNodeKind::ObjectPropertyName:
3457 0 : MOZ_ASSERT(pn->isArity(PN_NULLARY));
3458 0 : *answer = false;
3459 232 : return true;
3460 :
3461 : // |this| can throw in derived class constructors, including nested arrow
3462 : // functions or eval.
3463 : case ParseNodeKind::This:
3464 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3465 0 : *answer = sc->needsThisTDZChecks();
3466 0 : return true;
3467 :
3468 : // Trivial binary nodes with more token pos holders.
3469 : case ParseNodeKind::NewTarget:
3470 : case ParseNodeKind::ImportMeta:
3471 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3472 0 : MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder));
3473 0 : MOZ_ASSERT(pn->pn_right->isKind(ParseNodeKind::PosHolder));
3474 0 : *answer = false;
3475 0 : return true;
3476 :
3477 : case ParseNodeKind::Break:
3478 : case ParseNodeKind::Continue:
3479 : case ParseNodeKind::Debugger:
3480 0 : MOZ_ASSERT(pn->isArity(PN_NULLARY));
3481 0 : *answer = true;
3482 0 : return true;
3483 :
3484 : // Watch out for getters!
3485 : case ParseNodeKind::Dot:
3486 0 : MOZ_ASSERT(pn->isArity(PN_NAME));
3487 0 : *answer = true;
3488 18 : return true;
3489 :
3490 : // Unary cases with side effects only if the child has them.
3491 : case ParseNodeKind::TypeOfExpr:
3492 : case ParseNodeKind::Void:
3493 : case ParseNodeKind::Not:
3494 4 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3495 4 : return checkSideEffects(pn->pn_kid, answer);
3496 :
3497 : // Even if the name expression is effect-free, performing ToPropertyKey on
3498 : // it might not be effect-free:
3499 : //
3500 : // RegExp.prototype.toString = () => { throw 42; };
3501 : // ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
3502 : //
3503 : // function Q() {
3504 : // ({ [new.target]: 0 });
3505 : // }
3506 : // Q.toString = () => { throw 17; };
3507 : // new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
3508 : case ParseNodeKind::ComputedName:
3509 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3510 0 : *answer = true;
3511 0 : return true;
3512 :
3513 : // Looking up or evaluating the associated name could throw.
3514 : case ParseNodeKind::TypeOfName:
3515 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3516 0 : *answer = true;
3517 0 : return true;
3518 :
3519 : // This unary case has side effects on the enclosing object, sure. But
3520 : // that's not the question this function answers: it's whether the
3521 : // operation may have a side effect on something *other* than the result
3522 : // of the overall operation in which it's embedded. The answer to that
3523 : // is no, because an object literal having a mutated prototype only
3524 : // produces a value, without affecting anything else.
3525 : case ParseNodeKind::MutateProto:
3526 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3527 0 : return checkSideEffects(pn->pn_kid, answer);
3528 :
3529 : // Unary cases with obvious side effects.
3530 : case ParseNodeKind::PreIncrement:
3531 : case ParseNodeKind::PostIncrement:
3532 : case ParseNodeKind::PreDecrement:
3533 : case ParseNodeKind::PostDecrement:
3534 : case ParseNodeKind::Throw:
3535 205 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3536 205 : *answer = true;
3537 205 : return true;
3538 :
3539 : // These might invoke valueOf/toString, even with a subexpression without
3540 : // side effects! Consider |+{ valueOf: null, toString: null }|.
3541 : case ParseNodeKind::BitNot:
3542 : case ParseNodeKind::Pos:
3543 : case ParseNodeKind::Neg:
3544 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3545 0 : *answer = true;
3546 0 : return true;
3547 :
3548 : // This invokes the (user-controllable) iterator protocol.
3549 : case ParseNodeKind::Spread:
3550 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3551 0 : *answer = true;
3552 0 : return true;
3553 :
3554 : case ParseNodeKind::InitialYield:
3555 : case ParseNodeKind::YieldStar:
3556 : case ParseNodeKind::Yield:
3557 : case ParseNodeKind::Await:
3558 665 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3559 665 : *answer = true;
3560 665 : return true;
3561 :
3562 : // Deletion generally has side effects, even if isolated cases have none.
3563 : case ParseNodeKind::DeleteName:
3564 : case ParseNodeKind::DeleteProp:
3565 : case ParseNodeKind::DeleteElem:
3566 360 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3567 360 : *answer = true;
3568 360 : return true;
3569 :
3570 : // Deletion of a non-Reference expression has side effects only through
3571 : // evaluating the expression.
3572 : case ParseNodeKind::DeleteExpr: {
3573 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3574 0 : ParseNode* expr = pn->pn_kid;
3575 0 : return checkSideEffects(expr, answer);
3576 : }
3577 :
3578 : case ParseNodeKind::ExpressionStatement:
3579 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3580 0 : return checkSideEffects(pn->pn_kid, answer);
3581 :
3582 : // Binary cases with obvious side effects.
3583 : case ParseNodeKind::Assign:
3584 : case ParseNodeKind::AddAssign:
3585 : case ParseNodeKind::SubAssign:
3586 : case ParseNodeKind::BitOrAssign:
3587 : case ParseNodeKind::BitXorAssign:
3588 : case ParseNodeKind::BitAndAssign:
3589 : case ParseNodeKind::LshAssign:
3590 : case ParseNodeKind::RshAssign:
3591 : case ParseNodeKind::UrshAssign:
3592 : case ParseNodeKind::MulAssign:
3593 : case ParseNodeKind::DivAssign:
3594 : case ParseNodeKind::ModAssign:
3595 : case ParseNodeKind::PowAssign:
3596 : case ParseNodeKind::SetThis:
3597 11522 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3598 11522 : *answer = true;
3599 11522 : return true;
3600 :
3601 : case ParseNodeKind::StatementList:
3602 : // Strict equality operations and logical operators are well-behaved and
3603 : // perform no conversions.
3604 : case ParseNodeKind::Or:
3605 : case ParseNodeKind::And:
3606 : case ParseNodeKind::StrictEq:
3607 : case ParseNodeKind::StrictNe:
3608 : // Any subexpression of a comma expression could be effectful.
3609 : case ParseNodeKind::Comma:
3610 9 : MOZ_ASSERT(pn->pn_count > 0);
3611 : MOZ_FALLTHROUGH;
3612 : // Subcomponents of a literal may be effectful.
3613 : case ParseNodeKind::Array:
3614 : case ParseNodeKind::Object:
3615 9 : MOZ_ASSERT(pn->isArity(PN_LIST));
3616 9 : for (ParseNode* item = pn->pn_head; item; item = item->pn_next) {
3617 9 : if (!checkSideEffects(item, answer))
3618 : return false;
3619 0 : if (*answer)
3620 : return true;
3621 : }
3622 : return true;
3623 :
3624 : // Most other binary operations (parsed as lists in SpiderMonkey) may
3625 : // perform conversions triggering side effects. Math operations perform
3626 : // ToNumber and may fail invoking invalid user-defined toString/valueOf:
3627 : // |5 < { toString: null }|. |instanceof| throws if provided a
3628 : // non-object constructor: |null instanceof null|. |in| throws if given
3629 : // a non-object RHS: |5 in null|.
3630 : case ParseNodeKind::BitOr:
3631 : case ParseNodeKind::BitXor:
3632 : case ParseNodeKind::BitAnd:
3633 : case ParseNodeKind::Eq:
3634 : case ParseNodeKind::Ne:
3635 : case ParseNodeKind::Lt:
3636 : case ParseNodeKind::Le:
3637 : case ParseNodeKind::Gt:
3638 : case ParseNodeKind::Ge:
3639 : case ParseNodeKind::InstanceOf:
3640 : case ParseNodeKind::In:
3641 : case ParseNodeKind::Lsh:
3642 : case ParseNodeKind::Rsh:
3643 : case ParseNodeKind::Ursh:
3644 : case ParseNodeKind::Add:
3645 : case ParseNodeKind::Sub:
3646 : case ParseNodeKind::Star:
3647 : case ParseNodeKind::Div:
3648 : case ParseNodeKind::Mod:
3649 : case ParseNodeKind::Pow:
3650 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3651 0 : MOZ_ASSERT(pn->pn_count >= 2);
3652 0 : *answer = true;
3653 0 : return true;
3654 :
3655 : case ParseNodeKind::Colon:
3656 : case ParseNodeKind::Case:
3657 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3658 0 : if (!checkSideEffects(pn->pn_left, answer))
3659 : return false;
3660 0 : if (*answer)
3661 : return true;
3662 0 : return checkSideEffects(pn->pn_right, answer);
3663 :
3664 : // More getters.
3665 : case ParseNodeKind::Elem:
3666 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3667 0 : *answer = true;
3668 0 : return true;
3669 :
3670 : // These affect visible names in this code, or in other code.
3671 : case ParseNodeKind::Import:
3672 : case ParseNodeKind::ExportFrom:
3673 : case ParseNodeKind::ExportDefault:
3674 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3675 0 : *answer = true;
3676 0 : return true;
3677 :
3678 : // Likewise.
3679 : case ParseNodeKind::Export:
3680 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3681 0 : *answer = true;
3682 0 : return true;
3683 :
3684 : // Every part of a loop might be effect-free, but looping infinitely *is*
3685 : // an effect. (Language lawyer trivia: C++ says threads can be assumed
3686 : // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
3687 : // implementation's equivalent of the below could set |*answer = false;|
3688 : // if all loop sub-nodes set |*answer = false|!)
3689 : case ParseNodeKind::DoWhile:
3690 : case ParseNodeKind::While:
3691 : case ParseNodeKind::For:
3692 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3693 0 : *answer = true;
3694 0 : return true;
3695 :
3696 : // Declarations affect the name set of the relevant scope.
3697 : case ParseNodeKind::Var:
3698 : case ParseNodeKind::Const:
3699 : case ParseNodeKind::Let:
3700 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3701 0 : *answer = true;
3702 0 : return true;
3703 :
3704 : case ParseNodeKind::If:
3705 : case ParseNodeKind::Conditional:
3706 1 : MOZ_ASSERT(pn->isArity(PN_TERNARY));
3707 1 : if (!checkSideEffects(pn->pn_kid1, answer))
3708 : return false;
3709 1 : if (*answer)
3710 : return true;
3711 0 : if (!checkSideEffects(pn->pn_kid2, answer))
3712 : return false;
3713 0 : if (*answer)
3714 : return true;
3715 0 : if ((pn = pn->pn_kid3))
3716 : goto restart;
3717 : return true;
3718 :
3719 : // Function calls can invoke non-local code.
3720 : case ParseNodeKind::New:
3721 : case ParseNodeKind::Call:
3722 : case ParseNodeKind::TaggedTemplate:
3723 : case ParseNodeKind::SuperCall:
3724 18573 : MOZ_ASSERT(pn->isArity(PN_LIST));
3725 18573 : *answer = true;
3726 1 : return true;
3727 :
3728 : case ParseNodeKind::Pipeline:
3729 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3730 0 : MOZ_ASSERT(pn->pn_count >= 2);
3731 0 : *answer = true;
3732 0 : return true;
3733 :
3734 : // Classes typically introduce names. Even if no name is introduced,
3735 : // the heritage and/or class body (through computed property names)
3736 : // usually have effects.
3737 : case ParseNodeKind::Class:
3738 0 : MOZ_ASSERT(pn->isArity(PN_TERNARY));
3739 0 : *answer = true;
3740 0 : return true;
3741 :
3742 : // |with| calls |ToObject| on its expression and so throws if that value
3743 : // is null/undefined.
3744 : case ParseNodeKind::With:
3745 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3746 0 : *answer = true;
3747 0 : return true;
3748 :
3749 : case ParseNodeKind::Return:
3750 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3751 0 : *answer = true;
3752 0 : return true;
3753 :
3754 : case ParseNodeKind::Name:
3755 6 : MOZ_ASSERT(pn->isArity(PN_NAME));
3756 6 : *answer = true;
3757 6 : return true;
3758 :
3759 : // Shorthands could trigger getters: the |x| in the object literal in
3760 : // |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
3761 : // one. (Of course, it isn't necessary to use |with| for a shorthand to
3762 : // trigger a getter.)
3763 : case ParseNodeKind::Shorthand:
3764 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3765 0 : *answer = true;
3766 0 : return true;
3767 :
3768 : case ParseNodeKind::Function:
3769 0 : MOZ_ASSERT(pn->isArity(PN_CODE));
3770 : /*
3771 : * A named function, contrary to ES3, is no longer effectful, because
3772 : * we bind its name lexically (using JSOP_CALLEE) instead of creating
3773 : * an Object instance and binding a readonly, permanent property in it
3774 : * (the object and binding can be detected and hijacked or captured).
3775 : * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
3776 : */
3777 0 : *answer = false;
3778 0 : return true;
3779 :
3780 : case ParseNodeKind::Module:
3781 0 : *answer = false;
3782 0 : return true;
3783 :
3784 : case ParseNodeKind::Try:
3785 0 : MOZ_ASSERT(pn->isArity(PN_TERNARY));
3786 0 : if (!checkSideEffects(pn->pn_kid1, answer))
3787 : return false;
3788 0 : if (*answer)
3789 : return true;
3790 0 : if (ParseNode* catchScope = pn->pn_kid2) {
3791 0 : MOZ_ASSERT(catchScope->isKind(ParseNodeKind::LexicalScope));
3792 0 : if (!checkSideEffects(catchScope, answer))
3793 : return false;
3794 0 : if (*answer)
3795 : return true;
3796 : }
3797 0 : if (ParseNode* finallyBlock = pn->pn_kid3) {
3798 0 : if (!checkSideEffects(finallyBlock, answer))
3799 : return false;
3800 : }
3801 : return true;
3802 :
3803 : case ParseNodeKind::Catch:
3804 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3805 0 : if (ParseNode* name = pn->pn_left) {
3806 0 : if (!checkSideEffects(name, answer))
3807 : return false;
3808 0 : if (*answer)
3809 : return true;
3810 : }
3811 0 : return checkSideEffects(pn->pn_right, answer);
3812 :
3813 : case ParseNodeKind::Switch:
3814 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3815 0 : if (!checkSideEffects(pn->pn_left, answer))
3816 : return false;
3817 0 : return *answer || checkSideEffects(pn->pn_right, answer);
3818 :
3819 : case ParseNodeKind::Label:
3820 0 : MOZ_ASSERT(pn->isArity(PN_NAME));
3821 0 : return checkSideEffects(pn->expr(), answer);
3822 :
3823 : case ParseNodeKind::LexicalScope:
3824 0 : MOZ_ASSERT(pn->isArity(PN_SCOPE));
3825 0 : return checkSideEffects(pn->scopeBody(), answer);
3826 :
3827 : // We could methodically check every interpolated expression, but it's
3828 : // probably not worth the trouble. Treat template strings as effect-free
3829 : // only if they don't contain any substitutions.
3830 : case ParseNodeKind::TemplateStringList:
3831 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3832 0 : MOZ_ASSERT(pn->pn_count > 0);
3833 0 : MOZ_ASSERT((pn->pn_count % 2) == 1,
3834 : "template strings must alternate template and substitution "
3835 : "parts");
3836 0 : *answer = pn->pn_count > 1;
3837 0 : return true;
3838 :
3839 : // This should be unreachable but is left as-is for now.
3840 : case ParseNodeKind::ParamsBody:
3841 0 : *answer = true;
3842 0 : return true;
3843 :
3844 : case ParseNodeKind::ForIn: // by ParseNodeKind::For
3845 : case ParseNodeKind::ForOf: // by ParseNodeKind::For
3846 : case ParseNodeKind::ForHead: // by ParseNodeKind::For
3847 : case ParseNodeKind::ClassMethod: // by ParseNodeKind::Class
3848 : case ParseNodeKind::ClassNames: // by ParseNodeKind::Class
3849 : case ParseNodeKind::ClassMethodList: // by ParseNodeKind::Class
3850 : case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
3851 : case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
3852 : case ParseNodeKind::ExportBatchSpec:// by ParseNodeKind::Export
3853 : case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
3854 : case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
3855 : case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
3856 : case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
3857 : case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
3858 0 : MOZ_CRASH("handled by parent nodes");
3859 :
3860 : case ParseNodeKind::Limit: // invalid sentinel value
3861 0 : MOZ_CRASH("invalid node kind");
3862 : }
3863 :
3864 0 : MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in "
3865 : "BytecodeEmitter::checkSideEffects");
3866 : }
3867 :
3868 : bool
3869 0 : BytecodeEmitter::isInLoop()
3870 : {
3871 0 : return findInnermostNestableControl<LoopControl>();
3872 : }
3873 :
3874 : bool
3875 0 : BytecodeEmitter::checkSingletonContext()
3876 : {
3877 43298 : if (!script->treatAsRunOnce() || sc->isFunctionBox() || isInLoop())
3878 : return false;
3879 842 : hasSingletons = true;
3880 0 : return true;
3881 : }
3882 :
3883 : bool
3884 0 : BytecodeEmitter::checkRunOnceContext()
3885 : {
3886 0 : return checkSingletonContext() || (!isInLoop() && isRunOnceLambda());
3887 : }
3888 :
3889 : bool
3890 0 : BytecodeEmitter::needsImplicitThis()
3891 : {
3892 : // Short-circuit if there is an enclosing 'with' scope.
3893 0 : if (sc->inWith())
3894 : return true;
3895 :
3896 : // Otherwise see if the current point is under a 'with'.
3897 0 : for (EmitterScope* es = innermostEmitterScope(); es; es = es->enclosingInFrame()) {
3898 913 : if (es->scope(this)->kind() == ScopeKind::With)
3899 : return true;
3900 : }
3901 :
3902 : return false;
3903 : }
3904 :
3905 : void
3906 0 : BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext* cx)
3907 : {
3908 : // Note: when parsing off thread the resulting scripts need to be handed to
3909 : // the debugger after rejoining to the main thread.
3910 13449 : if (cx->helperThread())
3911 : return;
3912 :
3913 : // Lazy scripts are never top level (despite always being invoked with a
3914 : // nullptr parent), and so the hook should never be fired.
3915 0 : if (emitterMode != LazyFunction && !parent)
3916 2432 : Debugger::onNewScript(cx, script);
3917 : }
3918 :
3919 : void
3920 0 : BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
3921 : {
3922 0 : MOZ_ASSERT_IF(!pn, this->scriptStartOffsetSet);
3923 0 : uint32_t offset = pn ? pn->pn_pos.begin : this->scriptStartOffset;
3924 :
3925 : va_list args;
3926 0 : va_start(args, errorNumber);
3927 :
3928 0 : parser->errorReporter().errorAtVA(offset, errorNumber, &args);
3929 :
3930 0 : va_end(args);
3931 0 : }
3932 :
3933 : bool
3934 0 : BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
3935 : {
3936 0 : MOZ_ASSERT_IF(!pn, this->scriptStartOffsetSet);
3937 1 : uint32_t offset = pn ? pn->pn_pos.begin : this->scriptStartOffset;
3938 :
3939 : va_list args;
3940 1 : va_start(args, errorNumber);
3941 :
3942 2 : bool result = parser->errorReporter().reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args);
3943 :
3944 1 : va_end(args);
3945 1 : return result;
3946 : }
3947 :
3948 : bool
3949 4739 : BytecodeEmitter::emitNewInit(JSProtoKey key)
3950 : {
3951 4739 : const size_t len = 1 + UINT32_INDEX_LEN;
3952 : ptrdiff_t offset;
3953 0 : if (!emitCheck(len, &offset))
3954 : return false;
3955 :
3956 4739 : jsbytecode* code = this->code(offset);
3957 4739 : code[0] = JSOP_NEWINIT;
3958 0 : code[1] = jsbytecode(key);
3959 4739 : code[2] = 0;
3960 4739 : code[3] = 0;
3961 4739 : code[4] = 0;
3962 4739 : checkTypeSet(JSOP_NEWINIT);
3963 0 : updateDepth(offset);
3964 4739 : return true;
3965 : }
3966 :
3967 : bool
3968 0 : BytecodeEmitter::iteratorResultShape(unsigned* shape)
3969 : {
3970 : // No need to do any guessing for the object kind, since we know exactly how
3971 : // many properties we plan to have.
3972 0 : gc::AllocKind kind = gc::GetGCObjectKind(2);
3973 204 : RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
3974 102 : if (!obj)
3975 : return false;
3976 :
3977 0 : Rooted<jsid> value_id(cx, NameToId(cx->names().value));
3978 0 : Rooted<jsid> done_id(cx, NameToId(cx->names().done));
3979 204 : if (!NativeDefineDataProperty(cx, obj, value_id, UndefinedHandleValue, JSPROP_ENUMERATE))
3980 : return false;
3981 0 : if (!NativeDefineDataProperty(cx, obj, done_id, UndefinedHandleValue, JSPROP_ENUMERATE))
3982 : return false;
3983 :
3984 204 : ObjectBox* objbox = parser->newObjectBox(obj);
3985 102 : if (!objbox)
3986 : return false;
3987 :
3988 102 : *shape = objectList.add(objbox);
3989 :
3990 0 : return true;
3991 : }
3992 :
3993 : bool
3994 0 : BytecodeEmitter::emitPrepareIteratorResult()
3995 : {
3996 : unsigned shape;
3997 102 : if (!iteratorResultShape(&shape))
3998 : return false;
3999 102 : return emitIndex32(JSOP_NEWOBJECT, shape);
4000 : }
4001 :
4002 : bool
4003 102 : BytecodeEmitter::emitFinishIteratorResult(bool done)
4004 : {
4005 : uint32_t value_id;
4006 306 : if (!makeAtomIndex(cx->names().value, &value_id))
4007 : return false;
4008 : uint32_t done_id;
4009 306 : if (!makeAtomIndex(cx->names().done, &done_id))
4010 : return false;
4011 :
4012 102 : if (!emitIndex32(JSOP_INITPROP, value_id))
4013 : return false;
4014 102 : if (!emit1(done ? JSOP_TRUE : JSOP_FALSE))
4015 : return false;
4016 102 : if (!emitIndex32(JSOP_INITPROP, done_id))
4017 : return false;
4018 102 : return true;
4019 : }
4020 :
4021 : bool
4022 132137 : BytecodeEmitter::emitGetNameAtLocation(JSAtom* name, const NameLocation& loc, bool callContext)
4023 : {
4024 132137 : switch (loc.kind()) {
4025 : case NameLocation::Kind::Dynamic:
4026 14738 : if (!emitAtomOp(name, JSOP_GETNAME))
4027 : return false;
4028 : break;
4029 :
4030 : case NameLocation::Kind::Global:
4031 16368 : if (!emitAtomOp(name, JSOP_GETGNAME))
4032 : return false;
4033 : break;
4034 :
4035 : case NameLocation::Kind::Intrinsic:
4036 3321 : if (!emitAtomOp(name, JSOP_GETINTRINSIC))
4037 : return false;
4038 : break;
4039 :
4040 : case NameLocation::Kind::NamedLambdaCallee:
4041 0 : if (!emit1(JSOP_CALLEE))
4042 : return false;
4043 : break;
4044 :
4045 : case NameLocation::Kind::Import:
4046 0 : if (!emitAtomOp(name, JSOP_GETIMPORT))
4047 : return false;
4048 : break;
4049 :
4050 : case NameLocation::Kind::ArgumentSlot:
4051 21607 : if (!emitArgOp(JSOP_GETARG, loc.argumentSlot()))
4052 : return false;
4053 : break;
4054 :
4055 : case NameLocation::Kind::FrameSlot:
4056 50963 : if (loc.isLexical()) {
4057 0 : if (!emitTDZCheckIfNeeded(name, loc))
4058 : return false;
4059 : }
4060 50963 : if (!emitLocalOp(JSOP_GETLOCAL, loc.frameSlot()))
4061 : return false;
4062 : break;
4063 :
4064 : case NameLocation::Kind::EnvironmentCoordinate:
4065 0 : if (loc.isLexical()) {
4066 10573 : if (!emitTDZCheckIfNeeded(name, loc))
4067 : return false;
4068 : }
4069 25112 : if (!emitEnvCoordOp(JSOP_GETALIASEDVAR, loc.environmentCoordinate()))
4070 : return false;
4071 : break;
4072 :
4073 : case NameLocation::Kind::DynamicAnnexBVar:
4074 0 : MOZ_CRASH("Synthesized vars for Annex B.3.3 should only be used in initialization");
4075 : }
4076 :
4077 : // Need to provide |this| value for call.
4078 0 : if (callContext) {
4079 6589 : switch (loc.kind()) {
4080 : case NameLocation::Kind::Dynamic: {
4081 511 : JSOp thisOp = needsImplicitThis() ? JSOP_IMPLICITTHIS : JSOP_GIMPLICITTHIS;
4082 511 : if (!emitAtomOp(name, thisOp))
4083 : return false;
4084 : break;
4085 : }
4086 :
4087 : case NameLocation::Kind::Global:
4088 2542 : if (!emitAtomOp(name, JSOP_GIMPLICITTHIS))
4089 : return false;
4090 : break;
4091 :
4092 : case NameLocation::Kind::Intrinsic:
4093 : case NameLocation::Kind::NamedLambdaCallee:
4094 : case NameLocation::Kind::Import:
4095 : case NameLocation::Kind::ArgumentSlot:
4096 : case NameLocation::Kind::FrameSlot:
4097 : case NameLocation::Kind::EnvironmentCoordinate:
4098 3536 : if (!emit1(JSOP_UNDEFINED))
4099 : return false;
4100 : break;
4101 :
4102 : case NameLocation::Kind::DynamicAnnexBVar:
4103 0 : MOZ_CRASH("Synthesized vars for Annex B.3.3 should only be used in initialization");
4104 : }
4105 : }
4106 :
4107 : return true;
4108 : }
4109 :
4110 : bool
4111 0 : BytecodeEmitter::emitGetName(ParseNode* pn, bool callContext)
4112 : {
4113 0 : return emitGetName(pn->name(), callContext);
4114 : }
4115 :
4116 : template <typename RHSEmitter>
4117 : bool
4118 32467 : BytecodeEmitter::emitSetOrInitializeNameAtLocation(HandleAtom name, const NameLocation& loc,
4119 : RHSEmitter emitRhs, bool initialize)
4120 : {
4121 32467 : bool emittedBindOp = false;
4122 :
4123 0 : switch (loc.kind()) {
4124 : case NameLocation::Kind::Dynamic:
4125 : case NameLocation::Kind::Import:
4126 : case NameLocation::Kind::DynamicAnnexBVar: {
4127 : uint32_t atomIndex;
4128 159 : if (!makeAtomIndex(name, &atomIndex))
4129 0 : return false;
4130 159 : if (loc.kind() == NameLocation::Kind::DynamicAnnexBVar) {
4131 : // Annex B vars always go on the nearest variable environment,
4132 : // even if lexical environments in between contain same-named
4133 : // bindings.
4134 0 : if (!emit1(JSOP_BINDVAR))
4135 : return false;
4136 : } else {
4137 159 : if (!emitIndexOp(JSOP_BINDNAME, atomIndex))
4138 : return false;
4139 : }
4140 159 : emittedBindOp = true;
4141 159 : if (!emitRhs(this, loc, emittedBindOp))
4142 : return false;
4143 0 : if (!emitIndexOp(strictifySetNameOp(JSOP_SETNAME), atomIndex))
4144 : return false;
4145 159 : break;
4146 : }
4147 :
4148 : case NameLocation::Kind::Global: {
4149 : JSOp op;
4150 : uint32_t atomIndex;
4151 0 : if (!makeAtomIndex(name, &atomIndex))
4152 0 : return false;
4153 0 : if (loc.isLexical() && initialize) {
4154 : // INITGLEXICAL always gets the global lexical scope. It doesn't
4155 : // need a BINDGNAME.
4156 3450 : MOZ_ASSERT(innermostScope()->is<GlobalScope>());
4157 : op = JSOP_INITGLEXICAL;
4158 : } else {
4159 946 : if (!emitIndexOp(JSOP_BINDGNAME, atomIndex))
4160 : return false;
4161 0 : emittedBindOp = true;
4162 : op = strictifySetNameOp(JSOP_SETGNAME);
4163 : }
4164 0 : if (!emitRhs(this, loc, emittedBindOp))
4165 : return false;
4166 2671 : if (!emitIndexOp(op, atomIndex))
4167 : return false;
4168 0 : break;
4169 : }
4170 :
4171 : case NameLocation::Kind::Intrinsic:
4172 25 : if (!emitRhs(this, loc, emittedBindOp))
4173 : return false;
4174 25 : if (!emitAtomOp(name, JSOP_SETINTRINSIC))
4175 : return false;
4176 : break;
4177 :
4178 : case NameLocation::Kind::NamedLambdaCallee:
4179 0 : if (!emitRhs(this, loc, emittedBindOp))
4180 : return false;
4181 : // Assigning to the named lambda is a no-op in sloppy mode but
4182 : // throws in strict mode.
4183 0 : if (sc->strict() && !emit1(JSOP_THROWSETCALLEE))
4184 : return false;
4185 : break;
4186 :
4187 : case NameLocation::Kind::ArgumentSlot: {
4188 : // If we assign to a positional formal parameter and the arguments
4189 : // object is unmapped (strict mode or function with
4190 : // default/rest/destructing args), parameters do not alias
4191 : // arguments[i], and to make the arguments object reflect initial
4192 : // parameter values prior to any mutation we create it eagerly
4193 : // whenever parameters are (or might, in the case of calls to eval)
4194 : // assigned.
4195 0 : FunctionBox* funbox = sc->asFunctionBox();
4196 471 : if (funbox->argumentsHasLocalBinding() && !funbox->hasMappedArgsObj())
4197 11 : funbox->setDefinitelyNeedsArgsObj();
4198 :
4199 453 : if (!emitRhs(this, loc, emittedBindOp))
4200 : return false;
4201 453 : if (!emitArgOp(JSOP_SETARG, loc.argumentSlot()))
4202 : return false;
4203 : break;
4204 : }
4205 :
4206 : case NameLocation::Kind::FrameSlot: {
4207 23049 : JSOp op = JSOP_SETLOCAL;
4208 0 : if (!emitRhs(this, loc, emittedBindOp))
4209 : return false;
4210 23049 : if (loc.isLexical()) {
4211 0 : if (initialize) {
4212 : op = JSOP_INITLEXICAL;
4213 : } else {
4214 2144 : if (loc.isConst())
4215 0 : op = JSOP_THROWSETCONST;
4216 :
4217 2144 : if (!emitTDZCheckIfNeeded(name, loc))
4218 : return false;
4219 : }
4220 : }
4221 23049 : if (!emitLocalOp(op, loc.frameSlot()))
4222 : return false;
4223 23049 : if (op == JSOP_INITLEXICAL) {
4224 0 : if (!innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ))
4225 : return false;
4226 : }
4227 : break;
4228 : }
4229 :
4230 : case NameLocation::Kind::EnvironmentCoordinate: {
4231 6110 : JSOp op = JSOP_SETALIASEDVAR;
4232 7207 : if (!emitRhs(this, loc, emittedBindOp))
4233 : return false;
4234 6110 : if (loc.isLexical()) {
4235 4002 : if (initialize) {
4236 : op = JSOP_INITALIASEDLEXICAL;
4237 : } else {
4238 0 : if (loc.isConst())
4239 0 : op = JSOP_THROWSETALIASEDCONST;
4240 :
4241 609 : if (!emitTDZCheckIfNeeded(name, loc))
4242 : return false;
4243 : }
4244 : }
4245 0 : if (loc.bindingKind() == BindingKind::NamedLambdaCallee) {
4246 : // Assigning to the named lambda is a no-op in sloppy mode and throws
4247 : // in strict mode.
4248 0 : op = JSOP_THROWSETALIASEDCONST;
4249 0 : if (sc->strict() && !emitEnvCoordOp(op, loc.environmentCoordinate()))
4250 : return false;
4251 : } else {
4252 6110 : if (!emitEnvCoordOp(op, loc.environmentCoordinate()))
4253 : return false;
4254 : }
4255 6110 : if (op == JSOP_INITALIASEDLEXICAL) {
4256 0 : if (!innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ))
4257 : return false;
4258 : }
4259 : break;
4260 : }
4261 : }
4262 :
4263 : return true;
4264 : }
4265 :
4266 : bool
4267 38912 : BytecodeEmitter::emitTDZCheckIfNeeded(JSAtom* name, const NameLocation& loc)
4268 : {
4269 : // Dynamic accesses have TDZ checks built into their VM code and should
4270 : // never emit explicit TDZ checks.
4271 77824 : MOZ_ASSERT(loc.hasKnownSlot());
4272 38912 : MOZ_ASSERT(loc.isLexical());
4273 :
4274 77824 : Maybe<MaybeCheckTDZ> check = innermostTDZCheckCache->needsTDZCheck(this, name);
4275 38912 : if (!check)
4276 : return false;
4277 :
4278 : // We've already emitted a check in this basic block.
4279 0 : if (*check == DontCheckTDZ)
4280 : return true;
4281 :
4282 0 : if (loc.kind() == NameLocation::Kind::FrameSlot) {
4283 4 : if (!emitLocalOp(JSOP_CHECKLEXICAL, loc.frameSlot()))
4284 : return false;
4285 : } else {
4286 0 : if (!emitEnvCoordOp(JSOP_CHECKALIASEDLEXICAL, loc.environmentCoordinate()))
4287 : return false;
4288 : }
4289 :
4290 2126 : return innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ);
4291 : }
4292 :
4293 : bool
4294 62769 : BytecodeEmitter::emitPropLHS(ParseNode* pn)
4295 : {
4296 62769 : MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot));
4297 125538 : MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper());
4298 :
4299 62769 : ParseNode* pn2 = pn->pn_expr;
4300 :
4301 : /*
4302 : * If the object operand is also a dotted property reference, reverse the
4303 : * list linked via pn_expr temporarily so we can iterate over it from the
4304 : * bottom up (reversing again as we go), to avoid excessive recursion.
4305 : */
4306 75765 : if (pn2->isKind(ParseNodeKind::Dot) && !pn2->as<PropertyAccess>().isSuper()) {
4307 : ParseNode* pndot = pn2;
4308 : ParseNode* pnup = nullptr;
4309 : ParseNode* pndown;
4310 : for (;;) {
4311 : /* Reverse pndot->pn_expr to point up, not down. */
4312 0 : pndown = pndot->pn_expr;
4313 13951 : pndot->pn_expr = pnup;
4314 0 : if (!pndown->isKind(ParseNodeKind::Dot) || pndown->as<PropertyAccess>().isSuper())
4315 : break;
4316 : pnup = pndot;
4317 : pndot = pndown;
4318 : }
4319 :
4320 : /* pndown is a primary expression, not a dotted property reference. */
4321 12993 : if (!emitTree(pndown))
4322 : return false;
4323 :
4324 0 : do {
4325 : /* Walk back up the list, emitting annotated name ops. */
4326 0 : if (!emitAtomOp(pndot, JSOP_GETPROP))
4327 : return false;
4328 :
4329 : /* Reverse the pn_expr link again. */
4330 0 : pnup = pndot->pn_expr;
4331 13951 : pndot->pn_expr = pndown;
4332 13951 : pndown = pndot;
4333 0 : } while ((pndot = pnup) != nullptr);
4334 : return true;
4335 : }
4336 :
4337 : // The non-optimized case.
4338 0 : return emitTree(pn2);
4339 : }
4340 :
4341 : bool
4342 60 : BytecodeEmitter::emitSuperPropLHS(ParseNode* superBase, bool isCall)
4343 : {
4344 60 : if (!emitGetThisForSuperBase(superBase))
4345 : return false;
4346 0 : if (isCall && !emit1(JSOP_DUP))
4347 : return false;
4348 0 : if (!emit1(JSOP_SUPERBASE))
4349 : return false;
4350 0 : return true;
4351 : }
4352 :
4353 : bool
4354 62653 : BytecodeEmitter::emitPropOp(ParseNode* pn, JSOp op)
4355 : {
4356 62653 : MOZ_ASSERT(pn->isArity(PN_NAME));
4357 :
4358 62653 : if (!emitPropLHS(pn))
4359 : return false;
4360 :
4361 62655 : if (op == JSOP_CALLPROP && !emit1(JSOP_DUP))
4362 : return false;
4363 :
4364 62655 : if (!emitAtomOp(pn, op))
4365 : return false;
4366 :
4367 0 : if (op == JSOP_CALLPROP && !emit1(JSOP_SWAP))
4368 : return false;
4369 :
4370 62653 : return true;
4371 : }
4372 :
4373 : bool
4374 60 : BytecodeEmitter::emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall)
4375 : {
4376 60 : ParseNode* base = &pn->as<PropertyAccess>().expression();
4377 60 : if (!emitSuperPropLHS(base, isCall))
4378 : return false;
4379 :
4380 0 : if (!emitAtomOp(pn, op))
4381 : return false;
4382 :
4383 60 : if (isCall && !emit1(JSOP_SWAP))
4384 : return false;
4385 :
4386 60 : return true;
4387 : }
4388 :
4389 : bool
4390 0 : BytecodeEmitter::emitPropIncDec(ParseNode* pn)
4391 : {
4392 232 : MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Dot));
4393 :
4394 : bool post;
4395 0 : bool isSuper = pn->pn_kid->as<PropertyAccess>().isSuper();
4396 116 : JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4397 :
4398 116 : if (isSuper) {
4399 0 : ParseNode* base = &pn->pn_kid->as<PropertyAccess>().expression();
4400 0 : if (!emitSuperPropLHS(base)) // THIS OBJ
4401 : return false;
4402 0 : if (!emit1(JSOP_DUP2)) // THIS OBJ THIS OBJ
4403 : return false;
4404 : } else {
4405 0 : if (!emitPropLHS(pn->pn_kid)) // OBJ
4406 : return false;
4407 116 : if (!emit1(JSOP_DUP)) // OBJ OBJ
4408 : return false;
4409 : }
4410 0 : if (!emitAtomOp(pn->pn_kid, isSuper? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
4411 : return false;
4412 0 : if (!emit1(JSOP_POS)) // OBJ N
4413 : return false;
4414 116 : if (post && !emit1(JSOP_DUP)) // OBJ N? N
4415 : return false;
4416 116 : if (!emit1(JSOP_ONE)) // OBJ N? N 1
4417 : return false;
4418 0 : if (!emit1(binop)) // OBJ N? N+1
4419 : return false;
4420 :
4421 116 : if (post) {
4422 0 : if (!emit2(JSOP_PICK, 2 + isSuper)) // N? N+1 OBJ
4423 : return false;
4424 0 : if (!emit1(JSOP_SWAP)) // N? OBJ N+1
4425 : return false;
4426 0 : if (isSuper) {
4427 0 : if (!emit2(JSOP_PICK, 3)) // N THIS N+1 OBJ
4428 : return false;
4429 0 : if (!emit1(JSOP_SWAP)) // N THIS OBJ N+1
4430 : return false;
4431 : }
4432 : }
4433 :
4434 116 : JSOp setOp = isSuper ? sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
4435 232 : : sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
4436 116 : if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1
4437 : return false;
4438 116 : if (post && !emit1(JSOP_POP)) // RESULT
4439 : return false;
4440 :
4441 1 : return true;
4442 : }
4443 :
4444 : bool
4445 911 : BytecodeEmitter::emitGetNameAtLocationForCompoundAssignment(JSAtom* name, const NameLocation& loc)
4446 : {
4447 911 : if (loc.kind() == NameLocation::Kind::Dynamic) {
4448 : // For dynamic accesses we need to emit GETBOUNDNAME instead of
4449 : // GETNAME for correctness: looking up @@unscopables on the
4450 : // environment chain (due to 'with' environments) must only happen
4451 : // once.
4452 : //
4453 : // GETBOUNDNAME uses the environment already pushed on the stack from
4454 : // the earlier BINDNAME.
4455 0 : if (!emit1(JSOP_DUP)) // ENV ENV
4456 : return false;
4457 0 : if (!emitAtomOp(name, JSOP_GETBOUNDNAME)) // ENV V
4458 : return false;
4459 : } else {
4460 0 : if (!emitGetNameAtLocation(name, loc)) // ENV? V
4461 : return false;
4462 : }
4463 :
4464 : return true;
4465 : }
4466 :
4467 : bool
4468 527 : BytecodeEmitter::emitNameIncDec(ParseNode* pn)
4469 : {
4470 0 : MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Name));
4471 :
4472 : bool post;
4473 0 : JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4474 :
4475 : auto emitRhs = [pn, post, binop](BytecodeEmitter* bce, const NameLocation& loc,
4476 527 : bool emittedBindOp)
4477 2108 : {
4478 0 : JSAtom* name = pn->pn_kid->name();
4479 527 : if (!bce->emitGetNameAtLocationForCompoundAssignment(name, loc)) // ENV? V
4480 : return false;
4481 527 : if (!bce->emit1(JSOP_POS)) // ENV? N
4482 : return false;
4483 527 : if (post && !bce->emit1(JSOP_DUP)) // ENV? N? N
4484 : return false;
4485 0 : if (!bce->emit1(JSOP_ONE)) // ENV? N? N 1
4486 : return false;
4487 527 : if (!bce->emit1(binop)) // ENV? N? N+1
4488 : return false;
4489 :
4490 527 : if (post && emittedBindOp) {
4491 8 : if (!bce->emit2(JSOP_PICK, 2)) // N? N+1 ENV?
4492 : return false;
4493 8 : if (!bce->emit1(JSOP_SWAP)) // N? ENV? N+1
4494 : return false;
4495 : }
4496 :
4497 : return true;
4498 527 : };
4499 :
4500 527 : if (!emitSetName(pn->pn_kid, emitRhs))
4501 : return false;
4502 :
4503 527 : if (post && !emit1(JSOP_POP))
4504 : return false;
4505 :
4506 527 : return true;
4507 : }
4508 :
4509 : bool
4510 0 : BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts)
4511 : {
4512 3239 : MOZ_ASSERT(pn->isArity(PN_BINARY));
4513 :
4514 0 : if (!emitTree(pn->pn_left))
4515 : return false;
4516 :
4517 0 : if (opts == EmitElemOption::IncDec) {
4518 5 : if (!emit1(JSOP_CHECKOBJCOERCIBLE))
4519 : return false;
4520 1 : } else if (opts == EmitElemOption::Call) {
4521 60 : if (!emit1(JSOP_DUP))
4522 : return false;
4523 : }
4524 :
4525 3239 : if (!emitTree(pn->pn_right))
4526 : return false;
4527 :
4528 3239 : if (opts == EmitElemOption::Set) {
4529 0 : if (!emit2(JSOP_PICK, 2))
4530 : return false;
4531 3239 : } else if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
4532 17 : if (!emit1(JSOP_TOID))
4533 : return false;
4534 : }
4535 : return true;
4536 : }
4537 :
4538 : bool
4539 0 : BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
4540 : {
4541 0 : MOZ_ASSERT(pn->isKind(ParseNodeKind::Elem) && pn->as<PropertyByValue>().isSuper());
4542 :
4543 : // The ordering here is somewhat screwy. We need to evaluate the propval
4544 : // first, by spec. Do a little dance to not emit more than one JSOP_THIS.
4545 : // Since JSOP_THIS might throw in derived class constructors, we cannot
4546 : // just push it earlier as the receiver. We have to swap it down instead.
4547 :
4548 0 : if (!emitTree(pn->pn_right))
4549 : return false;
4550 :
4551 : // We need to convert the key to an object id first, so that we do not do
4552 : // it inside both the GETELEM and the SETELEM.
4553 0 : if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
4554 0 : if (!emit1(JSOP_TOID))
4555 : return false;
4556 : }
4557 :
4558 0 : if (!emitGetThisForSuperBase(pn->pn_left))
4559 : return false;
4560 :
4561 0 : if (opts == EmitElemOption::Call) {
4562 0 : if (!emit1(JSOP_SWAP))
4563 : return false;
4564 :
4565 : // We need another |this| on top, also
4566 0 : if (!emitDupAt(1))
4567 : return false;
4568 : }
4569 :
4570 0 : if (!emit1(JSOP_SUPERBASE))
4571 : return false;
4572 :
4573 0 : if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3))
4574 : return false;
4575 :
4576 0 : return true;
4577 : }
4578 :
4579 : bool
4580 4400 : BytecodeEmitter::emitElemOpBase(JSOp op)
4581 : {
4582 0 : if (!emit1(op))
4583 : return false;
4584 :
4585 : checkTypeSet(op);
4586 : return true;
4587 : }
4588 :
4589 : bool
4590 2701 : BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op)
4591 : {
4592 2701 : EmitElemOption opts = EmitElemOption::Get;
4593 0 : if (op == JSOP_CALLELEM)
4594 : opts = EmitElemOption::Call;
4595 2641 : else if (op == JSOP_SETELEM || op == JSOP_STRICTSETELEM)
4596 0 : opts = EmitElemOption::Set;
4597 :
4598 0 : return emitElemOperands(pn, opts) && emitElemOpBase(op);
4599 : }
4600 :
4601 : bool
4602 0 : BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall)
4603 : {
4604 0 : EmitElemOption opts = EmitElemOption::Get;
4605 0 : if (isCall)
4606 : opts = EmitElemOption::Call;
4607 0 : else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER)
4608 0 : opts = EmitElemOption::Set;
4609 :
4610 0 : if (!emitSuperElemOperands(pn, opts))
4611 : return false;
4612 0 : if (!emitElemOpBase(op))
4613 : return false;
4614 :
4615 0 : if (isCall && !emit1(JSOP_SWAP))
4616 : return false;
4617 :
4618 0 : return true;
4619 : }
4620 :
4621 : bool
4622 5 : BytecodeEmitter::emitElemIncDec(ParseNode* pn)
4623 : {
4624 10 : MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Elem));
4625 :
4626 10 : bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
4627 :
4628 : // We need to convert the key to an object id first, so that we do not do
4629 : // it inside both the GETELEM and the SETELEM. This is done by
4630 : // emit(Super)ElemOperands.
4631 5 : if (isSuper) {
4632 0 : if (!emitSuperElemOperands(pn->pn_kid, EmitElemOption::IncDec))
4633 : return false;
4634 : } else {
4635 0 : if (!emitElemOperands(pn->pn_kid, EmitElemOption::IncDec))
4636 : return false;
4637 : }
4638 :
4639 : bool post;
4640 0 : JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4641 :
4642 : JSOp getOp;
4643 5 : if (isSuper) {
4644 : // There's no such thing as JSOP_DUP3, so we have to be creative.
4645 : // Note that pushing things again is no fewer JSOps.
4646 0 : if (!emitDupAt(2)) // KEY THIS OBJ KEY
4647 : return false;
4648 0 : if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS
4649 : return false;
4650 0 : if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS OBJ
4651 : return false;
4652 : getOp = JSOP_GETELEM_SUPER;
4653 : } else {
4654 : // OBJ KEY
4655 5 : if (!emit1(JSOP_DUP2)) // OBJ KEY OBJ KEY
4656 : return false;
4657 : getOp = JSOP_GETELEM;
4658 : }
4659 5 : if (!emitElemOpBase(getOp)) // OBJ KEY V
4660 : return false;
4661 0 : if (!emit1(JSOP_POS)) // OBJ KEY N
4662 : return false;
4663 5 : if (post && !emit1(JSOP_DUP)) // OBJ KEY N? N
4664 : return false;
4665 5 : if (!emit1(JSOP_ONE)) // OBJ KEY N? N 1
4666 : return false;
4667 5 : if (!emit1(binop)) // OBJ KEY N? N+1
4668 : return false;
4669 :
4670 0 : if (post) {
4671 5 : if (isSuper) {
4672 : // We have one more value to rotate around, because of |this|
4673 : // on the stack
4674 0 : if (!emit2(JSOP_PICK, 4))
4675 : return false;
4676 : }
4677 0 : if (!emit2(JSOP_PICK, 3 + isSuper)) // KEY N N+1 OBJ
4678 : return false;
4679 5 : if (!emit2(JSOP_PICK, 3 + isSuper)) // N N+1 OBJ KEY
4680 : return false;
4681 5 : if (!emit2(JSOP_PICK, 2 + isSuper)) // N OBJ KEY N+1
4682 : return false;
4683 : }
4684 :
4685 0 : JSOp setOp = isSuper ? (sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
4686 0 : : (sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM);
4687 0 : if (!emitElemOpBase(setOp)) // N? N+1
4688 : return false;
4689 5 : if (post && !emit1(JSOP_POP)) // RESULT
4690 : return false;
4691 :
4692 5 : return true;
4693 : }
4694 :
4695 : bool
4696 0 : BytecodeEmitter::emitCallIncDec(ParseNode* incDec)
4697 : {
4698 0 : MOZ_ASSERT(incDec->isKind(ParseNodeKind::PreIncrement) ||
4699 : incDec->isKind(ParseNodeKind::PostIncrement) ||
4700 : incDec->isKind(ParseNodeKind::PreDecrement) ||
4701 : incDec->isKind(ParseNodeKind::PostDecrement));
4702 :
4703 0 : MOZ_ASSERT(incDec->pn_kid->isKind(ParseNodeKind::Call));
4704 :
4705 0 : ParseNode* call = incDec->pn_kid;
4706 0 : if (!emitTree(call)) // CALLRESULT
4707 : return false;
4708 0 : if (!emit1(JSOP_POS)) // N
4709 : return false;
4710 :
4711 : // The increment/decrement has no side effects, so proceed to throw for
4712 : // invalid assignment target.
4713 0 : return emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS);
4714 : }
4715 :
4716 : bool
4717 1 : BytecodeEmitter::emitNumberOp(double dval)
4718 : {
4719 : int32_t ival;
4720 7951 : if (NumberIsInt32(dval, &ival)) {
4721 7872 : if (ival == 0)
4722 0 : return emit1(JSOP_ZERO);
4723 0 : if (ival == 1)
4724 1445 : return emit1(JSOP_ONE);
4725 0 : if ((int)(int8_t)ival == ival)
4726 0 : return emit2(JSOP_INT8, uint8_t(int8_t(ival)));
4727 :
4728 0 : uint32_t u = uint32_t(ival);
4729 534 : if (u < JS_BIT(16)) {
4730 438 : if (!emitUint16Operand(JSOP_UINT16, u))
4731 : return false;
4732 96 : } else if (u < JS_BIT(24)) {
4733 : ptrdiff_t off;
4734 0 : if (!emitN(JSOP_UINT24, 3, &off))
4735 0 : return false;
4736 0 : SET_UINT24(code(off), u);
4737 : } else {
4738 : ptrdiff_t off;
4739 0 : if (!emitN(JSOP_INT32, 4, &off))
4740 0 : return false;
4741 0 : SET_INT32(code(off), ival);
4742 : }
4743 : return true;
4744 : }
4745 :
4746 0 : if (!constList.append(DoubleValue(dval)))
4747 : return false;
4748 :
4749 0 : return emitIndex32(JSOP_DOUBLE, constList.length() - 1);
4750 : }
4751 :
4752 : /*
4753 : * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
4754 : * LLVM is deciding to inline this function which uses a lot of stack space
4755 : * into emitTree which is recursive and uses relatively little stack space.
4756 : */
4757 : MOZ_NEVER_INLINE bool
4758 397 : BytecodeEmitter::emitSwitch(ParseNode* pn)
4759 : {
4760 397 : ParseNode* cases = pn->pn_right;
4761 397 : MOZ_ASSERT(cases->isKind(ParseNodeKind::LexicalScope) ||
4762 : cases->isKind(ParseNodeKind::StatementList));
4763 :
4764 : // Emit code for the discriminant.
4765 397 : if (!emitTree(pn->pn_left))
4766 : return false;
4767 :
4768 : // Enter the scope before pushing the switch BreakableControl since all
4769 : // breaks are under this scope.
4770 0 : Maybe<TDZCheckCache> tdzCache;
4771 0 : Maybe<EmitterScope> emitterScope;
4772 397 : if (cases->isKind(ParseNodeKind::LexicalScope)) {
4773 397 : if (!cases->isEmptyScope()) {
4774 49 : tdzCache.emplace(this);
4775 49 : emitterScope.emplace(this);
4776 0 : if (!emitterScope->enterLexical(this, ScopeKind::Lexical, cases->scopeBindings()))
4777 : return false;
4778 : }
4779 :
4780 : // Advance |cases| to refer to the switch case list.
4781 0 : cases = cases->scopeBody();
4782 :
4783 : // A switch statement may contain hoisted functions inside its
4784 : // cases. The PNX_FUNCDEFS flag is propagated from the STATEMENTLIST
4785 : // bodies of the cases to the case list.
4786 0 : if (cases->pn_xflags & PNX_FUNCDEFS) {
4787 0 : MOZ_ASSERT(emitterScope);
4788 0 : for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
4789 0 : if (caseNode->pn_right->pn_xflags & PNX_FUNCDEFS) {
4790 0 : if (!emitHoistedFunctionsInList(caseNode->pn_right))
4791 : return false;
4792 : }
4793 : }
4794 : }
4795 : }
4796 :
4797 : // After entering the scope, push the switch control.
4798 0 : BreakableControl controlInfo(this, StatementKind::Switch);
4799 :
4800 397 : ptrdiff_t top = offset();
4801 :
4802 : // Switch bytecodes run from here till end of final case.
4803 397 : uint32_t caseCount = cases->pn_count;
4804 397 : if (caseCount > JS_BIT(16)) {
4805 0 : reportError(pn, JSMSG_TOO_MANY_CASES);
4806 0 : return false;
4807 : }
4808 :
4809 : // Try for most optimal, fall back if not dense ints.
4810 397 : JSOp switchOp = JSOP_TABLESWITCH;
4811 397 : uint32_t tableLength = 0;
4812 : int32_t low, high;
4813 397 : bool hasDefault = false;
4814 397 : CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
4815 0 : if (caseCount == 0 ||
4816 0 : (caseCount == 1 && (hasDefault = firstCase->isDefault())))
4817 : {
4818 : low = 0;
4819 : high = -1;
4820 : } else {
4821 0 : Vector<size_t, 128, SystemAllocPolicy> intmap;
4822 0 : int32_t intmapBitLength = 0;
4823 :
4824 397 : low = JSVAL_INT_MAX;
4825 0 : high = JSVAL_INT_MIN;
4826 :
4827 0 : for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4828 0 : if (caseNode->isDefault()) {
4829 129 : hasDefault = true;
4830 0 : caseCount--; // one of the "cases" was the default
4831 0 : continue;
4832 : }
4833 :
4834 1706 : if (switchOp == JSOP_CONDSWITCH)
4835 : continue;
4836 :
4837 584 : MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4838 :
4839 0 : ParseNode* caseValue = caseNode->caseExpression();
4840 :
4841 584 : if (caseValue->getKind() != ParseNodeKind::Number) {
4842 : switchOp = JSOP_CONDSWITCH;
4843 : continue;
4844 : }
4845 :
4846 : int32_t i;
4847 0 : if (!NumberEqualsInt32(caseValue->pn_dval, &i)) {
4848 : switchOp = JSOP_CONDSWITCH;
4849 : continue;
4850 : }
4851 :
4852 226 : if (unsigned(i + int(JS_BIT(15))) >= unsigned(JS_BIT(16))) {
4853 : switchOp = JSOP_CONDSWITCH;
4854 : continue;
4855 : }
4856 0 : if (i < low)
4857 46 : low = i;
4858 0 : if (i > high)
4859 189 : high = i;
4860 :
4861 : // Check for duplicates, which require a JSOP_CONDSWITCH.
4862 : // We bias i by 65536 if it's negative, and hope that's a rare
4863 : // case (because it requires a malloc'd bitmap).
4864 226 : if (i < 0)
4865 0 : i += JS_BIT(16);
4866 226 : if (i >= intmapBitLength) {
4867 0 : size_t newLength = NumWordsForBitArrayOfLength(i + 1);
4868 0 : if (!intmap.resize(newLength)) {
4869 0 : ReportOutOfMemory(cx);
4870 0 : return false;
4871 : }
4872 39 : intmapBitLength = newLength * BitArrayElementBits;
4873 : }
4874 678 : if (IsBitArrayElementSet(intmap.begin(), intmap.length(), i)) {
4875 : switchOp = JSOP_CONDSWITCH;
4876 : continue;
4877 : }
4878 0 : SetBitArrayElement(intmap.begin(), intmap.length(), i);
4879 : }
4880 :
4881 : // Compute table length and select condswitch instead if overlarge or
4882 : // more than half-sparse.
4883 397 : if (switchOp == JSOP_TABLESWITCH) {
4884 39 : tableLength = uint32_t(high - low + 1);
4885 39 : if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount)
4886 1 : switchOp = JSOP_CONDSWITCH;
4887 : }
4888 : }
4889 :
4890 : // The note has one or two offsets: first tells total switch code length;
4891 : // second (if condswitch) tells offset to first JSOP_CASE.
4892 : unsigned noteIndex;
4893 : size_t switchSize;
4894 397 : if (switchOp == JSOP_CONDSWITCH) {
4895 : // 0 bytes of immediate for unoptimized switch.
4896 359 : switchSize = 0;
4897 0 : if (!newSrcNote3(SRC_CONDSWITCH, 0, 0, ¬eIndex))
4898 : return false;
4899 : } else {
4900 0 : MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4901 :
4902 : // 3 offsets (len, low, high) before the table, 1 per entry.
4903 0 : switchSize = size_t(JUMP_OFFSET_LEN * (3 + tableLength));
4904 38 : if (!newSrcNote2(SRC_TABLESWITCH, 0, ¬eIndex))
4905 : return false;
4906 : }
4907 :
4908 : // Emit switchOp followed by switchSize bytes of jump or lookup table.
4909 0 : MOZ_ASSERT(top == offset());
4910 397 : if (!emitN(switchOp, switchSize))
4911 : return false;
4912 :
4913 1 : Vector<CaseClause*, 32, SystemAllocPolicy> table;
4914 :
4915 397 : JumpList condSwitchDefaultOff;
4916 397 : if (switchOp == JSOP_CONDSWITCH) {
4917 : unsigned caseNoteIndex;
4918 0 : bool beforeCases = true;
4919 0 : ptrdiff_t lastCaseOffset = -1;
4920 :
4921 : // The case conditions need their own TDZ cache since they might not
4922 : // all execute.
4923 718 : TDZCheckCache tdzCache(this);
4924 :
4925 : // Emit code for evaluating cases and jumping to case statements.
4926 0 : for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4927 0 : ParseNode* caseValue = caseNode->caseExpression();
4928 :
4929 : // If the expression is a literal, suppress line number emission so
4930 : // that debugging works more naturally.
4931 1594 : if (caseValue) {
4932 1483 : if (!emitTree(caseValue, ValueUsage::WantValue,
4933 0 : caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
4934 : {
4935 0 : return false;
4936 : }
4937 : }
4938 :
4939 1594 : if (!beforeCases) {
4940 : // prevCase is the previous JSOP_CASE's bytecode offset.
4941 0 : if (!setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
4942 : return false;
4943 : }
4944 1594 : if (!caseValue) {
4945 : // This is the default clause.
4946 111 : continue;
4947 : }
4948 :
4949 0 : if (!newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex))
4950 : return false;
4951 :
4952 : // The case clauses are produced before any of the case body. The
4953 : // JumpList is saved on the parsed tree, then later restored and
4954 : // patched when generating the cases body.
4955 1483 : JumpList caseJump;
4956 0 : if (!emitJump(JSOP_CASE, &caseJump))
4957 : return false;
4958 0 : caseNode->setOffset(caseJump.offset);
4959 1483 : lastCaseOffset = caseJump.offset;
4960 :
4961 1 : if (beforeCases) {
4962 : // Switch note's second offset is to first JSOP_CASE.
4963 359 : unsigned noteCount = notes().length();
4964 0 : if (!setSrcNoteOffset(noteIndex, 1, lastCaseOffset - top))
4965 : return false;
4966 0 : unsigned noteCountDelta = notes().length() - noteCount;
4967 359 : if (noteCountDelta != 0)
4968 0 : caseNoteIndex += noteCountDelta;
4969 : beforeCases = false;
4970 : }
4971 : }
4972 :
4973 : // If we didn't have an explicit default (which could fall in between
4974 : // cases, preventing us from fusing this setSrcNoteOffset with the call
4975 : // in the loop above), link the last case to the implicit default for
4976 : // the benefit of IonBuilder.
4977 0 : if (!hasDefault &&
4978 0 : !beforeCases &&
4979 0 : !setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
4980 : {
4981 : return false;
4982 : }
4983 :
4984 : // Emit default even if no explicit default statement.
4985 359 : if (!emitJump(JSOP_DEFAULT, &condSwitchDefaultOff))
4986 : return false;
4987 : } else {
4988 38 : MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4989 :
4990 : // skip default offset.
4991 38 : jsbytecode* pc = code(top + JUMP_OFFSET_LEN);
4992 :
4993 : // Fill in switch bounds, which we know fit in 16-bit offsets.
4994 0 : SET_JUMP_OFFSET(pc, low);
4995 0 : pc += JUMP_OFFSET_LEN;
4996 0 : SET_JUMP_OFFSET(pc, high);
4997 38 : pc += JUMP_OFFSET_LEN;
4998 :
4999 38 : if (tableLength != 0) {
5000 38 : if (!table.growBy(tableLength)) {
5001 0 : ReportOutOfMemory(cx);
5002 0 : return false;
5003 : }
5004 :
5005 0 : for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
5006 241 : if (ParseNode* caseValue = caseNode->caseExpression()) {
5007 223 : MOZ_ASSERT(caseValue->isKind(ParseNodeKind::Number));
5008 :
5009 223 : int32_t i = int32_t(caseValue->pn_dval);
5010 223 : MOZ_ASSERT(double(i) == caseValue->pn_dval);
5011 :
5012 0 : i -= low;
5013 223 : MOZ_ASSERT(uint32_t(i) < tableLength);
5014 223 : MOZ_ASSERT(!table[i]);
5015 223 : table[i] = caseNode;
5016 : }
5017 : }
5018 : }
5019 : }
5020 :
5021 397 : JumpTarget defaultOffset{ -1 };
5022 :
5023 : // Emit code for each case's statements.
5024 0 : for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
5025 0 : if (switchOp == JSOP_CONDSWITCH && !caseNode->isDefault()) {
5026 : // The case offset got saved in the caseNode structure after
5027 : // emitting the JSOP_CASE jump instruction above.
5028 0 : JumpList caseCond;
5029 1483 : caseCond.offset = caseNode->offset();
5030 1483 : if (!emitJumpTargetAndPatch(caseCond))
5031 0 : return false;
5032 : }
5033 :
5034 : JumpTarget here;
5035 0 : if (!emitJumpTarget(&here))
5036 : return false;
5037 0 : if (caseNode->isDefault())
5038 129 : defaultOffset = here;
5039 :
5040 : // If this is emitted as a TABLESWITCH, we'll need to know this case's
5041 : // offset later when emitting the table. Store it in the node's
5042 : // pn_offset (giving the field a different meaning vs. how we used it
5043 : // on the immediately preceding line of code).
5044 0 : caseNode->setOffset(here.offset);
5045 :
5046 1 : TDZCheckCache tdzCache(this);
5047 :
5048 1835 : if (!emitTree(caseNode->statementList()))
5049 0 : return false;
5050 : }
5051 :
5052 0 : if (!hasDefault) {
5053 : // If no default case, offset for default is to end of switch.
5054 0 : if (!emitJumpTarget(&defaultOffset))
5055 : return false;
5056 : }
5057 397 : MOZ_ASSERT(defaultOffset.offset != -1);
5058 :
5059 : // Set the default offset (to end of switch if no default).
5060 : jsbytecode* pc;
5061 397 : if (switchOp == JSOP_CONDSWITCH) {
5062 359 : pc = nullptr;
5063 0 : patchJumpsToTarget(condSwitchDefaultOff, defaultOffset);
5064 : } else {
5065 38 : MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
5066 38 : pc = code(top);
5067 76 : SET_JUMP_OFFSET(pc, defaultOffset.offset - top);
5068 0 : pc += JUMP_OFFSET_LEN;
5069 : }
5070 :
5071 : // Set the SRC_SWITCH note's offset operand to tell end of switch.
5072 0 : if (!setSrcNoteOffset(noteIndex, 0, lastNonJumpTargetOffset() - top))
5073 : return false;
5074 :
5075 397 : if (switchOp == JSOP_TABLESWITCH) {
5076 : // Skip over the already-initialized switch bounds.
5077 38 : pc += 2 * JUMP_OFFSET_LEN;
5078 :
5079 : // Fill in the jump table, if there is one.
5080 296 : for (uint32_t i = 0; i < tableLength; i++) {
5081 0 : CaseClause* caseNode = table[i];
5082 258 : ptrdiff_t off = caseNode ? caseNode->offset() - top : 0;
5083 0 : SET_JUMP_OFFSET(pc, off);
5084 258 : pc += JUMP_OFFSET_LEN;
5085 : }
5086 : }
5087 :
5088 : // Patch breaks before leaving the scope, as all breaks are under the
5089 : // lexical scope if it exists.
5090 0 : if (!controlInfo.patchBreaks(this))
5091 : return false;
5092 :
5093 0 : if (emitterScope && !emitterScope->leave(this))
5094 : return false;
5095 :
5096 0 : return true;
5097 : }
5098 :
5099 : bool
5100 0 : BytecodeEmitter::isRunOnceLambda()
5101 : {
5102 : // The run once lambda flags set by the parser are approximate, and we look
5103 : // at properties of the function itself before deciding to emit a function
5104 : // as a run once lambda.
5105 :
5106 73095 : if (!(parent && parent->emittingRunOnceLambda) &&
5107 0 : (emitterMode != LazyFunction || !lazyScript->treatAsRunOnce()))
5108 : {
5109 : return false;
5110 : }
5111 :
5112 258 : FunctionBox* funbox = sc->asFunctionBox();
5113 0 : return !funbox->argumentsHasLocalBinding() &&
5114 0 : !funbox->isGenerator() &&
5115 0 : !funbox->isAsync() &&
5116 0 : !funbox->function()->explicitName();
5117 : }
5118 :
5119 : bool
5120 0 : BytecodeEmitter::emitYieldOp(JSOp op)
5121 : {
5122 0 : if (op == JSOP_FINALYIELDRVAL)
5123 1361 : return emit1(JSOP_FINALYIELDRVAL);
5124 :
5125 2015 : MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT);
5126 :
5127 : ptrdiff_t off;
5128 2015 : if (!emitN(op, 3, &off))
5129 : return false;
5130 :
5131 0 : uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
5132 2015 : if (yieldAndAwaitIndex >= JS_BIT(24)) {
5133 0 : reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
5134 0 : return false;
5135 : }
5136 :
5137 2015 : if (op == JSOP_AWAIT)
5138 1233 : yieldAndAwaitOffsetList.numAwaits++;
5139 : else
5140 0 : yieldAndAwaitOffsetList.numYields++;
5141 :
5142 0 : SET_UINT24(code(off), yieldAndAwaitIndex);
5143 :
5144 1 : if (!yieldAndAwaitOffsetList.append(offset()))
5145 : return false;
5146 :
5147 0 : return emit1(JSOP_DEBUGAFTERYIELD);
5148 : }
5149 :
5150 : bool
5151 79 : BytecodeEmitter::emitSetThis(ParseNode* pn)
5152 : {
5153 : // ParseNodeKind::SetThis is used to update |this| after a super() call
5154 : // in a derived class constructor.
5155 :
5156 79 : MOZ_ASSERT(pn->isKind(ParseNodeKind::SetThis));
5157 0 : MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::Name));
5158 :
5159 158 : RootedAtom name(cx, pn->pn_left->name());
5160 0 : auto emitRhs = [&name, pn](BytecodeEmitter* bce, const NameLocation&, bool) {
5161 : // Emit the new |this| value.
5162 79 : if (!bce->emitTree(pn->pn_right))
5163 : return false;
5164 : // Get the original |this| and throw if we already initialized
5165 : // it. Do *not* use the NameLocation argument, as that's the special
5166 : // lexical location below to deal with super() semantics.
5167 79 : if (!bce->emitGetName(name))
5168 : return false;
5169 0 : if (!bce->emit1(JSOP_CHECKTHISREINIT))
5170 : return false;
5171 0 : if (!bce->emit1(JSOP_POP))
5172 : return false;
5173 79 : return true;
5174 79 : };
5175 :
5176 : // The 'this' binding is not lexical, but due to super() semantics this
5177 : // initialization needs to be treated as a lexical one.
5178 0 : NameLocation loc = lookupName(name);
5179 : NameLocation lexicalLoc;
5180 0 : if (loc.kind() == NameLocation::Kind::FrameSlot) {
5181 74 : lexicalLoc = NameLocation::FrameSlot(BindingKind::Let, loc.frameSlot());
5182 5 : } else if (loc.kind() == NameLocation::Kind::EnvironmentCoordinate) {
5183 5 : EnvironmentCoordinate coord = loc.environmentCoordinate();
5184 5 : uint8_t hops = AssertedCast<uint8_t>(coord.hops());
5185 5 : lexicalLoc = NameLocation::EnvironmentCoordinate(BindingKind::Let, hops, coord.slot());
5186 : } else {
5187 0 : MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic);
5188 0 : lexicalLoc = loc;
5189 : }
5190 :
5191 158 : return emitSetOrInitializeNameAtLocation(name, lexicalLoc, emitRhs, true);
5192 : }
5193 :
5194 : bool
5195 408 : BytecodeEmitter::emitScript(ParseNode* body)
5196 : {
5197 816 : AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser->errorReporter(), body);
5198 :
5199 816 : setScriptStartOffsetIfUnset(body->pn_pos);
5200 :
5201 0 : TDZCheckCache tdzCache(this);
5202 0 : EmitterScope emitterScope(this);
5203 0 : if (sc->isGlobalContext()) {
5204 390 : switchToPrologue();
5205 0 : if (!emitterScope.enterGlobal(this, sc->asGlobalContext()))
5206 : return false;
5207 : switchToMain();
5208 18 : } else if (sc->isEvalContext()) {
5209 18 : switchToPrologue();
5210 18 : if (!emitterScope.enterEval(this, sc->asEvalContext()))
5211 : return false;
5212 : switchToMain();
5213 : } else {
5214 0 : MOZ_ASSERT(sc->isModuleContext());
5215 0 : if (!emitterScope.enterModule(this, sc->asModuleContext()))
5216 : return false;
5217 : }
5218 :
5219 408 : setFunctionBodyEndPos(body->pn_pos);
5220 :
5221 0 : if (sc->isEvalContext() && !sc->strict() &&
5222 408 : body->isKind(ParseNodeKind::LexicalScope) && !body->isEmptyScope())
5223 : {
5224 : // Sloppy eval scripts may need to emit DEFFUNs in the prologue. If there is
5225 : // an immediately enclosed lexical scope, we need to enter the lexical
5226 : // scope in the prologue for the DEFFUNs to pick up the right
5227 : // environment chain.
5228 0 : EmitterScope lexicalEmitterScope(this);
5229 :
5230 0 : switchToPrologue();
5231 0 : if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical, body->scopeBindings()))
5232 0 : return false;
5233 0 : switchToMain();
5234 :
5235 0 : if (!emitLexicalScopeBody(body->scopeBody()))
5236 : return false;
5237 :
5238 0 : if (!lexicalEmitterScope.leave(this))
5239 : return false;
5240 : } else {
5241 0 : if (!emitTree(body))
5242 : return false;
5243 : }
5244 :
5245 0 : if (!updateSourceCoordNotes(body->pn_pos.end))
5246 : return false;
5247 :
5248 408 : if (!emit1(JSOP_RETRVAL))
5249 : return false;
5250 :
5251 408 : if (!emitterScope.leave(this))
5252 : return false;
5253 :
5254 0 : if (!JSScript::fullyInitFromEmitter(cx, script, this))
5255 : return false;
5256 :
5257 408 : tellDebuggerAboutCompiledScript(cx);
5258 :
5259 408 : return true;
5260 : }
5261 :
5262 : bool
5263 0 : BytecodeEmitter::emitFunctionScript(ParseNode* body)
5264 : {
5265 0 : FunctionBox* funbox = sc->asFunctionBox();
5266 0 : AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser->errorReporter(), funbox);
5267 :
5268 0 : setScriptStartOffsetIfUnset(body->pn_pos);
5269 :
5270 : // The ordering of these EmitterScopes is important. The named lambda
5271 : // scope needs to enclose the function scope needs to enclose the extra
5272 : // var scope.
5273 :
5274 26082 : Maybe<EmitterScope> namedLambdaEmitterScope;
5275 26082 : if (funbox->namedLambdaBindings()) {
5276 1230 : namedLambdaEmitterScope.emplace(this);
5277 1230 : if (!namedLambdaEmitterScope->enterNamedLambda(this, funbox))
5278 : return false;
5279 : }
5280 :
5281 : /*
5282 : * Emit a prologue for run-once scripts which will deoptimize JIT code
5283 : * if the script ends up running multiple times via foo.caller related
5284 : * shenanigans.
5285 : *
5286 : * Also mark the script so that initializers created within it may be
5287 : * given more precise types.
5288 : */
5289 13041 : if (isRunOnceLambda()) {
5290 84 : script->setTreatAsRunOnce();
5291 1 : MOZ_ASSERT(!script->hasRunOnce());
5292 :
5293 28 : switchToPrologue();
5294 28 : if (!emit1(JSOP_RUNONCE))
5295 : return false;
5296 : switchToMain();
5297 : }
5298 :
5299 13041 : setFunctionBodyEndPos(body->pn_pos);
5300 0 : if (!emitTree(body))
5301 : return false;
5302 :
5303 13041 : if (!updateSourceCoordNotes(body->pn_pos.end))
5304 : return false;
5305 :
5306 : // Always end the script with a JSOP_RETRVAL. Some other parts of the
5307 : // codebase depend on this opcode,
5308 : // e.g. InterpreterRegs::setToEndOfScript.
5309 13041 : if (!emit1(JSOP_RETRVAL))
5310 : return false;
5311 :
5312 0 : if (namedLambdaEmitterScope) {
5313 0 : if (!namedLambdaEmitterScope->leave(this))
5314 : return false;
5315 0 : namedLambdaEmitterScope.reset();
5316 : }
5317 :
5318 26082 : if (!JSScript::fullyInitFromEmitter(cx, script, this))
5319 : return false;
5320 :
5321 0 : tellDebuggerAboutCompiledScript(cx);
5322 :
5323 13041 : return true;
5324 : }
5325 :
5326 : bool
5327 1636 : BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target, size_t* emitted)
5328 : {
5329 0 : *emitted = 0;
5330 :
5331 1636 : if (target->isKind(ParseNodeKind::Spread))
5332 1 : target = target->pn_kid;
5333 1635 : else if (target->isKind(ParseNodeKind::Assign))
5334 0 : target = target->pn_left;
5335 :
5336 : // No need to recur into ParseNodeKind::Array and
5337 : // ParseNodeKind::Object subpatterns here, since
5338 : // emitSetOrInitializeDestructuring does the recursion when
5339 : // setting or initializing value. Getting reference doesn't recur.
5340 3301 : if (target->isKind(ParseNodeKind::Name) ||
5341 1686 : target->isKind(ParseNodeKind::Array) ||
5342 21 : target->isKind(ParseNodeKind::Object))
5343 : {
5344 : return true;
5345 : }
5346 :
5347 : #ifdef DEBUG
5348 13 : int depth = stackDepth;
5349 : #endif
5350 :
5351 13 : switch (target->getKind()) {
5352 : case ParseNodeKind::Dot: {
5353 0 : if (target->as<PropertyAccess>().isSuper()) {
5354 0 : if (!emitSuperPropLHS(&target->as<PropertyAccess>().expression()))
5355 : return false;
5356 0 : *emitted = 2;
5357 : } else {
5358 13 : if (!emitTree(target->pn_expr))
5359 : return false;
5360 13 : *emitted = 1;
5361 : }
5362 : break;
5363 : }
5364 :
5365 : case ParseNodeKind::Elem: {
5366 0 : if (target->as<PropertyByValue>().isSuper()) {
5367 0 : if (!emitSuperElemOperands(target, EmitElemOption::Ref))
5368 : return false;
5369 0 : *emitted = 3;
5370 : } else {
5371 0 : if (!emitElemOperands(target, EmitElemOption::Ref))
5372 : return false;
5373 0 : *emitted = 2;
5374 : }
5375 : break;
5376 : }
5377 :
5378 : case ParseNodeKind::Call:
5379 0 : MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget "
5380 : "rejects function calls as assignment "
5381 : "targets in destructuring assignments");
5382 : break;
5383 :
5384 : default:
5385 0 : MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
5386 : }
5387 :
5388 0 : MOZ_ASSERT(stackDepth == depth + int(*emitted));
5389 :
5390 : return true;
5391 : }
5392 :
5393 : bool
5394 1636 : BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, DestructuringFlavor flav)
5395 : {
5396 : // Now emit the lvalue opcode sequence. If the lvalue is a nested
5397 : // destructuring initialiser-form, call ourselves to handle it, then pop
5398 : // the matched value. Otherwise emit an lvalue bytecode sequence followed
5399 : // by an assignment op.
5400 1636 : if (target->isKind(ParseNodeKind::Spread))
5401 1 : target = target->pn_kid;
5402 0 : else if (target->isKind(ParseNodeKind::Assign))
5403 0 : target = target->pn_left;
5404 3264 : if (target->isKind(ParseNodeKind::Array) || target->isKind(ParseNodeKind::Object)) {
5405 16 : if (!emitDestructuringOps(target, flav))
5406 : return false;
5407 : // Per its post-condition, emitDestructuringOps has left the
5408 : // to-be-destructured value on top of the stack.
5409 16 : if (!emit1(JSOP_POP))
5410 : return false;
5411 : } else {
5412 1620 : switch (target->getKind()) {
5413 : case ParseNodeKind::Name: {
5414 : auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&,
5415 : bool emittedBindOp)
5416 : {
5417 242 : if (emittedBindOp) {
5418 : // This is like ordinary assignment, but with one
5419 : // difference.
5420 : //
5421 : // In `a = b`, we first determine a binding for `a` (using
5422 : // JSOP_BINDNAME or JSOP_BINDGNAME), then we evaluate `b`,
5423 : // then a JSOP_SETNAME instruction.
5424 : //
5425 : // In `[a] = [b]`, per spec, `b` is evaluated first, then
5426 : // we determine a binding for `a`. Then we need to do
5427 : // assignment-- but the operands are on the stack in the
5428 : // wrong order for JSOP_SETPROP, so we have to add a
5429 : // JSOP_SWAP.
5430 : //
5431 : // In the cases where we are emitting a name op, emit a
5432 : // swap because of this.
5433 52 : return bce->emit1(JSOP_SWAP);
5434 : }
5435 :
5436 : // In cases of emitting a frame slot or environment slot,
5437 : // nothing needs be done.
5438 : return true;
5439 : };
5440 :
5441 0 : RootedAtom name(cx, target->name());
5442 1607 : switch (flav) {
5443 : case DestructuringDeclaration:
5444 3128 : if (!emitInitializeName(name, emitSwapScopeAndRhs))
5445 0 : return false;
5446 : break;
5447 :
5448 : case DestructuringFormalParameterInVarScope: {
5449 : // If there's an parameter expression var scope, the
5450 : // destructuring declaration needs to initialize the name in
5451 : // the function scope. The innermost scope is the var scope,
5452 : // and its enclosing scope is the function scope.
5453 0 : EmitterScope* funScope = innermostEmitterScope()->enclosingInFrame();
5454 0 : NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
5455 0 : if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true))
5456 0 : return false;
5457 0 : break;
5458 : }
5459 :
5460 : case DestructuringAssignment:
5461 86 : if (!emitSetName(name, emitSwapScopeAndRhs))
5462 : return false;
5463 : break;
5464 : }
5465 :
5466 1607 : break;
5467 : }
5468 :
5469 : case ParseNodeKind::Dot: {
5470 : // The reference is already pushed by emitDestructuringLHSRef.
5471 : JSOp setOp;
5472 26 : if (target->as<PropertyAccess>().isSuper())
5473 0 : setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
5474 : else
5475 26 : setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
5476 0 : if (!emitAtomOp(target, setOp))
5477 : return false;
5478 : break;
5479 : }
5480 :
5481 : case ParseNodeKind::Elem: {
5482 : // The reference is already pushed by emitDestructuringLHSRef.
5483 0 : if (target->as<PropertyByValue>().isSuper()) {
5484 0 : JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
5485 : // emitDestructuringLHSRef already did emitSuperElemOperands
5486 : // part of emitSuperElemOp. Perform remaining part here.
5487 0 : if (!emitElemOpBase(setOp))
5488 : return false;
5489 : } else {
5490 0 : JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
5491 0 : if (!emitElemOpBase(setOp))
5492 : return false;
5493 : }
5494 : break;
5495 : }
5496 :
5497 : case ParseNodeKind::Call:
5498 0 : MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget "
5499 : "rejects function calls as assignment "
5500 : "targets in destructuring assignments");
5501 : break;
5502 :
5503 : default:
5504 0 : MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind");
5505 : }
5506 :
5507 : // Pop the assigned value.
5508 1620 : if (!emit1(JSOP_POP))
5509 : return false;
5510 : }
5511 :
5512 : return true;
5513 : }
5514 :
5515 : bool
5516 0 : BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = IteratorKind::Sync */,
5517 : bool allowSelfHosted /* = false */)
5518 : {
5519 1961 : MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
5520 : ".next() iteration is prohibited in self-hosted code because it "
5521 : "can run user-modifiable iteration code");
5522 :
5523 1961 : MOZ_ASSERT(this->stackDepth >= 2); // ... NEXT ITER
5524 :
5525 1961 : if (!emitCall(JSOP_CALL, 0, pn)) // ... RESULT
5526 : return false;
5527 :
5528 1961 : if (iterKind == IteratorKind::Async) {
5529 0 : if (!emitAwaitInInnermostScope()) // ... RESULT
5530 : return false;
5531 : }
5532 :
5533 1961 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
5534 : return false;
5535 : checkTypeSet(JSOP_CALL);
5536 : return true;
5537 : }
5538 :
5539 : bool
5540 1619 : BytecodeEmitter::emitPushNotUndefinedOrNull()
5541 : {
5542 1619 : MOZ_ASSERT(this->stackDepth > 0); // V
5543 :
5544 1619 : if (!emit1(JSOP_DUP)) // V V
5545 : return false;
5546 0 : if (!emit1(JSOP_UNDEFINED)) // V V UNDEFINED
5547 : return false;
5548 0 : if (!emit1(JSOP_STRICTNE)) // V ?NEQL
5549 : return false;
5550 :
5551 1619 : JumpList undefinedOrNullJump;
5552 0 : if (!emitJump(JSOP_AND, &undefinedOrNullJump)) // V ?NEQL
5553 : return false;
5554 :
5555 1619 : if (!emit1(JSOP_POP)) // V
5556 : return false;
5557 1619 : if (!emit1(JSOP_DUP)) // V V
5558 : return false;
5559 1619 : if (!emit1(JSOP_NULL)) // V V NULL
5560 : return false;
5561 1619 : if (!emit1(JSOP_STRICTNE)) // V ?NEQL
5562 : return false;
5563 :
5564 0 : if (!emitJumpTargetAndPatch(undefinedOrNullJump)) // V NOT-UNDEF-OR-NULL
5565 : return false;
5566 :
5567 0 : return true;
5568 : }
5569 :
5570 : bool
5571 0 : BytecodeEmitter::emitIteratorCloseInScope(EmitterScope& currentScope,
5572 : IteratorKind iterKind /* = IteratorKind::Sync */,
5573 : CompletionKind completionKind /* = CompletionKind::Normal */,
5574 : bool allowSelfHosted /* = false */)
5575 : {
5576 1608 : MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
5577 : ".close() on iterators is prohibited in self-hosted code because it "
5578 : "can run user-modifiable iteration code");
5579 :
5580 : // Generate inline logic corresponding to IteratorClose (ES 7.4.6).
5581 : //
5582 : // Callers need to ensure that the iterator object is at the top of the
5583 : // stack.
5584 :
5585 1608 : if (!emit1(JSOP_DUP)) // ... ITER ITER
5586 : return false;
5587 :
5588 : // Step 3.
5589 : //
5590 : // Get the "return" method.
5591 4824 : if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) // ... ITER RET
5592 : return false;
5593 :
5594 : // Step 4.
5595 : //
5596 : // Do nothing if "return" is undefined or null.
5597 0 : InternalIfEmitter ifReturnMethodIsDefined(this);
5598 1608 : if (!emitPushNotUndefinedOrNull()) // ... ITER RET NOT-UNDEF-OR-NULL
5599 : return false;
5600 :
5601 1608 : if (!ifReturnMethodIsDefined.emitThenElse()) // ... ITER RET
5602 : return false;
5603 :
5604 1608 : if (completionKind == CompletionKind::Throw) {
5605 : // 7.4.6 IteratorClose ( iterator, completion )
5606 : // ...
5607 : // 3. Let return be ? GetMethod(iterator, "return").
5608 : // 4. If return is undefined, return Completion(completion).
5609 : // 5. Let innerResult be Call(return, iterator, « »).
5610 : // 6. If completion.[[Type]] is throw, return Completion(completion).
5611 : // 7. If innerResult.[[Type]] is throw, return
5612 : // Completion(innerResult).
5613 : //
5614 : // For CompletionKind::Normal case, JSOP_CALL for step 5 checks if RET
5615 : // is callable, and throws if not. Since step 6 doesn't match and
5616 : // error handling in step 3 and step 7 can be merged.
5617 : //
5618 : // For CompletionKind::Throw case, an error thrown by JSOP_CALL for
5619 : // step 5 is ignored by try-catch. So we should check if RET is
5620 : // callable here, outside of try-catch, and the throw immediately if
5621 : // not.
5622 0 : CheckIsCallableKind kind = CheckIsCallableKind::IteratorReturn;
5623 1114 : if (!emitCheckIsCallable(kind)) // ... ITER RET
5624 : return false;
5625 : }
5626 :
5627 : // Steps 5, 8.
5628 : //
5629 : // Call "return" if it is not undefined or null, and check that it returns
5630 : // an Object.
5631 1608 : if (!emit1(JSOP_SWAP)) // ... RET ITER
5632 : return false;
5633 :
5634 1608 : Maybe<TryEmitter> tryCatch;
5635 :
5636 0 : if (completionKind == CompletionKind::Throw) {
5637 1114 : tryCatch.emplace(this, TryEmitter::Kind::TryCatch, TryEmitter::ControlKind::NonSyntactic);
5638 :
5639 : // Mutate stack to balance stack for try-catch.
5640 0 : if (!emit1(JSOP_UNDEFINED)) // ... RET ITER UNDEF
5641 : return false;
5642 0 : if (!tryCatch->emitTry()) // ... RET ITER UNDEF
5643 : return false;
5644 0 : if (!emitDupAt(2)) // ... RET ITER UNDEF RET
5645 : return false;
5646 1114 : if (!emitDupAt(2)) // ... RET ITER UNDEF RET ITER
5647 : return false;
5648 : }
5649 :
5650 1608 : if (!emitCall(JSOP_CALL, 0)) // ... ... RESULT
5651 : return false;
5652 1608 : checkTypeSet(JSOP_CALL);
5653 :
5654 1608 : if (iterKind == IteratorKind::Async) {
5655 0 : if (completionKind != CompletionKind::Throw) {
5656 : // Await clobbers rval, so save the current rval.
5657 2 : if (!emit1(JSOP_GETRVAL)) // ... ... RESULT RVAL
5658 : return false;
5659 2 : if (!emit1(JSOP_SWAP)) // ... ... RVAL RESULT
5660 : return false;
5661 : }
5662 2 : if (!emitAwaitInScope(currentScope)) // ... ... RVAL? RESULT
5663 : return false;
5664 : }
5665 :
5666 1608 : if (completionKind == CompletionKind::Throw) {
5667 0 : if (!emit1(JSOP_SWAP)) // ... RET ITER RESULT UNDEF
5668 : return false;
5669 0 : if (!emit1(JSOP_POP)) // ... RET ITER RESULT
5670 : return false;
5671 :
5672 1114 : if (!tryCatch->emitCatch()) // ... RET ITER RESULT
5673 : return false;
5674 :
5675 : // Just ignore the exception thrown by call and await.
5676 1114 : if (!emit1(JSOP_EXCEPTION)) // ... RET ITER RESULT EXC
5677 : return false;
5678 1114 : if (!emit1(JSOP_POP)) // ... RET ITER RESULT
5679 : return false;
5680 :
5681 1114 : if (!tryCatch->emitEnd()) // ... RET ITER RESULT
5682 : return false;
5683 :
5684 : // Restore stack.
5685 0 : if (!emit2(JSOP_UNPICK, 2)) // ... RESULT RET ITER
5686 : return false;
5687 1 : if (!emitPopN(2)) // ... RESULT
5688 : return false;
5689 : } else {
5690 494 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ... RVAL? RESULT
5691 : return false;
5692 :
5693 0 : if (iterKind == IteratorKind::Async) {
5694 2 : if (!emit1(JSOP_SWAP)) // ... RESULT RVAL
5695 : return false;
5696 0 : if (!emit1(JSOP_SETRVAL)) // ... RESULT
5697 : return false;
5698 : }
5699 : }
5700 :
5701 0 : if (!ifReturnMethodIsDefined.emitElse()) // ... ITER RET
5702 : return false;
5703 :
5704 0 : if (!emit1(JSOP_POP)) // ... ITER
5705 : return false;
5706 :
5707 1608 : if (!ifReturnMethodIsDefined.emitEnd())
5708 : return false;
5709 :
5710 0 : return emit1(JSOP_POP); // ...
5711 : }
5712 :
5713 : template <typename InnerEmitter>
5714 : bool
5715 0 : BytecodeEmitter::wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth, InnerEmitter emitter)
5716 : {
5717 0 : MOZ_ASSERT(this->stackDepth >= iterDepth);
5718 :
5719 : // Pad a nop at the beginning of the bytecode covered by the trynote so
5720 : // that when unwinding environments, we may unwind to the scope
5721 : // corresponding to the pc *before* the start, in case the first bytecode
5722 : // emitted by |emitter| is the start of an inner scope. See comment above
5723 : // UnwindEnvironmentToTryPc.
5724 1129 : if (!emit1(JSOP_TRY_DESTRUCTURING_ITERCLOSE))
5725 : return false;
5726 :
5727 1129 : ptrdiff_t start = offset();
5728 0 : if (!emitter(this))
5729 : return false;
5730 1129 : ptrdiff_t end = offset();
5731 1129 : if (start != end)
5732 578 : return tryNoteList.append(JSTRY_DESTRUCTURING_ITERCLOSE, iterDepth, start, end);
5733 : return true;
5734 : }
5735 :
5736 : bool
5737 0 : BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern)
5738 : {
5739 41 : if (!emit1(JSOP_DUP)) // VALUE VALUE
5740 : return false;
5741 41 : if (!emit1(JSOP_UNDEFINED)) // VALUE VALUE UNDEFINED
5742 : return false;
5743 41 : if (!emit1(JSOP_STRICTEQ)) // VALUE EQL?
5744 : return false;
5745 : // Emit source note to enable ion compilation.
5746 41 : if (!newSrcNote(SRC_IF))
5747 : return false;
5748 41 : JumpList jump;
5749 41 : if (!emitJump(JSOP_IFEQ, &jump)) // VALUE
5750 : return false;
5751 41 : if (!emit1(JSOP_POP)) // .
5752 : return false;
5753 41 : if (!emitInitializerInBranch(defaultExpr, pattern)) // DEFAULTVALUE
5754 : return false;
5755 41 : if (!emitJumpTargetAndPatch(jump))
5756 : return false;
5757 41 : return true;
5758 : }
5759 :
5760 : bool
5761 838 : BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name)
5762 : {
5763 838 : MOZ_ASSERT(maybeFun->isDirectRHSAnonFunction());
5764 :
5765 838 : if (maybeFun->isKind(ParseNodeKind::Function)) {
5766 : // Function doesn't have 'name' property at this point.
5767 : // Set function's name at compile time.
5768 1662 : JSFunction* fun = maybeFun->pn_funbox->function();
5769 :
5770 : // The inferred name may already be set if this function is an
5771 : // interpreted lazy function and we OOM'ed after we set the inferred
5772 : // name the first time.
5773 831 : if (fun->hasInferredName()) {
5774 0 : MOZ_ASSERT(fun->isInterpretedLazy());
5775 0 : MOZ_ASSERT(fun->inferredName() == name);
5776 :
5777 : return true;
5778 : }
5779 :
5780 831 : fun->setInferredName(name);
5781 831 : return true;
5782 : }
5783 :
5784 7 : MOZ_ASSERT(maybeFun->isKind(ParseNodeKind::Class));
5785 :
5786 : uint32_t nameIndex;
5787 7 : if (!makeAtomIndex(name, &nameIndex))
5788 : return false;
5789 7 : if (!emitIndexOp(JSOP_STRING, nameIndex)) // FUN NAME
5790 : return false;
5791 7 : uint8_t kind = uint8_t(FunctionPrefixKind::None);
5792 7 : if (!emit2(JSOP_SETFUNNAME, kind)) // FUN
5793 : return false;
5794 7 : return true;
5795 : }
5796 :
5797 : bool
5798 15121 : BytecodeEmitter::emitInitializer(ParseNode* initializer, ParseNode* pattern)
5799 : {
5800 15121 : if (!emitTree(initializer))
5801 : return false;
5802 :
5803 15121 : if (initializer->isDirectRHSAnonFunction()) {
5804 312 : MOZ_ASSERT(!pattern->isInParens());
5805 624 : RootedAtom name(cx, pattern->name());
5806 312 : if (!setOrEmitSetFunName(initializer, name))
5807 0 : return false;
5808 : }
5809 :
5810 : return true;
5811 : }
5812 :
5813 : bool
5814 584 : BytecodeEmitter::emitInitializerInBranch(ParseNode* initializer, ParseNode* pattern)
5815 : {
5816 1168 : TDZCheckCache tdzCache(this);
5817 1168 : return emitInitializer(initializer, pattern);
5818 : }
5819 :
5820 : bool
5821 309 : BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlavor flav)
5822 : {
5823 309 : MOZ_ASSERT(pattern->isKind(ParseNodeKind::Array));
5824 309 : MOZ_ASSERT(pattern->isArity(PN_LIST));
5825 309 : MOZ_ASSERT(this->stackDepth != 0);
5826 :
5827 : // Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
5828 : //
5829 : // Lines that are annotated "covered by trynote" mean that upon throwing
5830 : // an exception, IteratorClose is called on iter only if done is false.
5831 : //
5832 : // let x, y;
5833 : // let a, b, c, d;
5834 : // let iter, next, lref, result, done, value; // stack values
5835 : //
5836 : // iter = x[Symbol.iterator]();
5837 : // next = iter.next;
5838 : //
5839 : // // ==== emitted by loop for a ====
5840 : // lref = GetReference(a); // covered by trynote
5841 : //
5842 : // result = Call(next, iter);
5843 : // done = result.done;
5844 : //
5845 : // if (done)
5846 : // value = undefined;
5847 : // else
5848 : // value = result.value;
5849 : //
5850 : // SetOrInitialize(lref, value); // covered by trynote
5851 : //
5852 : // // ==== emitted by loop for b ====
5853 : // lref = GetReference(b); // covered by trynote
5854 : //
5855 : // if (done) {
5856 : // value = undefined;
5857 : // } else {
5858 : // result = Call(next, iter);
5859 : // done = result.done;
5860 : // if (done)
5861 : // value = undefined;
5862 : // else
5863 : // value = result.value;
5864 : // }
5865 : //
5866 : // SetOrInitialize(lref, value); // covered by trynote
5867 : //
5868 : // // ==== emitted by loop for elision ====
5869 : // if (done) {
5870 : // value = undefined;
5871 : // } else {
5872 : // result = Call(next, iter);
5873 : // done = result.done;
5874 : // if (done)
5875 : // value = undefined;
5876 : // else
5877 : // value = result.value;
5878 : // }
5879 : //
5880 : // // ==== emitted by loop for c ====
5881 : // lref = GetReference(c); // covered by trynote
5882 : //
5883 : // if (done) {
5884 : // value = undefined;
5885 : // } else {
5886 : // result = Call(next, iter);
5887 : // done = result.done;
5888 : // if (done)
5889 : // value = undefined;
5890 : // else
5891 : // value = result.value;
5892 : // }
5893 : //
5894 : // if (value === undefined)
5895 : // value = y; // covered by trynote
5896 : //
5897 : // SetOrInitialize(lref, value); // covered by trynote
5898 : //
5899 : // // ==== emitted by loop for d ====
5900 : // lref = GetReference(d); // covered by trynote
5901 : //
5902 : // if (done)
5903 : // value = [];
5904 : // else
5905 : // value = [...iter];
5906 : //
5907 : // SetOrInitialize(lref, value); // covered by trynote
5908 : //
5909 : // // === emitted after loop ===
5910 : // if (!done)
5911 : // IteratorClose(iter);
5912 :
5913 : // Use an iterator to destructure the RHS, instead of index lookup. We
5914 : // must leave the *original* value on the stack.
5915 309 : if (!emit1(JSOP_DUP)) // ... OBJ OBJ
5916 : return false;
5917 0 : if (!emitIterator()) // ... OBJ NEXT ITER
5918 : return false;
5919 :
5920 : // For an empty pattern [], call IteratorClose unconditionally. Nothing
5921 : // else needs to be done.
5922 309 : if (!pattern->pn_head) {
5923 0 : if (!emit1(JSOP_SWAP)) // ... OBJ ITER NEXT
5924 : return false;
5925 0 : if (!emit1(JSOP_POP)) // ... OBJ ITER
5926 : return false;
5927 :
5928 0 : return emitIteratorCloseInInnermostScope(); // ... OBJ
5929 : }
5930 :
5931 : // Push an initial FALSE value for DONE.
5932 0 : if (!emit1(JSOP_FALSE)) // ... OBJ NEXT ITER FALSE
5933 : return false;
5934 :
5935 : // JSTRY_DESTRUCTURING_ITERCLOSE expects the iterator and the done value
5936 : // to be the second to top and the top of the stack, respectively.
5937 : // IteratorClose is called upon exception only if done is false.
5938 309 : int32_t tryNoteDepth = stackDepth;
5939 :
5940 0 : for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
5941 0 : bool isFirst = member == pattern->pn_head;
5942 1814 : DebugOnly<bool> hasNext = !!member->pn_next;
5943 :
5944 605 : size_t emitted = 0;
5945 :
5946 : // Spec requires LHS reference to be evaluated first.
5947 605 : ParseNode* lhsPattern = member;
5948 0 : if (lhsPattern->isKind(ParseNodeKind::Assign))
5949 1 : lhsPattern = lhsPattern->pn_left;
5950 :
5951 0 : bool isElision = lhsPattern->isKind(ParseNodeKind::Elision);
5952 605 : if (!isElision) {
5953 0 : auto emitLHSRef = [lhsPattern, &emitted](BytecodeEmitter* bce) {
5954 : return bce->emitDestructuringLHSRef(lhsPattern, &emitted); // ... OBJ NEXT ITER DONE *LREF
5955 1128 : };
5956 564 : if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitLHSRef))
5957 0 : return false;
5958 : }
5959 :
5960 : // Pick the DONE value to the top of the stack.
5961 605 : if (emitted) {
5962 0 : if (!emit2(JSOP_PICK, emitted)) // ... OBJ NEXT ITER *LREF DONE
5963 : return false;
5964 : }
5965 :
5966 0 : if (isFirst) {
5967 : // If this element is the first, DONE is always FALSE, so pop it.
5968 : //
5969 : // Non-first elements should emit if-else depending on the
5970 : // member pattern, below.
5971 309 : if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER *LREF
5972 : return false;
5973 : }
5974 :
5975 605 : if (member->isKind(ParseNodeKind::Spread)) {
5976 1 : InternalIfEmitter ifThenElse(this);
5977 0 : if (!isFirst) {
5978 : // If spread is not the first element of the pattern,
5979 : // iterator can already be completed.
5980 : // ... OBJ NEXT ITER *LREF DONE
5981 1 : if (!ifThenElse.emitThenElse()) // ... OBJ NEXT ITER *LREF
5982 0 : return false;
5983 :
5984 1 : if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ NEXT ITER *LREF ARRAY
5985 : return false;
5986 0 : if (!ifThenElse.emitElse()) // ... OBJ NEXT ITER *LREF
5987 : return false;
5988 : }
5989 :
5990 : // If iterator is not completed, create a new array with the rest
5991 : // of the iterator.
5992 1 : if (!emitDupAt(emitted + 1)) // ... OBJ NEXT ITER *LREF NEXT
5993 : return false;
5994 1 : if (!emitDupAt(emitted + 1)) // ... OBJ NEXT ITER *LREF NEXT ITER
5995 : return false;
5996 0 : if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ NEXT ITER *LREF NEXT ITER ARRAY
5997 : return false;
5998 1 : if (!emitNumberOp(0)) // ... OBJ NEXT ITER *LREF NEXT ITER ARRAY INDEX
5999 : return false;
6000 1 : if (!emitSpread()) // ... OBJ NEXT ITER *LREF ARRAY INDEX
6001 : return false;
6002 1 : if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER *LREF ARRAY
6003 : return false;
6004 :
6005 1 : if (!isFirst) {
6006 0 : if (!ifThenElse.emitEnd())
6007 : return false;
6008 1 : MOZ_ASSERT(ifThenElse.pushed() == 1);
6009 : }
6010 :
6011 : // At this point the iterator is done. Unpick a TRUE value for DONE above ITER.
6012 0 : if (!emit1(JSOP_TRUE)) // ... OBJ NEXT ITER *LREF ARRAY TRUE
6013 : return false;
6014 0 : if (!emit2(JSOP_UNPICK, emitted + 1)) // ... OBJ NEXT ITER TRUE *LREF ARRAY
6015 : return false;
6016 :
6017 : auto emitAssignment = [member, flav](BytecodeEmitter* bce) {
6018 : return bce->emitSetOrInitializeDestructuring(member, flav); // ... OBJ NEXT ITER TRUE
6019 2 : };
6020 1 : if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitAssignment))
6021 : return false;
6022 :
6023 0 : MOZ_ASSERT(!hasNext);
6024 1 : break;
6025 : }
6026 :
6027 604 : ParseNode* pndefault = nullptr;
6028 604 : if (member->isKind(ParseNodeKind::Assign))
6029 1 : pndefault = member->pn_right;
6030 :
6031 604 : MOZ_ASSERT(!member->isKind(ParseNodeKind::Spread));
6032 :
6033 1208 : InternalIfEmitter ifAlreadyDone(this);
6034 0 : if (!isFirst) {
6035 : // ... OBJ NEXT ITER *LREF DONE
6036 295 : if (!ifAlreadyDone.emitThenElse()) // ... OBJ NEXT ITER *LREF
6037 : return false;
6038 :
6039 0 : if (!emit1(JSOP_UNDEFINED)) // ... OBJ NEXT ITER *LREF UNDEF
6040 : return false;
6041 0 : if (!emit1(JSOP_NOP_DESTRUCTURING)) // ... OBJ NEXT ITER *LREF UNDEF
6042 : return false;
6043 :
6044 : // The iterator is done. Unpick a TRUE value for DONE above ITER.
6045 0 : if (!emit1(JSOP_TRUE)) // ... OBJ NEXT ITER *LREF UNDEF TRUE
6046 : return false;
6047 0 : if (!emit2(JSOP_UNPICK, emitted + 1)) // ... OBJ NEXT ITER TRUE *LREF UNDEF
6048 : return false;
6049 :
6050 0 : if (!ifAlreadyDone.emitElse()) // ... OBJ NEXT ITER *LREF
6051 : return false;
6052 : }
6053 :
6054 0 : if (!emitDupAt(emitted + 1)) // ... OBJ NEXT ITER *LREF NEXT
6055 : return false;
6056 0 : if (!emitDupAt(emitted + 1)) // ... OBJ NEXT ITER *LREF NEXT ITER
6057 : return false;
6058 604 : if (!emitIteratorNext(pattern)) // ... OBJ NEXT ITER *LREF RESULT
6059 : return false;
6060 604 : if (!emit1(JSOP_DUP)) // ... OBJ NEXT ITER *LREF RESULT RESULT
6061 : return false;
6062 1812 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ... OBJ NEXT ITER *LREF RESULT DONE
6063 : return false;
6064 :
6065 604 : if (!emit1(JSOP_DUP)) // ... OBJ NEXT ITER *LREF RESULT DONE DONE
6066 : return false;
6067 604 : if (!emit2(JSOP_UNPICK, emitted + 2)) // ... OBJ NEXT ITER DONE *LREF RESULT DONE
6068 : return false;
6069 :
6070 1208 : InternalIfEmitter ifDone(this);
6071 0 : if (!ifDone.emitThenElse()) // ... OBJ NEXT ITER DONE *LREF RESULT
6072 : return false;
6073 :
6074 0 : if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER DONE *LREF
6075 : return false;
6076 604 : if (!emit1(JSOP_UNDEFINED)) // ... OBJ NEXT ITER DONE *LREF UNDEF
6077 : return false;
6078 604 : if (!emit1(JSOP_NOP_DESTRUCTURING)) // ... OBJ NEXT ITER DONE *LREF UNDEF
6079 : return false;
6080 :
6081 0 : if (!ifDone.emitElse()) // ... OBJ NEXT ITER DONE *LREF RESULT
6082 : return false;
6083 :
6084 0 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ... OBJ NEXT ITER DONE *LREF VALUE
6085 : return false;
6086 :
6087 604 : if (!ifDone.emitEnd())
6088 : return false;
6089 604 : MOZ_ASSERT(ifDone.pushed() == 0);
6090 :
6091 0 : if (!isFirst) {
6092 0 : if (!ifAlreadyDone.emitEnd())
6093 : return false;
6094 0 : MOZ_ASSERT(ifAlreadyDone.pushed() == 2);
6095 : }
6096 :
6097 604 : if (pndefault) {
6098 0 : auto emitDefault = [pndefault, lhsPattern](BytecodeEmitter* bce) {
6099 : return bce->emitDefault(pndefault, lhsPattern); // ... OBJ NEXT ITER DONE *LREF VALUE
6100 2 : };
6101 :
6102 0 : if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitDefault))
6103 0 : return false;
6104 : }
6105 :
6106 0 : if (!isElision) {
6107 : auto emitAssignment = [lhsPattern, flav](BytecodeEmitter* bce) {
6108 : return bce->emitSetOrInitializeDestructuring(lhsPattern, flav); // ... OBJ NEXT ITER DONE
6109 0 : };
6110 :
6111 0 : if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitAssignment))
6112 0 : return false;
6113 : } else {
6114 41 : if (!emit1(JSOP_POP)) // ... OBJ NEXT ITER DONE
6115 : return false;
6116 : }
6117 : }
6118 :
6119 : // The last DONE value is on top of the stack. If not DONE, call
6120 : // IteratorClose.
6121 : // ... OBJ NEXT ITER DONE
6122 0 : InternalIfEmitter ifDone(this);
6123 0 : if (!ifDone.emitThenElse()) // ... OBJ NEXT ITER
6124 : return false;
6125 309 : if (!emitPopN(2)) // ... OBJ
6126 : return false;
6127 309 : if (!ifDone.emitElse()) // ... OBJ NEXT ITER
6128 : return false;
6129 309 : if (!emit1(JSOP_SWAP)) // ... OBJ ITER NEXT
6130 : return false;
6131 0 : if (!emit1(JSOP_POP)) // ... OBJ ITER
6132 : return false;
6133 309 : if (!emitIteratorCloseInInnermostScope()) // ... OBJ
6134 : return false;
6135 309 : if (!ifDone.emitEnd())
6136 : return false;
6137 :
6138 0 : return true;
6139 : }
6140 :
6141 : bool
6142 58 : BytecodeEmitter::emitComputedPropertyName(ParseNode* computedPropName)
6143 : {
6144 58 : MOZ_ASSERT(computedPropName->isKind(ParseNodeKind::ComputedName));
6145 0 : return emitTree(computedPropName->pn_kid) && emit1(JSOP_TOID);
6146 : }
6147 :
6148 : bool
6149 0 : BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFlavor flav)
6150 : {
6151 563 : MOZ_ASSERT(pattern->isKind(ParseNodeKind::Object));
6152 0 : MOZ_ASSERT(pattern->isArity(PN_LIST));
6153 :
6154 563 : MOZ_ASSERT(this->stackDepth > 0); // ... RHS
6155 :
6156 563 : if (!emit1(JSOP_CHECKOBJCOERCIBLE)) // ... RHS
6157 : return false;
6158 :
6159 0 : bool needsRestPropertyExcludedSet = pattern->pn_count > 1 &&
6160 1093 : pattern->last()->isKind(ParseNodeKind::Spread);
6161 563 : if (needsRestPropertyExcludedSet) {
6162 0 : if (!emitDestructuringObjRestExclusionSet(pattern)) // ... RHS SET
6163 : return false;
6164 :
6165 0 : if (!emit1(JSOP_SWAP)) // ... SET RHS
6166 : return false;
6167 : }
6168 :
6169 1635 : for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
6170 : ParseNode* subpattern;
6171 2144 : if (member->isKind(ParseNodeKind::MutateProto) ||
6172 0 : member->isKind(ParseNodeKind::Spread))
6173 : {
6174 0 : subpattern = member->pn_kid;
6175 : } else {
6176 1072 : subpattern = member->pn_right;
6177 : }
6178 :
6179 0 : ParseNode* lhs = subpattern;
6180 1072 : MOZ_ASSERT_IF(member->isKind(ParseNodeKind::Spread),
6181 : !lhs->isKind(ParseNodeKind::Assign));
6182 0 : if (lhs->isKind(ParseNodeKind::Assign))
6183 0 : lhs = lhs->pn_left;
6184 :
6185 : size_t emitted;
6186 1072 : if (!emitDestructuringLHSRef(lhs, &emitted)) // ... *SET RHS *LREF
6187 0 : return false;
6188 :
6189 : // Duplicate the value being destructured to use as a reference base.
6190 1072 : if (!emitDupAt(emitted)) // ... *SET RHS *LREF RHS
6191 : return false;
6192 :
6193 1072 : if (member->isKind(ParseNodeKind::Spread)) {
6194 0 : if (!updateSourceCoordNotes(member->pn_pos.begin))
6195 : return false;
6196 :
6197 0 : if (!emitNewInit(JSProto_Object)) // ... *SET RHS *LREF RHS TARGET
6198 : return false;
6199 0 : if (!emit1(JSOP_DUP)) // ... *SET RHS *LREF RHS TARGET TARGET
6200 : return false;
6201 0 : if (!emit2(JSOP_PICK, 2)) // ... *SET RHS *LREF TARGET TARGET RHS
6202 : return false;
6203 :
6204 0 : if (needsRestPropertyExcludedSet) {
6205 0 : if (!emit2(JSOP_PICK, emitted + 4)) // ... RHS *LREF TARGET TARGET RHS SET
6206 : return false;
6207 : }
6208 :
6209 : CopyOption option = needsRestPropertyExcludedSet
6210 0 : ? CopyOption::Filtered
6211 0 : : CopyOption::Unfiltered;
6212 0 : if (!emitCopyDataProperties(option)) // ... RHS *LREF TARGET
6213 : return false;
6214 :
6215 : // Destructure TARGET per this member's lhs.
6216 0 : if (!emitSetOrInitializeDestructuring(lhs, flav)) // ... RHS
6217 : return false;
6218 :
6219 0 : MOZ_ASSERT(member == pattern->last(), "Rest property is always last");
6220 0 : break;
6221 : }
6222 :
6223 : // Now push the property name currently being matched, which is the
6224 : // current property name "label" on the left of a colon in the object
6225 : // initialiser.
6226 1 : bool needsGetElem = true;
6227 :
6228 0 : if (member->isKind(ParseNodeKind::MutateProto)) {
6229 0 : if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... *SET RHS *LREF PROP
6230 : return false;
6231 : needsGetElem = false;
6232 : } else {
6233 0 : MOZ_ASSERT(member->isKind(ParseNodeKind::Colon) ||
6234 : member->isKind(ParseNodeKind::Shorthand));
6235 :
6236 0 : ParseNode* key = member->pn_left;
6237 1072 : if (key->isKind(ParseNodeKind::Number)) {
6238 0 : if (!emitNumberOp(key->pn_dval)) // ... *SET RHS *LREF RHS KEY
6239 : return false;
6240 0 : } else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
6241 0 : key->isKind(ParseNodeKind::String))
6242 : {
6243 1072 : if (!emitAtomOp(key->pn_atom, JSOP_GETPROP)) // ... *SET RHS *LREF PROP
6244 : return false;
6245 : needsGetElem = false;
6246 : } else {
6247 0 : if (!emitComputedPropertyName(key)) // ... *SET RHS *LREF RHS KEY
6248 : return false;
6249 :
6250 : // Add the computed property key to the exclusion set.
6251 0 : if (needsRestPropertyExcludedSet) {
6252 0 : if (!emitDupAt(emitted + 3)) // ... SET RHS *LREF RHS KEY SET
6253 : return false;
6254 0 : if (!emitDupAt(1)) // ... SET RHS *LREF RHS KEY SET KEY
6255 : return false;
6256 0 : if (!emit1(JSOP_UNDEFINED)) // ... SET RHS *LREF RHS KEY SET KEY UNDEFINED
6257 : return false;
6258 0 : if (!emit1(JSOP_INITELEM)) // ... SET RHS *LREF RHS KEY SET
6259 : return false;
6260 0 : if (!emit1(JSOP_POP)) // ... SET RHS *LREF RHS KEY
6261 : return false;
6262 : }
6263 : }
6264 : }
6265 :
6266 : // Get the property value if not done already.
6267 0 : if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... *SET RHS *LREF PROP
6268 : return false;
6269 :
6270 1072 : if (subpattern->isKind(ParseNodeKind::Assign)) {
6271 40 : if (!emitDefault(subpattern->pn_right, lhs)) // ... *SET RHS *LREF VALUE
6272 : return false;
6273 : }
6274 :
6275 : // Destructure PROP per this member's lhs.
6276 1072 : if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... *SET RHS
6277 : return false;
6278 : }
6279 :
6280 : return true;
6281 : }
6282 :
6283 : bool
6284 0 : BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern)
6285 : {
6286 0 : MOZ_ASSERT(pattern->isKind(ParseNodeKind::Object));
6287 0 : MOZ_ASSERT(pattern->isArity(PN_LIST));
6288 0 : MOZ_ASSERT(pattern->last()->isKind(ParseNodeKind::Spread));
6289 :
6290 0 : ptrdiff_t offset = this->offset();
6291 0 : if (!emitNewInit(JSProto_Object))
6292 : return false;
6293 :
6294 : // Try to construct the shape of the object as we go, so we can emit a
6295 : // JSOP_NEWOBJECT with the final shape instead.
6296 : // In the case of computed property names and indices, we cannot fix the
6297 : // shape at bytecode compile time. When the shape cannot be determined,
6298 : // |obj| is nulled out.
6299 :
6300 : // No need to do any guessing for the object kind, since we know the upper
6301 : // bound of how many properties we plan to have.
6302 0 : gc::AllocKind kind = gc::GetGCObjectKind(pattern->pn_count - 1);
6303 0 : RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
6304 0 : if (!obj)
6305 : return false;
6306 :
6307 0 : RootedAtom pnatom(cx);
6308 0 : for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
6309 0 : if (member->isKind(ParseNodeKind::Spread))
6310 : break;
6311 :
6312 0 : bool isIndex = false;
6313 0 : if (member->isKind(ParseNodeKind::MutateProto)) {
6314 0 : pnatom.set(cx->names().proto);
6315 : } else {
6316 0 : ParseNode* key = member->pn_left;
6317 0 : if (key->isKind(ParseNodeKind::Number)) {
6318 0 : if (!emitNumberOp(key->pn_dval))
6319 : return false;
6320 : isIndex = true;
6321 0 : } else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
6322 0 : key->isKind(ParseNodeKind::String))
6323 : {
6324 0 : pnatom.set(key->pn_atom);
6325 : } else {
6326 : // Otherwise this is a computed property name which needs to
6327 : // be added dynamically.
6328 0 : obj.set(nullptr);
6329 0 : continue;
6330 : }
6331 : }
6332 :
6333 : // Initialize elements with |undefined|.
6334 0 : if (!emit1(JSOP_UNDEFINED))
6335 : return false;
6336 :
6337 0 : if (isIndex) {
6338 0 : obj.set(nullptr);
6339 0 : if (!emit1(JSOP_INITELEM))
6340 : return false;
6341 : } else {
6342 : uint32_t index;
6343 0 : if (!makeAtomIndex(pnatom, &index))
6344 0 : return false;
6345 :
6346 0 : if (obj) {
6347 0 : MOZ_ASSERT(!obj->inDictionaryMode());
6348 0 : Rooted<jsid> id(cx, AtomToId(pnatom));
6349 0 : if (!NativeDefineDataProperty(cx, obj, id, UndefinedHandleValue, JSPROP_ENUMERATE))
6350 0 : return false;
6351 0 : if (obj->inDictionaryMode())
6352 0 : obj.set(nullptr);
6353 : }
6354 :
6355 0 : if (!emitIndex32(JSOP_INITPROP, index))
6356 : return false;
6357 : }
6358 : }
6359 :
6360 0 : if (obj) {
6361 : // The object survived and has a predictable shape: update the
6362 : // original bytecode.
6363 0 : if (!replaceNewInitWithNewObject(obj, offset))
6364 : return false;
6365 : }
6366 :
6367 : return true;
6368 : }
6369 :
6370 : bool
6371 872 : BytecodeEmitter::emitDestructuringOps(ParseNode* pattern, DestructuringFlavor flav)
6372 : {
6373 872 : if (pattern->isKind(ParseNodeKind::Array))
6374 309 : return emitDestructuringOpsArray(pattern, flav);
6375 563 : return emitDestructuringOpsObject(pattern, flav);
6376 : }
6377 :
6378 : bool
6379 754 : BytecodeEmitter::emitTemplateString(ParseNode* pn)
6380 : {
6381 754 : MOZ_ASSERT(pn->isArity(PN_LIST));
6382 :
6383 0 : bool pushedString = false;
6384 :
6385 3668 : for (ParseNode* pn2 = pn->pn_head; pn2 != NULL; pn2 = pn2->pn_next) {
6386 0 : bool isString = (pn2->getKind() == ParseNodeKind::String ||
6387 0 : pn2->getKind() == ParseNodeKind::TemplateString);
6388 :
6389 : // Skip empty strings. These are very common: a template string like
6390 : // `${a}${b}` has three empty strings and without this optimization
6391 : // we'd emit four JSOP_ADD operations instead of just one.
6392 2914 : if (isString && pn2->pn_atom->empty())
6393 : continue;
6394 :
6395 2418 : if (!isString) {
6396 : // We update source notes before emitting the expression
6397 1080 : if (!updateSourceCoordNotes(pn2->pn_pos.begin))
6398 : return false;
6399 : }
6400 :
6401 0 : if (!emitTree(pn2))
6402 : return false;
6403 :
6404 2418 : if (!isString) {
6405 : // We need to convert the expression to a string
6406 1080 : if (!emit1(JSOP_TOSTRING))
6407 : return false;
6408 : }
6409 :
6410 2418 : if (pushedString) {
6411 : // We've pushed two strings onto the stack. Add them together, leaving just one.
6412 0 : if (!emit1(JSOP_ADD))
6413 : return false;
6414 : } else {
6415 : pushedString = true;
6416 : }
6417 : }
6418 :
6419 0 : if (!pushedString) {
6420 : // All strings were empty, this can happen for something like `${""}`.
6421 : // Just push an empty string.
6422 0 : if (!emitAtomOp(cx->names().empty, JSOP_STRING))
6423 : return false;
6424 : }
6425 :
6426 : return true;
6427 : }
6428 :
6429 : bool
6430 0 : BytecodeEmitter::emitDeclarationList(ParseNode* declList)
6431 : {
6432 0 : MOZ_ASSERT(declList->isArity(PN_LIST));
6433 0 : MOZ_ASSERT(declList->isOp(JSOP_NOP));
6434 :
6435 : ParseNode* next;
6436 0 : for (ParseNode* decl = declList->pn_head; decl; decl = next) {
6437 0 : if (!updateSourceCoordNotes(decl->pn_pos.begin))
6438 : return false;
6439 0 : next = decl->pn_next;
6440 :
6441 0 : if (decl->isKind(ParseNodeKind::Assign)) {
6442 1 : MOZ_ASSERT(decl->isOp(JSOP_NOP));
6443 :
6444 524 : ParseNode* pattern = decl->pn_left;
6445 973 : MOZ_ASSERT(pattern->isKind(ParseNodeKind::Array) ||
6446 : pattern->isKind(ParseNodeKind::Object));
6447 :
6448 524 : if (!emitTree(decl->pn_right))
6449 : return false;
6450 :
6451 524 : if (!emitDestructuringOps(pattern, DestructuringDeclaration))
6452 : return false;
6453 :
6454 524 : if (!emit1(JSOP_POP))
6455 : return false;
6456 : } else {
6457 15294 : if (!emitSingleDeclaration(declList, decl, decl->expr()))
6458 : return false;
6459 : }
6460 : }
6461 : return true;
6462 : }
6463 :
6464 : bool
6465 15294 : BytecodeEmitter::emitSingleDeclaration(ParseNode* declList, ParseNode* decl,
6466 : ParseNode* initializer)
6467 : {
6468 15294 : MOZ_ASSERT(decl->isKind(ParseNodeKind::Name));
6469 :
6470 : // Nothing to do for initializer-less 'var' declarations, as there's no TDZ.
6471 0 : if (!initializer && declList->isKind(ParseNodeKind::Var))
6472 : return true;
6473 :
6474 1 : auto emitRhs = [initializer, declList, decl](BytecodeEmitter* bce, const NameLocation&, bool) {
6475 15049 : if (!initializer) {
6476 : // Lexical declarations are initialized to undefined without an
6477 : // initializer.
6478 0 : MOZ_ASSERT(declList->isKind(ParseNodeKind::Let),
6479 : "var declarations without initializers handled above, "
6480 : "and const declarations must have initializers");
6481 512 : Unused << declList; // silence clang -Wunused-lambda-capture in opt builds
6482 512 : return bce->emit1(JSOP_UNDEFINED);
6483 : }
6484 :
6485 : MOZ_ASSERT(initializer);
6486 0 : return bce->emitInitializer(initializer, decl);
6487 15049 : };
6488 :
6489 15049 : if (!emitInitializeName(decl, emitRhs))
6490 : return false;
6491 :
6492 : // Pop the RHS.
6493 0 : return emit1(JSOP_POP);
6494 : }
6495 :
6496 : static bool
6497 12895 : EmitAssignmentRhs(BytecodeEmitter* bce, ParseNode* rhs, uint8_t offset)
6498 : {
6499 : // If there is a RHS tree, emit the tree.
6500 0 : if (rhs)
6501 12891 : return bce->emitTree(rhs);
6502 :
6503 : // Otherwise the RHS value to assign is already on the stack, i.e., the
6504 : // next enumeration value in a for-in or for-of loop. Depending on how
6505 : // many other values have been pushed on the stack, we need to get the
6506 : // already-pushed RHS value.
6507 4 : if (offset != 1 && !bce->emit2(JSOP_PICK, offset - 1))
6508 : return false;
6509 :
6510 0 : return true;
6511 : }
6512 :
6513 : static inline JSOp
6514 12895 : CompoundAssignmentParseNodeKindToJSOp(ParseNodeKind pnk)
6515 : {
6516 12895 : switch (pnk) {
6517 : case ParseNodeKind::Assign: return JSOP_NOP;
6518 320 : case ParseNodeKind::AddAssign: return JSOP_ADD;
6519 12 : case ParseNodeKind::SubAssign: return JSOP_SUB;
6520 91 : case ParseNodeKind::BitOrAssign: return JSOP_BITOR;
6521 7 : case ParseNodeKind::BitXorAssign: return JSOP_BITXOR;
6522 6 : case ParseNodeKind::BitAndAssign: return JSOP_BITAND;
6523 0 : case ParseNodeKind::LshAssign: return JSOP_LSH;
6524 1 : case ParseNodeKind::RshAssign: return JSOP_RSH;
6525 0 : case ParseNodeKind::UrshAssign: return JSOP_URSH;
6526 12 : case ParseNodeKind::MulAssign: return JSOP_MUL;
6527 5 : case ParseNodeKind::DivAssign: return JSOP_DIV;
6528 0 : case ParseNodeKind::ModAssign: return JSOP_MOD;
6529 0 : case ParseNodeKind::PowAssign: return JSOP_POW;
6530 0 : default: MOZ_CRASH("unexpected compound assignment op");
6531 : }
6532 : }
6533 :
6534 : bool
6535 12895 : BytecodeEmitter::emitAssignment(ParseNode* lhs, ParseNodeKind pnk, ParseNode* rhs)
6536 : {
6537 12895 : JSOp op = CompoundAssignmentParseNodeKindToJSOp(pnk);
6538 :
6539 : // Name assignments are handled separately because choosing ops and when
6540 : // to emit BINDNAME is involved and should avoid duplication.
6541 0 : if (lhs->isKind(ParseNodeKind::Name)) {
6542 : auto emitRhs = [op, lhs, rhs](BytecodeEmitter* bce, const NameLocation& lhsLoc,
6543 0 : bool emittedBindOp)
6544 24478 : {
6545 : // For compound assignments, first get the LHS value, then emit
6546 : // the RHS and the op.
6547 0 : if (op != JSOP_NOP) {
6548 384 : if (!bce->emitGetNameAtLocationForCompoundAssignment(lhs->name(), lhsLoc))
6549 : return false;
6550 : }
6551 :
6552 : // Emit the RHS. If we emitted a BIND[G]NAME, then the scope is on
6553 : // the top of the stack and we need to pick the right RHS value.
6554 0 : if (!EmitAssignmentRhs(bce, rhs, emittedBindOp ? 2 : 1))
6555 : return false;
6556 :
6557 9580 : if (rhs && rhs->isDirectRHSAnonFunction()) {
6558 46 : MOZ_ASSERT(!lhs->isInParens());
6559 46 : MOZ_ASSERT(op == JSOP_NOP);
6560 92 : RootedAtom name(bce->cx, lhs->name());
6561 92 : if (!bce->setOrEmitSetFunName(rhs, name))
6562 0 : return false;
6563 : }
6564 :
6565 : // Emit the compound assignment op if there is one.
6566 4792 : if (op != JSOP_NOP) {
6567 1 : if (!bce->emit1(op))
6568 : return false;
6569 : }
6570 :
6571 : return true;
6572 4792 : };
6573 :
6574 4792 : return emitSetName(lhs, emitRhs);
6575 : }
6576 :
6577 : // Deal with non-name assignments.
6578 8103 : uint32_t atomIndex = (uint32_t) -1;
6579 8103 : uint8_t offset = 1;
6580 :
6581 8103 : switch (lhs->getKind()) {
6582 : case ParseNodeKind::Dot:
6583 0 : if (lhs->as<PropertyAccess>().isSuper()) {
6584 0 : if (!emitSuperPropLHS(&lhs->as<PropertyAccess>().expression()))
6585 : return false;
6586 : offset += 2;
6587 : } else {
6588 7541 : if (!emitTree(lhs->expr()))
6589 : return false;
6590 : offset += 1;
6591 : }
6592 7541 : if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
6593 : return false;
6594 : break;
6595 : case ParseNodeKind::Elem: {
6596 533 : MOZ_ASSERT(lhs->isArity(PN_BINARY));
6597 0 : EmitElemOption opt = op == JSOP_NOP ? EmitElemOption::Get : EmitElemOption::CompoundAssign;
6598 1066 : if (lhs->as<PropertyByValue>().isSuper()) {
6599 0 : if (!emitSuperElemOperands(lhs, opt))
6600 : return false;
6601 : offset += 3;
6602 : } else {
6603 533 : if (!emitElemOperands(lhs, opt))
6604 : return false;
6605 : offset += 2;
6606 : }
6607 : break;
6608 : }
6609 : case ParseNodeKind::Array:
6610 : case ParseNodeKind::Object:
6611 : break;
6612 : case ParseNodeKind::Call:
6613 0 : if (!emitTree(lhs))
6614 : return false;
6615 :
6616 : // Assignment to function calls is forbidden, but we have to make the
6617 : // call first. Now we can throw.
6618 0 : if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS))
6619 : return false;
6620 :
6621 : // Rebalance the stack to placate stack-depth assertions.
6622 0 : if (!emit1(JSOP_POP))
6623 : return false;
6624 : break;
6625 : default:
6626 0 : MOZ_ASSERT(0);
6627 : }
6628 :
6629 8103 : if (op != JSOP_NOP) {
6630 70 : MOZ_ASSERT(rhs);
6631 70 : switch (lhs->getKind()) {
6632 : case ParseNodeKind::Dot: {
6633 : JSOp getOp;
6634 0 : if (lhs->as<PropertyAccess>().isSuper()) {
6635 0 : if (!emit1(JSOP_DUP2))
6636 : return false;
6637 : getOp = JSOP_GETPROP_SUPER;
6638 : } else {
6639 58 : if (!emit1(JSOP_DUP))
6640 : return false;
6641 174 : bool isLength = (lhs->pn_atom == cx->names().length);
6642 0 : getOp = isLength ? JSOP_LENGTH : JSOP_GETPROP;
6643 : }
6644 58 : if (!emitIndex32(getOp, atomIndex))
6645 : return false;
6646 : break;
6647 : }
6648 : case ParseNodeKind::Elem: {
6649 : JSOp elemOp;
6650 0 : if (lhs->as<PropertyByValue>().isSuper()) {
6651 0 : if (!emitDupAt(2))
6652 : return false;
6653 0 : if (!emitDupAt(2))
6654 : return false;
6655 0 : if (!emitDupAt(2))
6656 : return false;
6657 : elemOp = JSOP_GETELEM_SUPER;
6658 : } else {
6659 0 : if (!emit1(JSOP_DUP2))
6660 : return false;
6661 : elemOp = JSOP_GETELEM;
6662 : }
6663 12 : if (!emitElemOpBase(elemOp))
6664 : return false;
6665 : break;
6666 : }
6667 : case ParseNodeKind::Call:
6668 : // We just emitted a JSOP_THROWMSG and popped the call's return
6669 : // value. Push a random value to make sure the stack depth is
6670 : // correct.
6671 0 : if (!emit1(JSOP_NULL))
6672 : return false;
6673 : break;
6674 : default:;
6675 : }
6676 : }
6677 :
6678 0 : if (!EmitAssignmentRhs(this, rhs, offset))
6679 : return false;
6680 :
6681 : /* If += etc., emit the binary operator with a source note. */
6682 0 : if (op != JSOP_NOP) {
6683 70 : if (!newSrcNote(SRC_ASSIGNOP))
6684 : return false;
6685 0 : if (!emit1(op))
6686 : return false;
6687 : }
6688 :
6689 : /* Finally, emit the specialized assignment bytecode. */
6690 0 : switch (lhs->getKind()) {
6691 : case ParseNodeKind::Dot: {
6692 0 : JSOp setOp = lhs->as<PropertyAccess>().isSuper() ?
6693 0 : (sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER) :
6694 0 : (sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP);
6695 7541 : if (!emitIndexOp(setOp, atomIndex))
6696 : return false;
6697 : break;
6698 : }
6699 : case ParseNodeKind::Call:
6700 : // We threw above, so nothing to do here.
6701 : break;
6702 : case ParseNodeKind::Elem: {
6703 1066 : JSOp setOp = lhs->as<PropertyByValue>().isSuper() ?
6704 0 : sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER :
6705 1066 : sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
6706 533 : if (!emit1(setOp))
6707 : return false;
6708 : break;
6709 : }
6710 : case ParseNodeKind::Array:
6711 : case ParseNodeKind::Object:
6712 29 : if (!emitDestructuringOps(lhs, DestructuringAssignment))
6713 : return false;
6714 : break;
6715 : default:
6716 0 : MOZ_ASSERT(0);
6717 : }
6718 : return true;
6719 : }
6720 :
6721 : bool
6722 0 : ParseNode::getConstantValue(JSContext* cx, AllowConstantObjects allowObjects,
6723 : MutableHandleValue vp, Value* compare, size_t ncompare,
6724 : NewObjectKind newKind)
6725 : {
6726 1 : MOZ_ASSERT(newKind == TenuredObject || newKind == SingletonObject);
6727 :
6728 2384 : switch (getKind()) {
6729 : case ParseNodeKind::Number:
6730 0 : vp.setNumber(pn_dval);
6731 0 : return true;
6732 : case ParseNodeKind::TemplateString:
6733 : case ParseNodeKind::String:
6734 0 : vp.setString(pn_atom);
6735 2027 : return true;
6736 : case ParseNodeKind::True:
6737 0 : vp.setBoolean(true);
6738 0 : return true;
6739 : case ParseNodeKind::False:
6740 0 : vp.setBoolean(false);
6741 0 : return true;
6742 : case ParseNodeKind::Null:
6743 2 : vp.setNull();
6744 0 : return true;
6745 : case ParseNodeKind::RawUndefined:
6746 0 : vp.setUndefined();
6747 0 : return true;
6748 : case ParseNodeKind::CallSiteObj:
6749 : case ParseNodeKind::Array: {
6750 : unsigned count;
6751 : ParseNode* pn;
6752 :
6753 0 : if (allowObjects == DontAllowObjects) {
6754 7 : vp.setMagic(JS_GENERIC_MAGIC);
6755 7 : return true;
6756 : }
6757 :
6758 168 : ObjectGroup::NewArrayKind arrayKind = ObjectGroup::NewArrayKind::Normal;
6759 168 : if (allowObjects == ForCopyOnWriteArray) {
6760 1 : arrayKind = ObjectGroup::NewArrayKind::CopyOnWrite;
6761 125 : allowObjects = DontAllowObjects;
6762 : }
6763 :
6764 168 : if (getKind() == ParseNodeKind::CallSiteObj) {
6765 7 : count = pn_count - 1;
6766 0 : pn = pn_head->pn_next;
6767 : } else {
6768 161 : MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
6769 0 : count = pn_count;
6770 161 : pn = pn_head;
6771 : }
6772 :
6773 168 : AutoValueVector values(cx);
6774 504 : if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), count))
6775 : return false;
6776 : size_t idx;
6777 0 : for (idx = 0; pn; idx++, pn = pn->pn_next) {
6778 0 : if (!pn->getConstantValue(cx, allowObjects, values[idx], values.begin(), idx))
6779 : return false;
6780 3548 : if (values[idx].isMagic(JS_GENERIC_MAGIC)) {
6781 0 : vp.setMagic(JS_GENERIC_MAGIC);
6782 9 : return true;
6783 : }
6784 : }
6785 0 : MOZ_ASSERT(idx == count);
6786 :
6787 0 : ArrayObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
6788 0 : newKind, arrayKind);
6789 159 : if (!obj)
6790 : return false;
6791 :
6792 159 : if (!CombineArrayElementTypes(cx, obj, compare, ncompare))
6793 : return false;
6794 :
6795 318 : vp.setObject(*obj);
6796 159 : return true;
6797 : }
6798 : case ParseNodeKind::Object: {
6799 22 : MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
6800 :
6801 22 : if (allowObjects == DontAllowObjects) {
6802 0 : vp.setMagic(JS_GENERIC_MAGIC);
6803 0 : return true;
6804 : }
6805 20 : MOZ_ASSERT(allowObjects == AllowObjects);
6806 :
6807 100 : Rooted<IdValueVector> properties(cx, IdValueVector(cx));
6808 :
6809 60 : RootedValue value(cx), idvalue(cx);
6810 448 : for (ParseNode* pn = pn_head; pn; pn = pn->pn_next) {
6811 428 : if (!pn->pn_right->getConstantValue(cx, allowObjects, &value))
6812 0 : return false;
6813 428 : if (value.isMagic(JS_GENERIC_MAGIC)) {
6814 0 : vp.setMagic(JS_GENERIC_MAGIC);
6815 0 : return true;
6816 : }
6817 :
6818 428 : ParseNode* pnid = pn->pn_left;
6819 0 : if (pnid->isKind(ParseNodeKind::Number)) {
6820 0 : idvalue = NumberValue(pnid->pn_dval);
6821 : } else {
6822 781 : MOZ_ASSERT(pnid->isKind(ParseNodeKind::ObjectPropertyName) ||
6823 : pnid->isKind(ParseNodeKind::String));
6824 1284 : MOZ_ASSERT(pnid->pn_atom != cx->names().proto);
6825 1284 : idvalue = StringValue(pnid->pn_atom);
6826 : }
6827 :
6828 856 : RootedId id(cx);
6829 0 : if (!ValueToId<CanGC>(cx, idvalue, &id))
6830 0 : return false;
6831 :
6832 0 : if (!properties.append(IdValuePair(id, value)))
6833 : return false;
6834 : }
6835 :
6836 0 : JSObject* obj = ObjectGroup::newPlainObject(cx, properties.begin(), properties.length(),
6837 20 : newKind);
6838 0 : if (!obj)
6839 : return false;
6840 :
6841 0 : if (!CombinePlainObjectPropertyTypes(cx, obj, compare, ncompare))
6842 : return false;
6843 :
6844 0 : vp.setObject(*obj);
6845 20 : return true;
6846 : }
6847 : default:
6848 0 : MOZ_CRASH("Unexpected node");
6849 : }
6850 : return false;
6851 : }
6852 :
6853 : bool
6854 43 : BytecodeEmitter::emitSingletonInitialiser(ParseNode* pn)
6855 : {
6856 : NewObjectKind newKind =
6857 43 : (pn->getKind() == ParseNodeKind::Object) ? SingletonObject : TenuredObject;
6858 :
6859 129 : RootedValue value(cx);
6860 43 : if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value, nullptr, 0, newKind))
6861 : return false;
6862 :
6863 0 : MOZ_ASSERT_IF(newKind == SingletonObject, value.toObject().isSingleton());
6864 :
6865 86 : ObjectBox* objbox = parser->newObjectBox(&value.toObject());
6866 43 : if (!objbox)
6867 : return false;
6868 :
6869 0 : return emitObjectOp(objbox, JSOP_OBJECT);
6870 : }
6871 :
6872 : bool
6873 7 : BytecodeEmitter::emitCallSiteObject(ParseNode* pn)
6874 : {
6875 0 : RootedValue value(cx);
6876 0 : if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value))
6877 : return false;
6878 :
6879 0 : MOZ_ASSERT(value.isObject());
6880 :
6881 0 : ObjectBox* objbox1 = parser->newObjectBox(&value.toObject());
6882 7 : if (!objbox1)
6883 : return false;
6884 :
6885 14 : if (!pn->as<CallSiteNode>().getRawArrayValue(cx, &value))
6886 : return false;
6887 :
6888 7 : MOZ_ASSERT(value.isObject());
6889 :
6890 14 : ObjectBox* objbox2 = parser->newObjectBox(&value.toObject());
6891 7 : if (!objbox2)
6892 : return false;
6893 :
6894 7 : return emitObjectPairOp(objbox1, objbox2, JSOP_CALLSITEOBJ);
6895 : }
6896 :
6897 : /* See the SRC_FOR source note offsetBias comments later in this file. */
6898 : JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
6899 : JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
6900 :
6901 : namespace {
6902 :
6903 : class EmitLevelManager
6904 : {
6905 : BytecodeEmitter* bce;
6906 : public:
6907 475437 : explicit EmitLevelManager(BytecodeEmitter* bce) : bce(bce) { bce->emitLevel++; }
6908 475441 : ~EmitLevelManager() { bce->emitLevel--; }
6909 : };
6910 :
6911 : } /* anonymous namespace */
6912 :
6913 : bool
6914 1003 : BytecodeEmitter::emitCatch(ParseNode* pn)
6915 : {
6916 : // We must be nested under a try-finally statement.
6917 2006 : MOZ_ASSERT(innermostNestableControl->is<TryFinallyControl>());
6918 :
6919 : /* Pick up the pending exception and bind it to the catch variable. */
6920 1003 : if (!emit1(JSOP_EXCEPTION))
6921 : return false;
6922 :
6923 0 : ParseNode* pn2 = pn->pn_left;
6924 1003 : if (!pn2) {
6925 : // Catch parameter was omitted; just discard the exception.
6926 0 : if (!emit1(JSOP_POP))
6927 : return false;
6928 : } else {
6929 1003 : switch (pn2->getKind()) {
6930 : case ParseNodeKind::Array:
6931 : case ParseNodeKind::Object:
6932 0 : if (!emitDestructuringOps(pn2, DestructuringDeclaration))
6933 : return false;
6934 1 : if (!emit1(JSOP_POP))
6935 : return false;
6936 : break;
6937 :
6938 : case ParseNodeKind::Name:
6939 0 : if (!emitLexicalInitialization(pn2))
6940 : return false;
6941 0 : if (!emit1(JSOP_POP))
6942 : return false;
6943 : break;
6944 :
6945 : default:
6946 0 : MOZ_ASSERT(0);
6947 : }
6948 : }
6949 :
6950 : /* Emit the catch body. */
6951 1003 : return emitTree(pn->pn_right);
6952 : }
6953 :
6954 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the
6955 : // comment on EmitSwitch.
6956 : MOZ_NEVER_INLINE bool
6957 1074 : BytecodeEmitter::emitTry(ParseNode* pn)
6958 : {
6959 1074 : ParseNode* catchScope = pn->pn_kid2;
6960 1074 : ParseNode* finallyNode = pn->pn_kid3;
6961 :
6962 : TryEmitter::Kind kind;
6963 1074 : if (catchScope) {
6964 1003 : if (finallyNode)
6965 : kind = TryEmitter::Kind::TryCatchFinally;
6966 : else
6967 974 : kind = TryEmitter::Kind::TryCatch;
6968 : } else {
6969 71 : MOZ_ASSERT(finallyNode);
6970 : kind = TryEmitter::Kind::TryFinally;
6971 : }
6972 2148 : TryEmitter tryCatch(this, kind, TryEmitter::ControlKind::Syntactic);
6973 :
6974 1074 : if (!tryCatch.emitTry())
6975 : return false;
6976 :
6977 0 : if (!emitTree(pn->pn_kid1))
6978 : return false;
6979 :
6980 : // If this try has a catch block, emit it.
6981 0 : if (catchScope) {
6982 : // The emitted code for a catch block looks like:
6983 : //
6984 : // [pushlexicalenv] only if any local aliased
6985 : // exception
6986 : // setlocal 0; pop assign or possibly destructure exception
6987 : // < catch block contents >
6988 : // debugleaveblock
6989 : // [poplexicalenv] only if any local aliased
6990 : // if there is a finally block:
6991 : // gosub <finally>
6992 : // goto <after finally>
6993 1003 : if (!tryCatch.emitCatch())
6994 : return false;
6995 :
6996 : // Emit the lexical scope and catch body.
6997 1003 : MOZ_ASSERT(catchScope->isKind(ParseNodeKind::LexicalScope));
6998 1003 : if (!emitTree(catchScope))
6999 : return false;
7000 : }
7001 :
7002 : // Emit the finally handler, if there is one.
7003 1074 : if (finallyNode) {
7004 300 : if (!tryCatch.emitFinally(Some(finallyNode->pn_pos.begin)))
7005 : return false;
7006 :
7007 100 : if (!emitTree(finallyNode))
7008 : return false;
7009 : }
7010 :
7011 1074 : if (!tryCatch.emitEnd())
7012 : return false;
7013 :
7014 1074 : return true;
7015 : }
7016 :
7017 : bool
7018 0 : BytecodeEmitter::emitIf(ParseNode* pn)
7019 : {
7020 0 : IfEmitter ifThenElse(this);
7021 :
7022 : if_again:
7023 : /* Emit code for the condition before pushing stmtInfo. */
7024 0 : if (!emitTree(pn->pn_kid1))
7025 : return false;
7026 :
7027 13516 : ParseNode* elseNode = pn->pn_kid3;
7028 13516 : if (elseNode) {
7029 2054 : if (!ifThenElse.emitThenElse())
7030 : return false;
7031 : } else {
7032 11462 : if (!ifThenElse.emitThen())
7033 : return false;
7034 : }
7035 :
7036 : /* Emit code for the then part. */
7037 0 : if (!emitTree(pn->pn_kid2))
7038 : return false;
7039 :
7040 13516 : if (elseNode) {
7041 2054 : if (elseNode->isKind(ParseNodeKind::If)) {
7042 682 : pn = elseNode;
7043 :
7044 682 : if (!ifThenElse.emitElseIf())
7045 : return false;
7046 :
7047 : goto if_again;
7048 : }
7049 :
7050 1372 : if (!ifThenElse.emitElse())
7051 : return false;
7052 :
7053 : /* Emit code for the else part. */
7054 1372 : if (!emitTree(elseNode))
7055 : return false;
7056 : }
7057 :
7058 12834 : if (!ifThenElse.emitEnd())
7059 : return false;
7060 :
7061 12834 : return true;
7062 : }
7063 :
7064 : bool
7065 0 : BytecodeEmitter::emitHoistedFunctionsInList(ParseNode* list)
7066 : {
7067 120 : MOZ_ASSERT(list->pn_xflags & PNX_FUNCDEFS);
7068 :
7069 0 : for (ParseNode* pn = list->pn_head; pn; pn = pn->pn_next) {
7070 1588 : ParseNode* maybeFun = pn;
7071 :
7072 0 : if (!sc->strict()) {
7073 272 : while (maybeFun->isKind(ParseNodeKind::Label))
7074 0 : maybeFun = maybeFun->as<LabeledStatement>().statement();
7075 : }
7076 :
7077 1588 : if (maybeFun->isKind(ParseNodeKind::Function) && maybeFun->functionIsHoisted()) {
7078 208 : if (!emitTree(maybeFun))
7079 : return false;
7080 : }
7081 : }
7082 :
7083 : return true;
7084 : }
7085 :
7086 : bool
7087 30359 : BytecodeEmitter::emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLineNote)
7088 : {
7089 0 : if (body->isKind(ParseNodeKind::StatementList) && body->pn_xflags & PNX_FUNCDEFS) {
7090 : // This block contains function statements whose definitions are
7091 : // hoisted to the top of the block. Emit these as a separate pass
7092 : // before the rest of the block.
7093 120 : if (!emitHoistedFunctionsInList(body))
7094 : return false;
7095 : }
7096 :
7097 : // Line notes were updated by emitLexicalScope.
7098 0 : return emitTree(body, ValueUsage::WantValue, emitLineNote);
7099 : }
7100 :
7101 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
7102 : // the comment on emitSwitch.
7103 : MOZ_NEVER_INLINE bool
7104 0 : BytecodeEmitter::emitLexicalScope(ParseNode* pn)
7105 : {
7106 0 : MOZ_ASSERT(pn->isKind(ParseNodeKind::LexicalScope));
7107 :
7108 0 : TDZCheckCache tdzCache(this);
7109 :
7110 0 : ParseNode* body = pn->scopeBody();
7111 0 : if (pn->isEmptyScope())
7112 23634 : return emitLexicalScopeBody(body);
7113 :
7114 : // We are about to emit some bytecode for what the spec calls "declaration
7115 : // instantiation". Assign these instructions to the opening `{` of the
7116 : // block. (Using the location of each declaration we're instantiating is
7117 : // too weird when stepping in the debugger.)
7118 0 : if (!ParseNodeRequiresSpecialLineNumberNotes(body)) {
7119 6725 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
7120 : return false;
7121 : }
7122 :
7123 16288 : EmitterScope emitterScope(this);
7124 : ScopeKind kind;
7125 8144 : if (body->isKind(ParseNodeKind::Catch)) {
7126 0 : kind = (!body->pn_left || body->pn_left->isKind(ParseNodeKind::Name))
7127 1003 : ? ScopeKind::SimpleCatch
7128 : : ScopeKind::Catch;
7129 : } else {
7130 : kind = ScopeKind::Lexical;
7131 : }
7132 :
7133 0 : if (!emitterScope.enterLexical(this, kind, pn->scopeBindings()))
7134 : return false;
7135 :
7136 8144 : if (body->isKind(ParseNodeKind::For)) {
7137 : // for loops need to emit {FRESHEN,RECREATE}LEXICALENV if there are
7138 : // lexical declarations in the head. Signal this by passing a
7139 : // non-nullptr lexical scope.
7140 0 : if (!emitFor(body, &emitterScope))
7141 : return false;
7142 : } else {
7143 6725 : if (!emitLexicalScopeBody(body, SUPPRESS_LINENOTE))
7144 : return false;
7145 : }
7146 :
7147 8144 : return emitterScope.leave(this);
7148 : }
7149 :
7150 : bool
7151 0 : BytecodeEmitter::emitWith(ParseNode* pn)
7152 : {
7153 0 : if (!emitTree(pn->pn_left))
7154 : return false;
7155 :
7156 0 : EmitterScope emitterScope(this);
7157 0 : if (!emitterScope.enterWith(this))
7158 : return false;
7159 :
7160 0 : if (!emitTree(pn->pn_right))
7161 : return false;
7162 :
7163 0 : return emitterScope.leave(this);
7164 : }
7165 :
7166 : bool
7167 0 : BytecodeEmitter::emitCopyDataProperties(CopyOption option)
7168 : {
7169 39 : DebugOnly<int32_t> depth = this->stackDepth;
7170 :
7171 : uint32_t argc;
7172 0 : if (option == CopyOption::Filtered) {
7173 0 : MOZ_ASSERT(depth > 2); // TARGET SOURCE SET
7174 0 : argc = 3;
7175 :
7176 0 : if (!emitAtomOp(cx->names().CopyDataProperties,
7177 0 : JSOP_GETINTRINSIC)) // TARGET SOURCE SET COPYDATAPROPERTIES
7178 : {
7179 : return false;
7180 : }
7181 : } else {
7182 0 : MOZ_ASSERT(depth > 1); // TARGET SOURCE
7183 0 : argc = 2;
7184 :
7185 39 : if (!emitAtomOp(cx->names().CopyDataPropertiesUnfiltered,
7186 0 : JSOP_GETINTRINSIC)) // TARGET SOURCE COPYDATAPROPERTIES
7187 : {
7188 : return false;
7189 : }
7190 : }
7191 :
7192 13 : if (!emit1(JSOP_UNDEFINED)) // TARGET SOURCE *SET COPYDATAPROPERTIES UNDEFINED
7193 : return false;
7194 0 : if (!emit2(JSOP_PICK, argc + 1)) // SOURCE *SET COPYDATAPROPERTIES UNDEFINED TARGET
7195 : return false;
7196 13 : if (!emit2(JSOP_PICK, argc + 1)) // *SET COPYDATAPROPERTIES UNDEFINED TARGET SOURCE
7197 : return false;
7198 13 : if (option == CopyOption::Filtered) {
7199 0 : if (!emit2(JSOP_PICK, argc + 1)) // COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
7200 : return false;
7201 : }
7202 0 : if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) // IGNORED
7203 : return false;
7204 13 : checkTypeSet(JSOP_CALL_IGNORES_RV);
7205 :
7206 13 : if (!emit1(JSOP_POP)) // -
7207 : return false;
7208 :
7209 13 : MOZ_ASSERT(depth - int(argc) == this->stackDepth);
7210 : return true;
7211 : }
7212 :
7213 : bool
7214 1672 : BytecodeEmitter::emitIterator()
7215 : {
7216 : // Convert iterable to iterator.
7217 1672 : if (!emit1(JSOP_DUP)) // OBJ OBJ
7218 : return false;
7219 0 : if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
7220 : return false;
7221 0 : if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
7222 : return false;
7223 1672 : if (!emit1(JSOP_SWAP)) // ITERFN OBJ
7224 : return false;
7225 1672 : if (!emitCall(JSOP_CALLITER, 0)) // ITER
7226 : return false;
7227 0 : checkTypeSet(JSOP_CALLITER);
7228 1672 : if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
7229 : return false;
7230 1672 : if (!emit1(JSOP_DUP)) // ITER ITER
7231 : return false;
7232 5016 : if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) // ITER NEXT
7233 : return false;
7234 0 : if (!emit1(JSOP_SWAP)) // NEXT ITER
7235 : return false;
7236 1672 : return true;
7237 : }
7238 :
7239 : bool
7240 2 : BytecodeEmitter::emitAsyncIterator()
7241 : {
7242 : // Convert iterable to iterator.
7243 2 : if (!emit1(JSOP_DUP)) // OBJ OBJ
7244 : return false;
7245 0 : if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::asyncIterator))) // OBJ OBJ @@ASYNCITERATOR
7246 : return false;
7247 0 : if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
7248 : return false;
7249 :
7250 2 : InternalIfEmitter ifAsyncIterIsUndefined(this);
7251 0 : if (!emitPushNotUndefinedOrNull()) // OBJ ITERFN !UNDEF-OR-NULL
7252 : return false;
7253 2 : if (!emit1(JSOP_NOT)) // OBJ ITERFN UNDEF-OR-NULL
7254 : return false;
7255 0 : if (!ifAsyncIterIsUndefined.emitThenElse()) // OBJ ITERFN
7256 : return false;
7257 :
7258 2 : if (!emit1(JSOP_POP)) // OBJ
7259 : return false;
7260 0 : if (!emit1(JSOP_DUP)) // OBJ OBJ
7261 : return false;
7262 2 : if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
7263 : return false;
7264 2 : if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
7265 : return false;
7266 0 : if (!emit1(JSOP_SWAP)) // ITERFN OBJ
7267 : return false;
7268 2 : if (!emitCall(JSOP_CALLITER, 0)) // ITER
7269 : return false;
7270 2 : checkTypeSet(JSOP_CALLITER);
7271 0 : if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
7272 : return false;
7273 :
7274 2 : if (!emit1(JSOP_DUP)) // ITER ITER
7275 : return false;
7276 6 : if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) // ITER SYNCNEXT
7277 : return false;
7278 :
7279 2 : if (!emit1(JSOP_TOASYNCITER)) // ITER
7280 : return false;
7281 :
7282 2 : if (!ifAsyncIterIsUndefined.emitElse()) // OBJ ITERFN
7283 : return false;
7284 :
7285 2 : if (!emit1(JSOP_SWAP)) // ITERFN OBJ
7286 : return false;
7287 0 : if (!emitCall(JSOP_CALLITER, 0)) // ITER
7288 : return false;
7289 2 : checkTypeSet(JSOP_CALLITER);
7290 2 : if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
7291 : return false;
7292 :
7293 2 : if (!ifAsyncIterIsUndefined.emitEnd()) // ITER
7294 : return false;
7295 :
7296 2 : if (!emit1(JSOP_DUP)) // ITER ITER
7297 : return false;
7298 6 : if (!emitAtomOp(cx->names().next, JSOP_GETPROP)) // ITER NEXT
7299 : return false;
7300 2 : if (!emit1(JSOP_SWAP)) // NEXT ITER
7301 : return false;
7302 :
7303 2 : return true;
7304 : }
7305 :
7306 : bool
7307 243 : BytecodeEmitter::emitSpread(bool allowSelfHosted)
7308 : {
7309 486 : LoopControl loopInfo(this, StatementKind::Spread);
7310 :
7311 : // Jump down to the loop condition to minimize overhead assuming at least
7312 : // one iteration, as the other loop forms do. Annotate so IonMonkey can
7313 : // find the loop-closing jump.
7314 : unsigned noteIndex;
7315 0 : if (!newSrcNote(SRC_FOR_OF, ¬eIndex))
7316 : return false;
7317 :
7318 : // Jump down to the loop condition to minimize overhead, assuming at least
7319 : // one iteration. (This is also what we do for loops; whether this
7320 : // assumption holds for spreads is an unanswered question.)
7321 0 : JumpList initialJump;
7322 0 : if (!emitJump(JSOP_GOTO, &initialJump)) // NEXT ITER ARR I (during the goto)
7323 : return false;
7324 :
7325 243 : JumpTarget top{ -1 };
7326 243 : if (!emitLoopHead(nullptr, &top)) // NEXT ITER ARR I
7327 : return false;
7328 :
7329 : // When we enter the goto above, we have NEXT ITER ARR I on the stack. But
7330 : // when we reach this point on the loop backedge (if spreading produces at
7331 : // least one value), we've additionally pushed a RESULT iteration value.
7332 : // Increment manually to reflect this.
7333 0 : this->stackDepth++;
7334 :
7335 243 : JumpList beq;
7336 0 : JumpTarget breakTarget{ -1 };
7337 : {
7338 : #ifdef DEBUG
7339 243 : auto loopDepth = this->stackDepth;
7340 : #endif
7341 :
7342 : // Emit code to assign result.value to the iteration variable.
7343 729 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER ARR I VALUE
7344 : return false;
7345 0 : if (!emit1(JSOP_INITELEM_INC)) // NEXT ITER ARR (I+1)
7346 : return false;
7347 :
7348 243 : MOZ_ASSERT(this->stackDepth == loopDepth - 1);
7349 :
7350 : // Spread operations can't contain |continue|, so don't bother setting loop
7351 : // and enclosing "update" offsets, as we do with for-loops.
7352 :
7353 : // COME FROM the beginning of the loop to here.
7354 243 : if (!emitLoopEntry(nullptr, initialJump)) // NEXT ITER ARR I
7355 : return false;
7356 :
7357 243 : if (!emitDupAt(3)) // NEXT ITER ARR I NEXT
7358 : return false;
7359 0 : if (!emitDupAt(3)) // NEXT ITER ARR I NEXT ITER
7360 : return false;
7361 243 : if (!emitIteratorNext(nullptr, IteratorKind::Sync, allowSelfHosted)) // ITER ARR I RESULT
7362 : return false;
7363 243 : if (!emit1(JSOP_DUP)) // NEXT ITER ARR I RESULT RESULT
7364 : return false;
7365 729 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // NEXT ITER ARR I RESULT DONE
7366 : return false;
7367 :
7368 0 : if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget)) // NEXT ITER ARR I RESULT
7369 : return false;
7370 :
7371 0 : MOZ_ASSERT(this->stackDepth == loopDepth);
7372 : }
7373 :
7374 : // Let Ion know where the closing jump of this loop is.
7375 0 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
7376 : return false;
7377 :
7378 : // No breaks or continues should occur in spreads.
7379 0 : MOZ_ASSERT(loopInfo.breaks.offset == -1);
7380 0 : MOZ_ASSERT(loopInfo.continues.offset == -1);
7381 :
7382 0 : if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
7383 : return false;
7384 :
7385 243 : if (!emit2(JSOP_PICK, 4)) // ITER ARR FINAL_INDEX RESULT NEXT
7386 : return false;
7387 243 : if (!emit2(JSOP_PICK, 4)) // ARR FINAL_INDEX RESULT NEXT ITER
7388 : return false;
7389 :
7390 0 : return emitPopN(3); // ARR FINAL_INDEX
7391 : }
7392 :
7393 : bool
7394 1254 : BytecodeEmitter::emitInitializeForInOrOfTarget(ParseNode* forHead)
7395 : {
7396 2368 : MOZ_ASSERT(forHead->isKind(ParseNodeKind::ForIn) ||
7397 : forHead->isKind(ParseNodeKind::ForOf));
7398 1254 : MOZ_ASSERT(forHead->isArity(PN_TERNARY));
7399 :
7400 1254 : MOZ_ASSERT(this->stackDepth >= 1,
7401 : "must have a per-iteration value for initializing");
7402 :
7403 1254 : ParseNode* target = forHead->pn_kid1;
7404 1254 : MOZ_ASSERT(!forHead->pn_kid2);
7405 :
7406 : // If the for-in/of loop didn't have a variable declaration, per-loop
7407 : // initialization is just assigning the iteration value to a target
7408 : // expression.
7409 0 : if (!parser->astGenerator().isDeclarationList(target))
7410 4 : return emitAssignment(target, ParseNodeKind::Assign, nullptr); // ... ITERVAL
7411 :
7412 : // Otherwise, per-loop initialization is (possibly) declaration
7413 : // initialization. If the declaration is a lexical declaration, it must be
7414 : // initialized. If the declaration is a variable declaration, an
7415 : // assignment to that name (which does *not* necessarily assign to the
7416 : // variable!) must be generated.
7417 :
7418 1250 : if (!updateSourceCoordNotes(target->pn_pos.begin))
7419 : return false;
7420 :
7421 0 : MOZ_ASSERT(target->isForLoopDeclaration());
7422 1250 : target = parser->astGenerator().singleBindingFromDeclaration(target);
7423 :
7424 0 : if (target->isKind(ParseNodeKind::Name)) {
7425 : auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&,
7426 1056 : bool emittedBindOp)
7427 : {
7428 0 : if (emittedBindOp) {
7429 : // Per-iteration initialization in for-in/of loops computes the
7430 : // iteration value *before* initializing. Thus the
7431 : // initializing value may be buried under a bind-specific value
7432 : // on the stack. Swap it to the top of the stack.
7433 0 : MOZ_ASSERT(bce->stackDepth >= 2);
7434 0 : return bce->emit1(JSOP_SWAP);
7435 : }
7436 :
7437 : // In cases of emitting a frame slot or environment slot,
7438 : // nothing needs be done.
7439 1056 : MOZ_ASSERT(bce->stackDepth >= 1);
7440 : return true;
7441 : };
7442 :
7443 : // The caller handles removing the iteration value from the stack.
7444 0 : return emitInitializeName(target, emitSwapScopeAndRhs);
7445 : }
7446 :
7447 0 : MOZ_ASSERT(!target->isKind(ParseNodeKind::Assign),
7448 : "for-in/of loop destructuring declarations can't have initializers");
7449 :
7450 204 : MOZ_ASSERT(target->isKind(ParseNodeKind::Array) ||
7451 : target->isKind(ParseNodeKind::Object));
7452 0 : return emitDestructuringOps(target, DestructuringDeclaration);
7453 : }
7454 :
7455 : bool
7456 0 : BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitterScope)
7457 : {
7458 1114 : MOZ_ASSERT(forOfLoop->isKind(ParseNodeKind::For));
7459 1114 : MOZ_ASSERT(forOfLoop->isArity(PN_BINARY));
7460 :
7461 1114 : ParseNode* forOfHead = forOfLoop->pn_left;
7462 1114 : MOZ_ASSERT(forOfHead->isKind(ParseNodeKind::ForOf));
7463 1114 : MOZ_ASSERT(forOfHead->isArity(PN_TERNARY));
7464 :
7465 1 : unsigned iflags = forOfLoop->pn_iflags;
7466 1114 : IteratorKind iterKind = (iflags & JSITER_FORAWAITOF)
7467 0 : ? IteratorKind::Async
7468 1114 : : IteratorKind::Sync;
7469 0 : MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox());
7470 1114 : MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox()->isAsync());
7471 :
7472 0 : ParseNode* forHeadExpr = forOfHead->pn_kid3;
7473 :
7474 : // Certain builtins (e.g. Array.from) are implemented in self-hosting
7475 : // as for-of loops.
7476 1114 : bool allowSelfHostedIter = false;
7477 0 : if (emitterMode == BytecodeEmitter::SelfHosting &&
7478 1124 : forHeadExpr->isKind(ParseNodeKind::Call) &&
7479 15 : forHeadExpr->pn_head->name() == cx->names().allowContentIter)
7480 : {
7481 5 : allowSelfHostedIter = true;
7482 : }
7483 :
7484 : // Evaluate the expression being iterated. The forHeadExpr should use a
7485 : // distinct TDZCheckCache to evaluate since (abstractly) it runs in its own
7486 : // LexicalEnvironment.
7487 1114 : if (!emitTreeInBranch(forHeadExpr)) // ITERABLE
7488 : return false;
7489 1114 : if (iterKind == IteratorKind::Async) {
7490 0 : if (!emitAsyncIterator()) // NEXT ITER
7491 : return false;
7492 : } else {
7493 0 : if (!emitIterator()) // NEXT ITER
7494 : return false;
7495 : }
7496 :
7497 1114 : int32_t iterDepth = stackDepth;
7498 :
7499 : // For-of loops have the iterator next method, the iterator itself, and
7500 : // the result.value on the stack.
7501 : // Push an undefined to balance the stack.
7502 1114 : if (!emit1(JSOP_UNDEFINED)) // NEXT ITER UNDEF
7503 : return false;
7504 :
7505 2228 : ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
7506 :
7507 : // Annotate so IonMonkey can find the loop-closing jump.
7508 : unsigned noteIndex;
7509 0 : if (!newSrcNote(SRC_FOR_OF, ¬eIndex))
7510 : return false;
7511 :
7512 0 : JumpList initialJump;
7513 1114 : if (!emitJump(JSOP_GOTO, &initialJump)) // NEXT ITER UNDEF
7514 : return false;
7515 :
7516 1114 : JumpTarget top{ -1 };
7517 0 : if (!emitLoopHead(nullptr, &top)) // NEXT ITER UNDEF
7518 : return false;
7519 :
7520 : // If the loop had an escaping lexical declaration, replace the current
7521 : // environment with an dead zoned one to implement TDZ semantics.
7522 1114 : if (headLexicalEmitterScope) {
7523 : // The environment chain only includes an environment for the for-of
7524 : // loop head *if* a scope binding is captured, thereby requiring
7525 : // recreation each iteration. If a lexical scope exists for the head,
7526 : // it must be the innermost one. If that scope has closed-over
7527 : // bindings inducing an environment, recreate the current environment.
7528 2204 : DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
7529 2296 : MOZ_ASSERT(forOfTarget->isKind(ParseNodeKind::Let) ||
7530 : forOfTarget->isKind(ParseNodeKind::Const));
7531 1102 : MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
7532 1102 : MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
7533 :
7534 0 : if (headLexicalEmitterScope->hasEnvironment()) {
7535 236 : if (!emit1(JSOP_RECREATELEXICALENV)) // NEXT ITER UNDEF
7536 : return false;
7537 : }
7538 :
7539 : // For uncaptured bindings, put them back in TDZ.
7540 1102 : if (!headLexicalEmitterScope->deadZoneFrameSlots(this))
7541 : return false;
7542 : }
7543 :
7544 0 : JumpList beq;
7545 1114 : JumpTarget breakTarget{ -1 };
7546 : {
7547 : #ifdef DEBUG
7548 0 : auto loopDepth = this->stackDepth;
7549 : #endif
7550 :
7551 : // Make sure this code is attributed to the "for".
7552 1114 : if (!updateSourceCoordNotes(forOfHead->pn_pos.begin))
7553 0 : return false;
7554 :
7555 1114 : if (!emit1(JSOP_POP)) // NEXT ITER
7556 : return false;
7557 0 : if (!emit1(JSOP_DUP2)) // NEXT ITER NEXT ITER
7558 : return false;
7559 :
7560 1114 : if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter))
7561 : return false; // NEXT ITER RESULT
7562 :
7563 0 : if (!emit1(JSOP_DUP)) // NEXT ITER RESULT RESULT
7564 : return false;
7565 0 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // NEXT ITER RESULT DONE
7566 : return false;
7567 :
7568 0 : InternalIfEmitter ifDone(this);
7569 :
7570 1114 : if (!ifDone.emitThen()) // NEXT ITER RESULT
7571 : return false;
7572 :
7573 : // Remove RESULT from the stack to release it.
7574 0 : if (!emit1(JSOP_POP)) // NEXT ITER
7575 : return false;
7576 0 : if (!emit1(JSOP_UNDEFINED)) // NEXT ITER UNDEF
7577 : return false;
7578 :
7579 : // If the iteration is done, leave loop here, instead of the branch at
7580 : // the end of the loop.
7581 0 : if (!loopInfo.emitSpecialBreakForDone(this)) // NEXT ITER UNDEF
7582 : return false;
7583 :
7584 1114 : if (!ifDone.emitEnd()) // NEXT ITER RESULT
7585 : return false;
7586 :
7587 : // Emit code to assign result.value to the iteration variable.
7588 : //
7589 : // Note that ES 13.7.5.13, step 5.c says getting result.value does not
7590 : // call IteratorClose, so start JSTRY_ITERCLOSE after the GETPROP.
7591 3342 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER VALUE
7592 : return false;
7593 :
7594 1114 : if (!loopInfo.emitBeginCodeNeedingIteratorClose(this))
7595 : return false;
7596 :
7597 1114 : if (!emitInitializeForInOrOfTarget(forOfHead)) // NEXT ITER VALUE
7598 : return false;
7599 :
7600 0 : MOZ_ASSERT(stackDepth == loopDepth,
7601 : "the stack must be balanced around the initializing "
7602 : "operation");
7603 :
7604 : // Remove VALUE from the stack to release it.
7605 0 : if (!emit1(JSOP_POP)) // NEXT ITER
7606 : return false;
7607 1114 : if (!emit1(JSOP_UNDEFINED)) // NEXT ITER UNDEF
7608 : return false;
7609 :
7610 : // Perform the loop body.
7611 1114 : ParseNode* forBody = forOfLoop->pn_right;
7612 1114 : if (!emitTree(forBody)) // NEXT ITER UNDEF
7613 : return false;
7614 :
7615 1114 : MOZ_ASSERT(stackDepth == loopDepth,
7616 : "the stack must be balanced around the for-of body");
7617 :
7618 1114 : if (!loopInfo.emitEndCodeNeedingIteratorClose(this))
7619 : return false;
7620 :
7621 : // Set offset for continues.
7622 0 : loopInfo.continueTarget = { offset() };
7623 :
7624 1114 : if (!emitLoopEntry(forHeadExpr, initialJump)) // NEXT ITER UNDEF
7625 : return false;
7626 :
7627 0 : if (!emit1(JSOP_FALSE)) // NEXT ITER UNDEF FALSE
7628 : return false;
7629 1114 : if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
7630 : return false; // NEXT ITER UNDEF
7631 :
7632 0 : MOZ_ASSERT(this->stackDepth == loopDepth);
7633 : }
7634 :
7635 : // Let Ion know where the closing jump of this loop is.
7636 1114 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
7637 : return false;
7638 :
7639 1114 : if (!loopInfo.patchBreaksAndContinues(this))
7640 : return false;
7641 :
7642 1114 : if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
7643 : return false;
7644 :
7645 1114 : return emitPopN(3); //
7646 : }
7647 :
7648 : bool
7649 0 : BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitterScope)
7650 : {
7651 140 : MOZ_ASSERT(forInLoop->isKind(ParseNodeKind::For));
7652 140 : MOZ_ASSERT(forInLoop->isArity(PN_BINARY));
7653 140 : MOZ_ASSERT(forInLoop->isOp(JSOP_ITER));
7654 :
7655 0 : ParseNode* forInHead = forInLoop->pn_left;
7656 140 : MOZ_ASSERT(forInHead->isKind(ParseNodeKind::ForIn));
7657 0 : MOZ_ASSERT(forInHead->isArity(PN_TERNARY));
7658 :
7659 : // Annex B: Evaluate the var-initializer expression if present.
7660 : // |for (var i = initializer in expr) { ... }|
7661 140 : ParseNode* forInTarget = forInHead->pn_kid1;
7662 0 : if (parser->astGenerator().isDeclarationList(forInTarget)) {
7663 138 : ParseNode* decl = parser->astGenerator().singleBindingFromDeclaration(forInTarget);
7664 138 : if (decl->isKind(ParseNodeKind::Name)) {
7665 0 : if (ParseNode* initializer = decl->expr()) {
7666 0 : MOZ_ASSERT(forInTarget->isKind(ParseNodeKind::Var),
7667 : "for-in initializers are only permitted for |var| declarations");
7668 :
7669 0 : if (!updateSourceCoordNotes(decl->pn_pos.begin))
7670 0 : return false;
7671 :
7672 : auto emitRhs = [decl, initializer](BytecodeEmitter* bce, const NameLocation&, bool) {
7673 : return bce->emitInitializer(initializer, decl);
7674 0 : };
7675 :
7676 0 : if (!emitInitializeName(decl, emitRhs))
7677 : return false;
7678 :
7679 : // Pop the initializer.
7680 0 : if (!emit1(JSOP_POP))
7681 : return false;
7682 : }
7683 : }
7684 : }
7685 :
7686 : // Evaluate the expression being iterated.
7687 0 : ParseNode* expr = forInHead->pn_kid3;
7688 140 : if (!emitTreeInBranch(expr)) // EXPR
7689 : return false;
7690 :
7691 0 : MOZ_ASSERT(forInLoop->pn_iflags == 0);
7692 :
7693 140 : if (!emit1(JSOP_ITER)) // ITER
7694 : return false;
7695 :
7696 : // For-in loops have both the iterator and the value on the stack. Push
7697 : // undefined to balance the stack.
7698 140 : if (!emit1(JSOP_UNDEFINED)) // ITER ITERVAL
7699 : return false;
7700 :
7701 280 : LoopControl loopInfo(this, StatementKind::ForInLoop);
7702 :
7703 : /* Annotate so IonMonkey can find the loop-closing jump. */
7704 : unsigned noteIndex;
7705 140 : if (!newSrcNote(SRC_FOR_IN, ¬eIndex))
7706 : return false;
7707 :
7708 : // Jump down to the loop condition to minimize overhead (assuming at least
7709 : // one iteration, just like the other loop forms).
7710 140 : JumpList initialJump;
7711 140 : if (!emitJump(JSOP_GOTO, &initialJump)) // ITER ITERVAL
7712 : return false;
7713 :
7714 0 : JumpTarget top{ -1 };
7715 140 : if (!emitLoopHead(nullptr, &top)) // ITER ITERVAL
7716 : return false;
7717 :
7718 : // If the loop had an escaping lexical declaration, replace the current
7719 : // environment with an dead zoned one to implement TDZ semantics.
7720 140 : if (headLexicalEmitterScope) {
7721 : // The environment chain only includes an environment for the for-in
7722 : // loop head *if* a scope binding is captured, thereby requiring
7723 : // recreation each iteration. If a lexical scope exists for the head,
7724 : // it must be the innermost one. If that scope has closed-over
7725 : // bindings inducing an environment, recreate the current environment.
7726 122 : MOZ_ASSERT(forInTarget->isKind(ParseNodeKind::Let) ||
7727 : forInTarget->isKind(ParseNodeKind::Const));
7728 118 : MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
7729 118 : MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
7730 :
7731 118 : if (headLexicalEmitterScope->hasEnvironment()) {
7732 16 : if (!emit1(JSOP_RECREATELEXICALENV)) // ITER ITERVAL
7733 : return false;
7734 : }
7735 :
7736 : // For uncaptured bindings, put them back in TDZ.
7737 118 : if (!headLexicalEmitterScope->deadZoneFrameSlots(this))
7738 : return false;
7739 : }
7740 :
7741 : {
7742 : #ifdef DEBUG
7743 140 : auto loopDepth = this->stackDepth;
7744 : #endif
7745 0 : MOZ_ASSERT(loopDepth >= 2);
7746 :
7747 140 : if (!emit1(JSOP_ITERNEXT)) // ITER ITERVAL
7748 : return false;
7749 :
7750 140 : if (!emitInitializeForInOrOfTarget(forInHead)) // ITER ITERVAL
7751 : return false;
7752 :
7753 140 : MOZ_ASSERT(this->stackDepth == loopDepth,
7754 : "iterator and iterval must be left on the stack");
7755 : }
7756 :
7757 : // Perform the loop body.
7758 140 : ParseNode* forBody = forInLoop->pn_right;
7759 0 : if (!emitTree(forBody)) // ITER ITERVAL
7760 : return false;
7761 :
7762 : // Set offset for continues.
7763 140 : loopInfo.continueTarget = { offset() };
7764 :
7765 : // Make sure this code is attributed to the "for".
7766 140 : if (!updateSourceCoordNotes(forInHead->pn_pos.begin))
7767 : return false;
7768 :
7769 0 : if (!emitLoopEntry(nullptr, initialJump)) // ITER ITERVAL
7770 : return false;
7771 140 : if (!emit1(JSOP_POP)) // ITER
7772 : return false;
7773 140 : if (!emit1(JSOP_MOREITER)) // ITER NEXTITERVAL?
7774 : return false;
7775 140 : if (!emit1(JSOP_ISNOITER)) // ITER NEXTITERVAL? ISNOITER
7776 : return false;
7777 :
7778 140 : JumpList beq;
7779 0 : JumpTarget breakTarget{ -1 };
7780 0 : if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
7781 : return false; // ITER NEXTITERVAL
7782 :
7783 : // Set the srcnote offset so we can find the closing jump.
7784 140 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
7785 : return false;
7786 :
7787 140 : if (!loopInfo.patchBreaksAndContinues(this))
7788 : return false;
7789 :
7790 : // Pop the enumeration value.
7791 140 : if (!emit1(JSOP_POP)) // ITER
7792 : return false;
7793 :
7794 140 : if (!tryNoteList.append(JSTRY_FOR_IN, this->stackDepth, top.offset, offset()))
7795 : return false;
7796 :
7797 0 : return emit1(JSOP_ENDITER); //
7798 : }
7799 :
7800 : /* C-style `for (init; cond; update) ...` loop. */
7801 : bool
7802 0 : BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope)
7803 : {
7804 706 : LoopControl loopInfo(this, StatementKind::ForLoop);
7805 :
7806 353 : ParseNode* forHead = pn->pn_left;
7807 0 : ParseNode* forBody = pn->pn_right;
7808 :
7809 : // If the head of this for-loop declared any lexical variables, the parser
7810 : // wrapped this ParseNodeKind::For node in a ParseNodeKind::LexicalScope
7811 : // representing the implicit scope of those variables. By the time we get here,
7812 : // we have already entered that scope. So far, so good.
7813 : //
7814 : // ### Scope freshening
7815 : //
7816 : // Each iteration of a `for (let V...)` loop creates a fresh loop variable
7817 : // binding for V, even if the loop is a C-style `for(;;)` loop:
7818 : //
7819 : // var funcs = [];
7820 : // for (let i = 0; i < 2; i++)
7821 : // funcs.push(function() { return i; });
7822 : // assertEq(funcs[0](), 0); // the two closures capture...
7823 : // assertEq(funcs[1](), 1); // ...two different `i` bindings
7824 : //
7825 : // This is implemented by "freshening" the implicit block -- changing the
7826 : // scope chain to a fresh clone of the instantaneous block object -- each
7827 : // iteration, just before evaluating the "update" in for(;;) loops.
7828 : //
7829 : // No freshening occurs in `for (const ...;;)` as there's no point: you
7830 : // can't reassign consts. This is observable through the Debugger API. (The
7831 : // ES6 spec also skips cloning the environment in this case.)
7832 353 : bool forLoopRequiresFreshening = false;
7833 353 : if (ParseNode* init = forHead->pn_kid1) {
7834 : // Emit the `init` clause, whether it's an expression or a variable
7835 : // declaration. (The loop variables were hoisted into an enclosing
7836 : // scope, but we still need to emit code for the initializers.)
7837 330 : if (!updateSourceCoordNotes(init->pn_pos.begin))
7838 : return false;
7839 1 : if (init->isForLoopDeclaration()) {
7840 0 : if (!emitTree(init))
7841 : return false;
7842 : } else {
7843 : // 'init' is an expression, not a declaration. emitTree left its
7844 : // value on the stack.
7845 8 : if (!emitTree(init, ValueUsage::IgnoreValue))
7846 : return false;
7847 0 : if (!emit1(JSOP_POP))
7848 : return false;
7849 : }
7850 :
7851 : // ES 13.7.4.8 step 2. The initial freshening.
7852 : //
7853 : // If an initializer let-declaration may be captured during loop iteration,
7854 : // the current scope has an environment. If so, freshen the current
7855 : // environment to expose distinct bindings for each loop iteration.
7856 330 : forLoopRequiresFreshening = init->isKind(ParseNodeKind::Let) && headLexicalEmitterScope;
7857 0 : if (forLoopRequiresFreshening) {
7858 : // The environment chain only includes an environment for the for(;;)
7859 : // loop head's let-declaration *if* a scope binding is captured, thus
7860 : // requiring a fresh environment each iteration. If a lexical scope
7861 : // exists for the head, it must be the innermost one. If that scope
7862 : // has closed-over bindings inducing an environment, recreate the
7863 : // current environment.
7864 199 : MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
7865 0 : MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
7866 :
7867 199 : if (headLexicalEmitterScope->hasEnvironment()) {
7868 16 : if (!emit1(JSOP_FRESHENLEXICALENV))
7869 : return false;
7870 : }
7871 : }
7872 : }
7873 :
7874 : /*
7875 : * NB: the SRC_FOR note has offsetBias 1 (JSOP_NOP_LENGTH).
7876 : * Use tmp to hold the biased srcnote "top" offset, which differs
7877 : * from the top local variable by the length of the JSOP_GOTO
7878 : * emitted in between tmp and top if this loop has a condition.
7879 : */
7880 : unsigned noteIndex;
7881 0 : if (!newSrcNote(SRC_FOR, ¬eIndex))
7882 : return false;
7883 0 : if (!emit1(JSOP_NOP))
7884 : return false;
7885 353 : ptrdiff_t tmp = offset();
7886 :
7887 0 : JumpList jmp;
7888 353 : if (forHead->pn_kid2) {
7889 : /* Goto the loop condition, which branches back to iterate. */
7890 0 : if (!emitJump(JSOP_GOTO, &jmp))
7891 : return false;
7892 : }
7893 :
7894 : /* Emit code for the loop body. */
7895 353 : JumpTarget top{ -1 };
7896 0 : if (!emitLoopHead(forBody, &top))
7897 : return false;
7898 353 : if (jmp.offset == -1 && !emitLoopEntry(forBody, jmp))
7899 : return false;
7900 :
7901 353 : if (!emitTreeInBranch(forBody))
7902 : return false;
7903 :
7904 : // Set loop and enclosing "update" offsets, for continue. Note that we
7905 : // continue to immediately *before* the block-freshening: continuing must
7906 : // refresh the block.
7907 0 : if (!emitJumpTarget(&loopInfo.continueTarget))
7908 : return false;
7909 :
7910 : // ES 13.7.4.8 step 3.e. The per-iteration freshening.
7911 0 : if (forLoopRequiresFreshening) {
7912 199 : MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
7913 0 : MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
7914 :
7915 199 : if (headLexicalEmitterScope->hasEnvironment()) {
7916 16 : if (!emit1(JSOP_FRESHENLEXICALENV))
7917 : return false;
7918 : }
7919 : }
7920 :
7921 : // Check for update code to do before the condition (if any).
7922 : // The update code may not be executed at all; it needs its own TDZ cache.
7923 0 : if (ParseNode* update = forHead->pn_kid3) {
7924 686 : TDZCheckCache tdzCache(this);
7925 :
7926 343 : if (!updateSourceCoordNotes(update->pn_pos.begin))
7927 0 : return false;
7928 0 : if (!emitTree(update, ValueUsage::IgnoreValue))
7929 : return false;
7930 343 : if (!emit1(JSOP_POP))
7931 : return false;
7932 :
7933 : /* Restore the absolute line number for source note readers. */
7934 0 : uint32_t lineNum = parser->errorReporter().lineAt(pn->pn_pos.end);
7935 686 : if (currentLine() != lineNum) {
7936 342 : if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum)))
7937 : return false;
7938 0 : current->currentLine = lineNum;
7939 342 : current->lastColumn = 0;
7940 : }
7941 : }
7942 :
7943 353 : ptrdiff_t tmp3 = offset();
7944 :
7945 0 : if (forHead->pn_kid2) {
7946 : /* Fix up the goto from top to target the loop condition. */
7947 345 : MOZ_ASSERT(jmp.offset >= 0);
7948 345 : if (!emitLoopEntry(forHead->pn_kid2, jmp))
7949 : return false;
7950 :
7951 345 : if (!emitTree(forHead->pn_kid2))
7952 : return false;
7953 0 : } else if (!forHead->pn_kid3) {
7954 : // If there is no condition clause and no update clause, mark
7955 : // the loop-ending "goto" with the location of the "for".
7956 : // This ensures that the debugger will stop on each loop
7957 : // iteration.
7958 7 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
7959 : return false;
7960 : }
7961 :
7962 : /* Set the first note offset so we can find the loop condition. */
7963 0 : if (!setSrcNoteOffset(noteIndex, 0, tmp3 - tmp))
7964 : return false;
7965 353 : if (!setSrcNoteOffset(noteIndex, 1, loopInfo.continueTarget.offset - tmp))
7966 : return false;
7967 :
7968 : /* If no loop condition, just emit a loop-closing jump. */
7969 353 : JumpList beq;
7970 353 : JumpTarget breakTarget{ -1 };
7971 353 : if (!emitBackwardJump(forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO, top, &beq, &breakTarget))
7972 : return false;
7973 :
7974 : /* The third note offset helps us find the loop-closing jump. */
7975 353 : if (!setSrcNoteOffset(noteIndex, 2, beq.offset - tmp))
7976 : return false;
7977 :
7978 0 : if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
7979 : return false;
7980 :
7981 353 : if (!loopInfo.patchBreaksAndContinues(this))
7982 : return false;
7983 :
7984 0 : return true;
7985 : }
7986 :
7987 : bool
7988 1607 : BytecodeEmitter::emitFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope)
7989 : {
7990 1607 : MOZ_ASSERT(pn->isKind(ParseNodeKind::For));
7991 :
7992 1 : if (pn->pn_left->isKind(ParseNodeKind::ForHead))
7993 1 : return emitCStyleFor(pn, headLexicalEmitterScope);
7994 :
7995 1254 : if (!updateLineNumberNotes(pn->pn_pos.begin))
7996 : return false;
7997 :
7998 2508 : if (pn->pn_left->isKind(ParseNodeKind::ForIn))
7999 140 : return emitForIn(pn, headLexicalEmitterScope);
8000 :
8001 0 : MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::ForOf));
8002 0 : return emitForOf(pn, headLexicalEmitterScope);
8003 : }
8004 :
8005 : MOZ_NEVER_INLINE bool
8006 0 : BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
8007 : {
8008 12436 : FunctionBox* funbox = pn->pn_funbox;
8009 0 : RootedFunction fun(cx, funbox->function());
8010 0 : RootedAtom name(cx, fun->explicitName());
8011 0 : MOZ_ASSERT_IF(fun->isInterpretedLazy(), fun->lazyScript());
8012 :
8013 : // Set the |wasEmitted| flag in the funbox once the function has been
8014 : // emitted. Function definitions that need hoisting to the top of the
8015 : // function will be seen by emitFunction in two places.
8016 0 : if (funbox->wasEmitted) {
8017 : // Annex B block-scoped functions are hoisted like any other
8018 : // block-scoped function to the top of their scope. When their
8019 : // definitions are seen for the second time, we need to emit the
8020 : // assignment that assigns the function to the outer 'var' binding.
8021 208 : if (funbox->isAnnexB) {
8022 0 : auto emitRhs = [&name](BytecodeEmitter* bce, const NameLocation&, bool) {
8023 : // The RHS is the value of the lexically bound name in the
8024 : // innermost scope.
8025 0 : return bce->emitGetName(name);
8026 0 : };
8027 :
8028 : // Get the location of the 'var' binding in the body scope. The
8029 : // name must be found, else there is a bug in the Annex B handling
8030 : // in Parser.
8031 : //
8032 : // In sloppy eval contexts, this location is dynamic.
8033 0 : Maybe<NameLocation> lhsLoc = locationOfNameBoundInScope(name, varEmitterScope);
8034 :
8035 : // If there are parameter expressions, the var name could be a
8036 : // parameter.
8037 0 : if (!lhsLoc && sc->isFunctionBox() && sc->asFunctionBox()->hasExtraBodyVarScope())
8038 0 : lhsLoc = locationOfNameBoundInScope(name, varEmitterScope->enclosingInFrame());
8039 :
8040 0 : if (!lhsLoc) {
8041 0 : lhsLoc = Some(NameLocation::DynamicAnnexBVar());
8042 : } else {
8043 0 : MOZ_ASSERT(lhsLoc->bindingKind() == BindingKind::Var ||
8044 : lhsLoc->bindingKind() == BindingKind::FormalParameter ||
8045 : (lhsLoc->bindingKind() == BindingKind::Let &&
8046 : sc->asFunctionBox()->hasParameterExprs));
8047 : }
8048 :
8049 0 : if (!emitSetOrInitializeNameAtLocation(name, *lhsLoc, emitRhs, false))
8050 0 : return false;
8051 0 : if (!emit1(JSOP_POP))
8052 : return false;
8053 : }
8054 :
8055 0 : MOZ_ASSERT_IF(fun->hasScript(), fun->nonLazyScript());
8056 0 : MOZ_ASSERT(pn->functionIsHoisted());
8057 : return true;
8058 : }
8059 :
8060 0 : funbox->wasEmitted = true;
8061 :
8062 : // Mark as singletons any function which will only be executed once, or
8063 : // which is inner to a lambda we only expect to run once. In the latter
8064 : // case, if the lambda runs multiple times then CloneFunctionObject will
8065 : // make a deep clone of its contents.
8066 24456 : if (fun->isInterpreted()) {
8067 12228 : bool singleton = checkRunOnceContext();
8068 0 : if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
8069 : return false;
8070 :
8071 0 : SharedContext* outersc = sc;
8072 24456 : if (fun->isInterpretedLazy()) {
8073 : // We need to update the static scope chain regardless of whether
8074 : // the LazyScript has already been initialized, due to the case
8075 : // where we previously successfully compiled an inner function's
8076 : // lazy script but failed to compile the outer script after the
8077 : // fact. If we attempt to compile the outer script again, the
8078 : // static scope chain will be newly allocated and will mismatch
8079 : // the previously compiled LazyScript's.
8080 0 : fun->lazyScript()->setEnclosingScope(innermostScope());
8081 0 : if (emittingRunOnceLambda)
8082 0 : fun->lazyScript()->setTreatAsRunOnce();
8083 : } else {
8084 12228 : MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript);
8085 :
8086 : // Inherit most things (principals, version, etc) from the
8087 : // parent. Use default values for the rest.
8088 24455 : Rooted<JSScript*> parent(cx, script);
8089 24456 : MOZ_ASSERT(parent->mutedErrors() == parser->options().mutedErrors());
8090 12228 : const TransitiveCompileOptions& transitiveOptions = parser->options();
8091 0 : CompileOptions options(cx, transitiveOptions);
8092 :
8093 0 : Rooted<JSObject*> sourceObject(cx, script->sourceObject());
8094 36684 : Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
8095 : funbox->bufStart, funbox->bufEnd,
8096 : funbox->toStringStart,
8097 0 : funbox->toStringEnd));
8098 0 : if (!script)
8099 0 : return false;
8100 :
8101 : BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
8102 48912 : pn->pn_pos, emitterMode);
8103 12227 : if (!bce2.init())
8104 0 : return false;
8105 :
8106 : /* We measured the max scope depth when we parsed the function. */
8107 12227 : if (!bce2.emitFunctionScript(pn->pn_body))
8108 : return false;
8109 :
8110 12228 : if (funbox->isLikelyConstructorWrapper())
8111 2 : script->setLikelyConstructorWrapper();
8112 : }
8113 :
8114 12227 : if (outersc->isFunctionBox())
8115 3365 : outersc->asFunctionBox()->setHasInnerFunctions();
8116 : } else {
8117 0 : MOZ_ASSERT(IsAsmJSModule(fun));
8118 : }
8119 :
8120 : // Make the function object a literal in the outer script's pool.
8121 0 : unsigned index = objectList.add(pn->pn_funbox);
8122 :
8123 : // Non-hoisted functions simply emit their respective op.
8124 0 : if (!pn->functionIsHoisted()) {
8125 : // JSOP_LAMBDA_ARROW is always preceded by a new.target
8126 31785 : MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
8127 0 : if (funbox->isAsync()) {
8128 632 : MOZ_ASSERT(!needsProto);
8129 0 : return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow(),
8130 1896 : fun->isGenerator());
8131 : }
8132 :
8133 19926 : if (fun->isArrow()) {
8134 4586 : if (sc->allowNewTarget()) {
8135 2058 : if (!emit1(JSOP_NEWTARGET))
8136 : return false;
8137 : } else {
8138 0 : if (!emit1(JSOP_NULL))
8139 : return false;
8140 : }
8141 : }
8142 :
8143 0 : if (needsProto) {
8144 158 : MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA);
8145 79 : pn->setOp(JSOP_FUNWITHPROTO);
8146 : }
8147 :
8148 19928 : if (pn->getOp() == JSOP_DEFFUN) {
8149 0 : if (!emitIndex32(JSOP_LAMBDA, index))
8150 : return false;
8151 0 : return emit1(JSOP_DEFFUN);
8152 : }
8153 :
8154 : // This is a FunctionExpression, ArrowFunctionExpression, or class
8155 : // constructor. Emit the single instruction (without location info).
8156 9964 : return emitIndex32(pn->getOp(), index);
8157 : }
8158 :
8159 1632 : MOZ_ASSERT(!needsProto);
8160 :
8161 : bool topLevelFunction;
8162 1674 : if (sc->isFunctionBox() || (sc->isEvalContext() && sc->strict())) {
8163 : // No nested functions inside other functions are top-level.
8164 : topLevelFunction = false;
8165 : } else {
8166 : // In sloppy eval scripts, top-level functions in are accessed
8167 : // dynamically. In global and module scripts, top-level functions are
8168 : // those bound in the var scope.
8169 2848 : NameLocation loc = lookupName(name);
8170 2848 : topLevelFunction = loc.kind() == NameLocation::Kind::Dynamic ||
8171 1424 : loc.bindingKind() == BindingKind::Var;
8172 : }
8173 :
8174 1632 : if (topLevelFunction) {
8175 1424 : if (sc->isModuleContext()) {
8176 : // For modules, we record the function and instantiate the binding
8177 : // during ModuleInstantiate(), before the script is run.
8178 :
8179 0 : RootedModuleObject module(cx, sc->asModuleContext()->module());
8180 0 : if (!module->noteFunctionDeclaration(cx, name, fun))
8181 0 : return false;
8182 : } else {
8183 1424 : MOZ_ASSERT(sc->isGlobalContext() || sc->isEvalContext());
8184 0 : MOZ_ASSERT(pn->getOp() == JSOP_NOP);
8185 1424 : switchToPrologue();
8186 0 : if (funbox->isAsync()) {
8187 0 : if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow(),
8188 108 : fun->isGenerator()))
8189 : {
8190 : return false;
8191 : }
8192 : } else {
8193 1370 : if (!emitIndex32(JSOP_LAMBDA, index))
8194 : return false;
8195 : }
8196 1424 : if (!emit1(JSOP_DEFFUN))
8197 : return false;
8198 : switchToMain();
8199 : }
8200 : } else {
8201 : // For functions nested within functions and blocks, make a lambda and
8202 : // initialize the binding name of the function in the current scope.
8203 :
8204 208 : bool isAsync = funbox->isAsync();
8205 0 : bool isGenerator = funbox->isGenerator();
8206 : auto emitLambda = [index, isAsync, isGenerator](BytecodeEmitter* bce,
8207 0 : const NameLocation&, bool) {
8208 208 : if (isAsync) {
8209 5 : return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
8210 5 : /* isArrow = */ false, isGenerator);
8211 : }
8212 203 : return bce->emitIndexOp(JSOP_LAMBDA, index);
8213 208 : };
8214 :
8215 416 : if (!emitInitializeName(name, emitLambda))
8216 : return false;
8217 208 : if (!emit1(JSOP_POP))
8218 : return false;
8219 : }
8220 :
8221 : return true;
8222 : }
8223 :
8224 : bool
8225 0 : BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
8226 691 : if (isArrow) {
8227 230 : if (sc->allowNewTarget()) {
8228 114 : if (!emit1(JSOP_NEWTARGET))
8229 : return false;
8230 : } else {
8231 1 : if (!emit1(JSOP_NULL))
8232 : return false;
8233 : }
8234 115 : if (!emitIndex32(JSOP_LAMBDA_ARROW, index))
8235 : return false;
8236 : } else {
8237 0 : if (!emitIndex32(JSOP_LAMBDA, index))
8238 : return false;
8239 : }
8240 :
8241 : return true;
8242 : }
8243 :
8244 : bool
8245 691 : BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
8246 : bool isGenerator)
8247 : {
8248 : // needsHomeObject can be true for propertyList for extended class.
8249 : // In that case push both unwrapped and wrapped function, in order to
8250 : // initialize home object of unwrapped function, and set wrapped function
8251 : // as a property.
8252 : //
8253 : // lambda // unwrapped
8254 : // dup // unwrapped unwrapped
8255 : // toasync // unwrapped wrapped
8256 : //
8257 : // Emitted code is surrounded by the following code.
8258 : //
8259 : // // classObj classCtor classProto
8260 : // (emitted code) // classObj classCtor classProto unwrapped wrapped
8261 : // swap // classObj classCtor classProto wrapped unwrapped
8262 : // inithomeobject 1 // classObj classCtor classProto wrapped unwrapped
8263 : // // initialize the home object of unwrapped
8264 : // // with classProto here
8265 : // pop // classObj classCtor classProto wrapped
8266 : // inithiddenprop // classObj classCtor classProto wrapped
8267 : // // initialize the property of the classProto
8268 : // // with wrapped function here
8269 : // pop // classObj classCtor classProto
8270 : //
8271 : // needsHomeObject is false for other cases, push wrapped function only.
8272 691 : if (!emitAsyncWrapperLambda(index, isArrow))
8273 : return false;
8274 691 : if (needsHomeObject) {
8275 5 : if (!emit1(JSOP_DUP))
8276 : return false;
8277 : }
8278 691 : if (isGenerator) {
8279 2 : if (!emit1(JSOP_TOASYNCGEN))
8280 : return false;
8281 : } else {
8282 689 : if (!emit1(JSOP_TOASYNC))
8283 : return false;
8284 : }
8285 : return true;
8286 : }
8287 :
8288 : bool
8289 290 : BytecodeEmitter::emitDo(ParseNode* pn)
8290 : {
8291 : /* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */
8292 : unsigned noteIndex;
8293 290 : if (!newSrcNote(SRC_WHILE, ¬eIndex))
8294 : return false;
8295 0 : if (!emit1(JSOP_NOP))
8296 : return false;
8297 :
8298 : unsigned noteIndex2;
8299 0 : if (!newSrcNote(SRC_WHILE, ¬eIndex2))
8300 : return false;
8301 :
8302 : /* Compile the loop body. */
8303 : JumpTarget top;
8304 290 : if (!emitLoopHead(pn->pn_left, &top))
8305 : return false;
8306 :
8307 580 : LoopControl loopInfo(this, StatementKind::DoLoop);
8308 :
8309 0 : JumpList empty;
8310 290 : if (!emitLoopEntry(nullptr, empty))
8311 : return false;
8312 :
8313 290 : if (!emitTree(pn->pn_left))
8314 : return false;
8315 :
8316 : // Set the offset for continues.
8317 0 : if (!emitJumpTarget(&loopInfo.continueTarget))
8318 : return false;
8319 :
8320 : /* Compile the loop condition, now that continues know where to go. */
8321 0 : if (!emitTree(pn->pn_right))
8322 : return false;
8323 :
8324 290 : JumpList beq;
8325 0 : JumpTarget breakTarget{ -1 };
8326 290 : if (!emitBackwardJump(JSOP_IFNE, top, &beq, &breakTarget))
8327 : return false;
8328 :
8329 290 : if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
8330 : return false;
8331 :
8332 : /*
8333 : * Update the annotations with the update and back edge positions, for
8334 : * IonBuilder.
8335 : *
8336 : * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
8337 : * note gets bigger.
8338 : */
8339 290 : if (!setSrcNoteOffset(noteIndex2, 0, beq.offset - top.offset))
8340 : return false;
8341 290 : if (!setSrcNoteOffset(noteIndex, 0, 1 + (loopInfo.continueTarget.offset - top.offset)))
8342 : return false;
8343 :
8344 0 : if (!loopInfo.patchBreaksAndContinues(this))
8345 : return false;
8346 :
8347 0 : return true;
8348 : }
8349 :
8350 : bool
8351 0 : BytecodeEmitter::emitWhile(ParseNode* pn)
8352 : {
8353 : /*
8354 : * Minimize bytecodes issued for one or more iterations by jumping to
8355 : * the condition below the body and closing the loop if the condition
8356 : * is true with a backward branch. For iteration count i:
8357 : *
8358 : * i test at the top test at the bottom
8359 : * = =============== ==================
8360 : * 0 ifeq-pass goto; ifne-fail
8361 : * 1 ifeq-fail; goto; ifne-pass goto; ifne-pass; ifne-fail
8362 : * 2 2*(ifeq-fail; goto); ifeq-pass goto; 2*ifne-pass; ifne-fail
8363 : * . . .
8364 : * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail
8365 : */
8366 :
8367 : // If we have a single-line while, like "while (x) ;", we want to
8368 : // emit the line note before the initial goto, so that the
8369 : // debugger sees a single entry point. This way, if there is a
8370 : // breakpoint on the line, it will only fire once; and "next"ing
8371 : // will skip the whole loop. However, for the multi-line case we
8372 : // want to emit the line note after the initial goto, so that
8373 : // "cont" stops on each iteration -- but without a stop before the
8374 : // first iteration.
8375 0 : if (parser->errorReporter().lineAt(pn->pn_pos.begin) ==
8376 267 : parser->errorReporter().lineAt(pn->pn_pos.end))
8377 : {
8378 1 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
8379 : return false;
8380 : }
8381 :
8382 0 : JumpTarget top{ -1 };
8383 0 : if (!emitJumpTarget(&top))
8384 : return false;
8385 :
8386 534 : LoopControl loopInfo(this, StatementKind::WhileLoop);
8387 0 : loopInfo.continueTarget = top;
8388 :
8389 : unsigned noteIndex;
8390 0 : if (!newSrcNote(SRC_WHILE, ¬eIndex))
8391 : return false;
8392 :
8393 267 : JumpList jmp;
8394 0 : if (!emitJump(JSOP_GOTO, &jmp))
8395 : return false;
8396 :
8397 0 : if (!emitLoopHead(pn->pn_right, &top))
8398 : return false;
8399 :
8400 267 : if (!emitTreeInBranch(pn->pn_right))
8401 : return false;
8402 :
8403 0 : if (!emitLoopEntry(pn->pn_left, jmp))
8404 : return false;
8405 0 : if (!emitTree(pn->pn_left))
8406 : return false;
8407 :
8408 0 : JumpList beq;
8409 0 : JumpTarget breakTarget{ -1 };
8410 267 : if (!emitBackwardJump(JSOP_IFNE, top, &beq, &breakTarget))
8411 : return false;
8412 :
8413 267 : if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
8414 : return false;
8415 :
8416 0 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - jmp.offset))
8417 : return false;
8418 :
8419 0 : if (!loopInfo.patchBreaksAndContinues(this))
8420 : return false;
8421 :
8422 267 : return true;
8423 : }
8424 :
8425 : bool
8426 1260 : BytecodeEmitter::emitBreak(PropertyName* label)
8427 : {
8428 : BreakableControl* target;
8429 : SrcNoteType noteType;
8430 1260 : if (label) {
8431 : // Any statement with the matching label may be the break target.
8432 0 : auto hasSameLabel = [label](LabelControl* labelControl) {
8433 0 : return labelControl->label() == label;
8434 0 : };
8435 0 : target = findInnermostNestableControl<LabelControl>(hasSameLabel);
8436 0 : noteType = SRC_BREAK2LABEL;
8437 : } else {
8438 : auto isNotLabel = [](BreakableControl* control) {
8439 0 : return !control->is<LabelControl>();
8440 : };
8441 2520 : target = findInnermostNestableControl<BreakableControl>(isNotLabel);
8442 1260 : noteType = (target->kind() == StatementKind::Switch) ? SRC_SWITCHBREAK : SRC_BREAK;
8443 : }
8444 :
8445 0 : return emitGoto(target, &target->breaks, noteType);
8446 : }
8447 :
8448 : bool
8449 265 : BytecodeEmitter::emitContinue(PropertyName* label)
8450 : {
8451 0 : LoopControl* target = nullptr;
8452 265 : if (label) {
8453 : // Find the loop statement enclosed by the matching label.
8454 0 : NestableControl* control = innermostNestableControl;
8455 0 : while (!control->is<LabelControl>() || control->as<LabelControl>().label() != label) {
8456 0 : if (control->is<LoopControl>())
8457 0 : target = &control->as<LoopControl>();
8458 0 : control = control->enclosing();
8459 : }
8460 : } else {
8461 530 : target = findInnermostNestableControl<LoopControl>();
8462 : }
8463 0 : return emitGoto(target, &target->continues, SRC_CONTINUE);
8464 : }
8465 :
8466 : bool
8467 22826 : BytecodeEmitter::emitGetFunctionThis(ParseNode* pn)
8468 : {
8469 22826 : MOZ_ASSERT(sc->thisBinding() == ThisBinding::Function);
8470 22826 : MOZ_ASSERT(pn->isKind(ParseNodeKind::Name));
8471 68482 : MOZ_ASSERT(pn->name() == cx->names().dotThis);
8472 :
8473 22828 : if (!emitTree(pn))
8474 : return false;
8475 45656 : if (sc->needsThisTDZChecks() && !emit1(JSOP_CHECKTHIS))
8476 : return false;
8477 :
8478 0 : return true;
8479 : }
8480 :
8481 : bool
8482 0 : BytecodeEmitter::emitGetThisForSuperBase(ParseNode* pn)
8483 : {
8484 0 : MOZ_ASSERT(pn->isKind(ParseNodeKind::SuperBase));
8485 60 : return emitGetFunctionThis(pn->pn_kid);
8486 : }
8487 :
8488 : bool
8489 0 : BytecodeEmitter::emitThisLiteral(ParseNode* pn)
8490 : {
8491 23660 : MOZ_ASSERT(pn->isKind(ParseNodeKind::This));
8492 :
8493 23660 : if (ParseNode* thisName = pn->pn_kid)
8494 0 : return emitGetFunctionThis(thisName);
8495 :
8496 0 : if (sc->thisBinding() == ThisBinding::Module)
8497 0 : return emit1(JSOP_UNDEFINED);
8498 :
8499 0 : MOZ_ASSERT(sc->thisBinding() == ThisBinding::Global);
8500 894 : return emit1(JSOP_GLOBALTHIS);
8501 : }
8502 :
8503 : bool
8504 0 : BytecodeEmitter::emitCheckDerivedClassConstructorReturn()
8505 : {
8506 0 : MOZ_ASSERT(lookupName(cx->names().dotThis).hasKnownSlot());
8507 237 : if (!emitGetName(cx->names().dotThis))
8508 : return false;
8509 0 : if (!emit1(JSOP_CHECKRETURN))
8510 : return false;
8511 79 : return true;
8512 : }
8513 :
8514 : bool
8515 11321 : BytecodeEmitter::emitReturn(ParseNode* pn)
8516 : {
8517 11321 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
8518 : return false;
8519 :
8520 22642 : bool needsIteratorResult = sc->isFunctionBox() && sc->asFunctionBox()->needsIteratorResult();
8521 11321 : if (needsIteratorResult) {
8522 0 : if (!emitPrepareIteratorResult())
8523 : return false;
8524 : }
8525 :
8526 : /* Push a return value */
8527 11321 : if (ParseNode* pn2 = pn->pn_kid) {
8528 9792 : if (!emitTree(pn2))
8529 : return false;
8530 :
8531 0 : bool isAsyncGenerator = sc->asFunctionBox()->isAsync() &&
8532 10718 : sc->asFunctionBox()->isGenerator();
8533 9792 : if (isAsyncGenerator) {
8534 0 : if (!emitAwaitInInnermostScope())
8535 : return false;
8536 : }
8537 : } else {
8538 : /* No explicit return value provided */
8539 1529 : if (!emit1(JSOP_UNDEFINED))
8540 : return false;
8541 : }
8542 :
8543 11321 : if (needsIteratorResult) {
8544 0 : if (!emitFinishIteratorResult(true))
8545 : return false;
8546 : }
8547 :
8548 : // We know functionBodyEndPos is set because "return" is only
8549 : // valid in a function, and so we've passed through
8550 : // emitFunctionScript.
8551 0 : MOZ_ASSERT(functionBodyEndPosSet);
8552 11321 : if (!updateSourceCoordNotes(functionBodyEndPos))
8553 : return false;
8554 :
8555 : /*
8556 : * EmitNonLocalJumpFixup may add fixup bytecode to close open try
8557 : * blocks having finally clauses and to exit intermingled let blocks.
8558 : * We can't simply transfer control flow to our caller in that case,
8559 : * because we must gosub to those finally clauses from inner to outer,
8560 : * with the correct stack pointer (i.e., after popping any with,
8561 : * for/in, etc., slots nested inside the finally's try).
8562 : *
8563 : * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
8564 : * extra JSOP_RETRVAL after the fixups.
8565 : */
8566 11321 : ptrdiff_t top = offset();
8567 :
8568 22642 : bool needsFinalYield = sc->isFunctionBox() && sc->asFunctionBox()->needsFinalYield();
8569 : bool isDerivedClassConstructor =
8570 0 : sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
8571 :
8572 11321 : if (!emit1((needsFinalYield || isDerivedClassConstructor) ? JSOP_SETRVAL : JSOP_RETURN))
8573 : return false;
8574 :
8575 : // Make sure that we emit this before popping the blocks in prepareForNonLocalJump,
8576 : // to ensure that the error is thrown while the scope-chain is still intact.
8577 0 : if (isDerivedClassConstructor) {
8578 0 : if (!emitCheckDerivedClassConstructorReturn())
8579 : return false;
8580 : }
8581 :
8582 22642 : NonLocalExitControl nle(this, NonLocalExitControl::Return);
8583 :
8584 0 : if (!nle.prepareForNonLocalJumpToOutermost())
8585 : return false;
8586 :
8587 0 : if (needsFinalYield) {
8588 : // We know that .generator is on the function scope, as we just exited
8589 : // all nested scopes.
8590 : NameLocation loc =
8591 0 : *locationOfNameBoundInFunctionScope(cx->names().dotGenerator, varEmitterScope);
8592 1896 : if (!emitGetNameAtLocation(cx->names().dotGenerator, loc))
8593 0 : return false;
8594 632 : if (!emitYieldOp(JSOP_FINALYIELDRVAL))
8595 : return false;
8596 10689 : } else if (isDerivedClassConstructor) {
8597 0 : MOZ_ASSERT(code()[top] == JSOP_SETRVAL);
8598 0 : if (!emit1(JSOP_RETRVAL))
8599 : return false;
8600 10689 : } else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) != offset()) {
8601 0 : code()[top] = JSOP_SETRVAL;
8602 3923 : if (!emit1(JSOP_RETRVAL))
8603 : return false;
8604 : }
8605 :
8606 : return true;
8607 : }
8608 :
8609 : bool
8610 0 : BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope& currentScope)
8611 : {
8612 0 : NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator, ¤tScope);
8613 6045 : return emitGetNameAtLocation(cx->names().dotGenerator, loc);
8614 : }
8615 :
8616 : bool
8617 729 : BytecodeEmitter::emitInitialYield(ParseNode* pn)
8618 : {
8619 729 : if (!emitTree(pn->pn_kid))
8620 : return false;
8621 :
8622 729 : if (!emitYieldOp(JSOP_INITIALYIELD))
8623 : return false;
8624 :
8625 729 : if (!emit1(JSOP_POP))
8626 : return false;
8627 :
8628 0 : return true;
8629 : }
8630 :
8631 : bool
8632 0 : BytecodeEmitter::emitYield(ParseNode* pn)
8633 : {
8634 44 : MOZ_ASSERT(sc->isFunctionBox());
8635 0 : MOZ_ASSERT(pn->isKind(ParseNodeKind::Yield));
8636 :
8637 88 : bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
8638 44 : if (needsIteratorResult) {
8639 0 : if (!emitPrepareIteratorResult())
8640 : return false;
8641 : }
8642 0 : if (pn->pn_kid) {
8643 0 : if (!emitTree(pn->pn_kid))
8644 : return false;
8645 : } else {
8646 0 : if (!emit1(JSOP_UNDEFINED))
8647 : return false;
8648 : }
8649 :
8650 : // 11.4.3.7 AsyncGeneratorYield step 5.
8651 88 : bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
8652 0 : if (isAsyncGenerator) {
8653 1 : if (!emitAwaitInInnermostScope()) // RESULT
8654 : return false;
8655 : }
8656 :
8657 44 : if (needsIteratorResult) {
8658 0 : if (!emitFinishIteratorResult(false))
8659 : return false;
8660 : }
8661 :
8662 44 : if (!emitGetDotGeneratorInInnermostScope())
8663 : return false;
8664 :
8665 0 : if (!emitYieldOp(JSOP_YIELD))
8666 : return false;
8667 :
8668 44 : return true;
8669 : }
8670 :
8671 : bool
8672 1222 : BytecodeEmitter::emitAwaitInInnermostScope(ParseNode* pn)
8673 : {
8674 0 : MOZ_ASSERT(sc->isFunctionBox());
8675 0 : MOZ_ASSERT(pn->isKind(ParseNodeKind::Await));
8676 :
8677 0 : if (!emitTree(pn->pn_kid))
8678 : return false;
8679 1222 : return emitAwaitInInnermostScope();
8680 : }
8681 :
8682 : bool
8683 1233 : BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope)
8684 : {
8685 0 : if (!emitGetDotGeneratorInScope(currentScope))
8686 : return false;
8687 0 : if (!emitYieldOp(JSOP_AWAIT))
8688 : return false;
8689 0 : return true;
8690 : }
8691 :
8692 : bool
8693 9 : BytecodeEmitter::emitYieldStar(ParseNode* iter)
8694 : {
8695 9 : MOZ_ASSERT(sc->isFunctionBox());
8696 0 : MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
8697 :
8698 0 : bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
8699 :
8700 0 : if (!emitTree(iter)) // ITERABLE
8701 : return false;
8702 0 : if (isAsyncGenerator) {
8703 0 : if (!emitAsyncIterator()) // NEXT ITER
8704 : return false;
8705 : } else {
8706 7 : if (!emitIterator()) // NEXT ITER
8707 : return false;
8708 : }
8709 :
8710 : // Initial send value is undefined.
8711 0 : if (!emit1(JSOP_UNDEFINED)) // NEXT ITER RECEIVED
8712 : return false;
8713 :
8714 : int32_t savedDepthTemp;
8715 9 : int32_t startDepth = stackDepth;
8716 9 : MOZ_ASSERT(startDepth >= 3);
8717 :
8718 : TryEmitter tryCatch(this, TryEmitter::Kind::TryCatchFinally,
8719 0 : TryEmitter::ControlKind::NonSyntactic);
8720 9 : if (!tryCatch.emitJumpOverCatchAndFinally()) // NEXT ITER RESULT
8721 : return false;
8722 :
8723 9 : JumpTarget tryStart{ offset() };
8724 9 : if (!tryCatch.emitTry()) // NEXT ITER RESULT
8725 : return false;
8726 :
8727 9 : MOZ_ASSERT(this->stackDepth == startDepth);
8728 :
8729 : // 11.4.3.7 AsyncGeneratorYield step 5.
8730 0 : if (isAsyncGenerator) {
8731 0 : if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT
8732 : return false;
8733 : }
8734 :
8735 : // Load the generator object.
8736 9 : if (!emitGetDotGeneratorInInnermostScope()) // NEXT ITER RESULT GENOBJ
8737 : return false;
8738 :
8739 : // Yield RESULT as-is, without re-boxing.
8740 9 : if (!emitYieldOp(JSOP_YIELD)) // NEXT ITER RECEIVED
8741 : return false;
8742 :
8743 0 : if (!tryCatch.emitCatch()) // NEXT ITER RESULT
8744 : return false;
8745 :
8746 9 : stackDepth = startDepth; // NEXT ITER RESULT
8747 9 : if (!emit1(JSOP_EXCEPTION)) // NEXT ITER RESULT EXCEPTION
8748 : return false;
8749 0 : if (!emitDupAt(2)) // NEXT ITER RESULT EXCEPTION ITER
8750 : return false;
8751 9 : if (!emit1(JSOP_DUP)) // NEXT ITER RESULT EXCEPTION ITER ITER
8752 : return false;
8753 27 : if (!emitAtomOp(cx->names().throw_, JSOP_CALLPROP)) // NEXT ITER RESULT EXCEPTION ITER THROW
8754 : return false;
8755 9 : if (!emit1(JSOP_DUP)) // NEXT ITER RESULT EXCEPTION ITER THROW THROW
8756 : return false;
8757 0 : if (!emit1(JSOP_UNDEFINED)) // NEXT ITER RESULT EXCEPTION ITER THROW THROW UNDEFINED
8758 : return false;
8759 0 : if (!emit1(JSOP_EQ)) // NEXT ITER RESULT EXCEPTION ITER THROW ?EQL
8760 : return false;
8761 :
8762 9 : InternalIfEmitter ifThrowMethodIsNotDefined(this);
8763 0 : if (!ifThrowMethodIsNotDefined.emitThen()) // NEXT ITER RESULT EXCEPTION ITER THROW
8764 : return false;
8765 0 : savedDepthTemp = stackDepth;
8766 9 : if (!emit1(JSOP_POP)) // NEXT ITER RESULT EXCEPTION ITER
8767 : return false;
8768 : // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
8769 : //
8770 : // If the iterator does not have a "throw" method, it calls IteratorClose
8771 : // and then throws a TypeError.
8772 9 : IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
8773 9 : if (!emitIteratorCloseInInnermostScope(iterKind)) // NEXT ITER RESULT EXCEPTION
8774 : return false;
8775 0 : if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
8776 : return false;
8777 9 : stackDepth = savedDepthTemp;
8778 9 : if (!ifThrowMethodIsNotDefined.emitEnd()) // NEXT ITER OLDRESULT EXCEPTION ITER THROW
8779 : return false;
8780 : // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.4.
8781 : // RESULT = ITER.throw(EXCEPTION) // NEXT ITER OLDRESULT EXCEPTION ITER THROW
8782 0 : if (!emit1(JSOP_SWAP)) // NEXT ITER OLDRESULT EXCEPTION THROW ITER
8783 : return false;
8784 9 : if (!emit2(JSOP_PICK, 2)) // NEXT ITER OLDRESULT THROW ITER EXCEPTION
8785 : return false;
8786 9 : if (!emitCall(JSOP_CALL, 1, iter)) // NEXT ITER OLDRESULT RESULT
8787 : return false;
8788 9 : checkTypeSet(JSOP_CALL);
8789 :
8790 9 : if (isAsyncGenerator) {
8791 2 : if (!emitAwaitInInnermostScope()) // NEXT ITER OLDRESULT RESULT
8792 : return false;
8793 : }
8794 :
8795 9 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) // NEXT ITER OLDRESULT RESULT
8796 : return false;
8797 9 : if (!emit1(JSOP_SWAP)) // NEXT ITER RESULT OLDRESULT
8798 : return false;
8799 9 : if (!emit1(JSOP_POP)) // NEXT ITER RESULT
8800 : return false;
8801 0 : MOZ_ASSERT(this->stackDepth == startDepth);
8802 9 : JumpList checkResult;
8803 : // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.ii.
8804 : //
8805 : // Note that there is no GOSUB to the finally block here. If the iterator has a
8806 : // "throw" method, it does not perform IteratorClose.
8807 9 : if (!emitJump(JSOP_GOTO, &checkResult)) // goto checkResult
8808 : return false;
8809 :
8810 0 : if (!tryCatch.emitFinally())
8811 : return false;
8812 :
8813 : // ES 14.4.13, yield * AssignmentExpression, step 5.c
8814 : //
8815 : // Call iterator.return() for receiving a "forced return" completion from
8816 : // the generator.
8817 :
8818 0 : InternalIfEmitter ifGeneratorClosing(this);
8819 9 : if (!emit1(JSOP_ISGENCLOSING)) // NEXT ITER RESULT FTYPE FVALUE CLOSING
8820 : return false;
8821 9 : if (!ifGeneratorClosing.emitThen()) // NEXT ITER RESULT FTYPE FVALUE
8822 : return false;
8823 :
8824 : // Step ii.
8825 : //
8826 : // Get the "return" method.
8827 9 : if (!emitDupAt(3)) // NEXT ITER RESULT FTYPE FVALUE ITER
8828 : return false;
8829 9 : if (!emit1(JSOP_DUP)) // NEXT ITER RESULT FTYPE FVALUE ITER ITER
8830 : return false;
8831 27 : if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) // NEXT ITER RESULT FTYPE FVALUE ITER RET
8832 : return false;
8833 :
8834 : // Step iii.
8835 : //
8836 : // Do nothing if "return" is undefined or null.
8837 0 : InternalIfEmitter ifReturnMethodIsDefined(this);
8838 9 : if (!emitPushNotUndefinedOrNull()) // NEXT ITER RESULT FTYPE FVALUE ITER RET NOT-UNDEF-OR-NULL
8839 : return false;
8840 :
8841 : // Step iv.
8842 : //
8843 : // Call "return" with the argument passed to Generator.prototype.return,
8844 : // which is currently in rval.value.
8845 9 : if (!ifReturnMethodIsDefined.emitThenElse()) // NEXT ITER OLDRESULT FTYPE FVALUE ITER RET
8846 : return false;
8847 9 : if (!emit1(JSOP_SWAP)) // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER
8848 : return false;
8849 9 : if (!emit1(JSOP_GETRVAL)) // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER RVAL
8850 : return false;
8851 27 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER OLDRESULT FTYPE FVALUE RET ITER VALUE
8852 : return false;
8853 9 : if (!emitCall(JSOP_CALL, 1)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
8854 : return false;
8855 9 : checkTypeSet(JSOP_CALL);
8856 :
8857 9 : if (iterKind == IteratorKind::Async) {
8858 0 : if (!emitAwaitInInnermostScope()) // ... FTYPE FVALUE RESULT
8859 : return false;
8860 : }
8861 :
8862 : // Step v.
8863 0 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
8864 : return false;
8865 :
8866 : // Steps vi-viii.
8867 : //
8868 : // Check if the returned object from iterator.return() is done. If not,
8869 : // continuing yielding.
8870 9 : InternalIfEmitter ifReturnDone(this);
8871 0 : if (!emit1(JSOP_DUP)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT RESULT
8872 : return false;
8873 0 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT DONE
8874 : return false;
8875 9 : if (!ifReturnDone.emitThenElse()) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
8876 : return false;
8877 27 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // NEXT ITER OLDRESULT FTYPE FVALUE VALUE
8878 : return false;
8879 :
8880 9 : if (!emitPrepareIteratorResult()) // NEXT ITER OLDRESULT FTYPE FVALUE VALUE RESULT
8881 : return false;
8882 0 : if (!emit1(JSOP_SWAP)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT VALUE
8883 : return false;
8884 0 : if (!emitFinishIteratorResult(true)) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
8885 : return false;
8886 0 : if (!emit1(JSOP_SETRVAL)) // NEXT ITER OLDRESULT FTYPE FVALUE
8887 : return false;
8888 9 : savedDepthTemp = this->stackDepth;
8889 9 : if (!ifReturnDone.emitElse()) // NEXT ITER OLDRESULT FTYPE FVALUE RESULT
8890 : return false;
8891 9 : if (!emit2(JSOP_UNPICK, 3)) // NEXT ITER RESULT OLDRESULT FTYPE FVALUE
8892 : return false;
8893 0 : if (!emitPopN(3)) // NEXT ITER RESULT
8894 : return false;
8895 : {
8896 : // goto tryStart;
8897 9 : JumpList beq;
8898 9 : JumpTarget breakTarget{ -1 };
8899 9 : if (!emitBackwardJump(JSOP_GOTO, tryStart, &beq, &breakTarget)) // NEXT ITER RESULT
8900 0 : return false;
8901 : }
8902 9 : this->stackDepth = savedDepthTemp;
8903 9 : if (!ifReturnDone.emitEnd())
8904 : return false;
8905 :
8906 0 : if (!ifReturnMethodIsDefined.emitElse()) // NEXT ITER RESULT FTYPE FVALUE ITER RET
8907 : return false;
8908 0 : if (!emitPopN(2)) // NEXT ITER RESULT FTYPE FVALUE
8909 : return false;
8910 9 : if (!ifReturnMethodIsDefined.emitEnd())
8911 : return false;
8912 :
8913 9 : if (!ifGeneratorClosing.emitEnd())
8914 : return false;
8915 :
8916 0 : if (!tryCatch.emitEnd())
8917 : return false;
8918 :
8919 : // After the try-catch-finally block: send the received value to the iterator.
8920 : // result = iter.next(received) // NEXT ITER RECEIVED
8921 9 : if (!emit2(JSOP_UNPICK, 2)) // RECEIVED NEXT ITER
8922 : return false;
8923 9 : if (!emit1(JSOP_DUP2)) // RECEIVED NEXT ITER NEXT ITER
8924 : return false;
8925 0 : if (!emit2(JSOP_PICK, 4)) // NEXT ITER NEXT ITER RECEIVED
8926 : return false;
8927 9 : if (!emitCall(JSOP_CALL, 1, iter)) // NEXT ITER RESULT
8928 : return false;
8929 9 : checkTypeSet(JSOP_CALL);
8930 :
8931 9 : if (isAsyncGenerator) {
8932 0 : if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT RESULT
8933 : return false;
8934 : }
8935 :
8936 0 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // NEXT ITER RESULT
8937 : return false;
8938 0 : MOZ_ASSERT(this->stackDepth == startDepth);
8939 :
8940 0 : if (!emitJumpTargetAndPatch(checkResult)) // checkResult:
8941 : return false;
8942 :
8943 : // if (!result.done) goto tryStart; // NEXT ITER RESULT
8944 9 : if (!emit1(JSOP_DUP)) // NEXT ITER RESULT RESULT
8945 : return false;
8946 0 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // NEXT ITER RESULT DONE
8947 : return false;
8948 : // if (!DONE) goto tryStart;
8949 : {
8950 9 : JumpList beq;
8951 9 : JumpTarget breakTarget{ -1 };
8952 0 : if (!emitBackwardJump(JSOP_IFEQ, tryStart, &beq, &breakTarget)) // NEXT ITER RESULT
8953 0 : return false;
8954 : }
8955 :
8956 : // result.value
8957 1 : if (!emit2(JSOP_UNPICK, 2)) // RESULT NEXT ITER
8958 : return false;
8959 1 : if (!emitPopN(2)) // RESULT
8960 : return false;
8961 27 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // VALUE
8962 : return false;
8963 :
8964 0 : MOZ_ASSERT(this->stackDepth == startDepth - 2);
8965 :
8966 : return true;
8967 : }
8968 :
8969 : bool
8970 30549 : BytecodeEmitter::emitStatementList(ParseNode* pn)
8971 : {
8972 30549 : MOZ_ASSERT(pn->isArity(PN_LIST));
8973 107261 : for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
8974 76712 : if (!emitTree(pn2))
8975 : return false;
8976 : }
8977 : return true;
8978 : }
8979 :
8980 : bool
8981 32140 : BytecodeEmitter::emitExpressionStatement(ParseNode* pn)
8982 : {
8983 0 : MOZ_ASSERT(pn->isKind(ParseNodeKind::ExpressionStatement));
8984 :
8985 : /*
8986 : * Top-level or called-from-a-native JS_Execute/EvaluateScript,
8987 : * debugger, and eval frames may need the value of the ultimate
8988 : * expression statement as the script's result, despite the fact
8989 : * that it appears useless to the compiler.
8990 : *
8991 : * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
8992 : * calling JS_Compile* to suppress JSOP_SETRVAL.
8993 : */
8994 0 : bool wantval = false;
8995 0 : bool useful = false;
8996 32140 : if (sc->isFunctionBox())
8997 0 : MOZ_ASSERT(!script->noScriptRval());
8998 : else
8999 8301 : useful = wantval = !script->noScriptRval();
9000 :
9001 : /* Don't eliminate expressions with side effects. */
9002 32140 : ParseNode* expr = pn->pn_kid;
9003 32140 : if (!useful) {
9004 0 : if (!checkSideEffects(expr, &useful))
9005 : return false;
9006 :
9007 : /*
9008 : * Don't eliminate apparently useless expressions if they are labeled
9009 : * expression statements. The startOffset() test catches the case
9010 : * where we are nesting in emitTree for a labeled compound statement.
9011 : */
9012 0 : if (innermostNestableControl &&
9013 39182 : innermostNestableControl->is<LabelControl>() &&
9014 0 : innermostNestableControl->as<LabelControl>().startOffset() >= offset())
9015 : {
9016 0 : useful = true;
9017 : }
9018 : }
9019 :
9020 0 : if (useful) {
9021 31908 : JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
9022 31908 : ValueUsage valueUsage = wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
9023 0 : MOZ_ASSERT_IF(expr->isKind(ParseNodeKind::Assign), expr->isOp(JSOP_NOP));
9024 31908 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
9025 : return false;
9026 0 : if (!emitTree(expr, valueUsage))
9027 : return false;
9028 0 : if (!emit1(op))
9029 : return false;
9030 232 : } else if (pn->isDirectivePrologueMember()) {
9031 : // Don't complain about directive prologue members; just don't emit
9032 : // their code.
9033 : } else {
9034 1 : if (JSAtom* atom = pn->isStringExprStatement()) {
9035 : // Warn if encountering a non-directive prologue member string
9036 : // expression statement, that is inconsistent with the current
9037 : // directive prologue. That is, a script *not* starting with
9038 : // "use strict" should warn for any "use strict" statements seen
9039 : // later in the script, because such statements are misleading.
9040 0 : const char* directive = nullptr;
9041 0 : if (atom == cx->names().useStrict) {
9042 0 : if (!sc->strictScript)
9043 0 : directive = js_useStrict_str;
9044 0 : } else if (atom == cx->names().useAsm) {
9045 0 : if (sc->isFunctionBox()) {
9046 0 : if (IsAsmJSModule(sc->asFunctionBox()->function()))
9047 0 : directive = js_useAsm_str;
9048 : }
9049 : }
9050 :
9051 0 : if (directive) {
9052 0 : if (!reportExtraWarning(expr, JSMSG_CONTRARY_NONDIRECTIVE, directive))
9053 : return false;
9054 : }
9055 : } else {
9056 1 : if (!reportExtraWarning(expr, JSMSG_USELESS_EXPR))
9057 : return false;
9058 : }
9059 : }
9060 :
9061 : return true;
9062 : }
9063 :
9064 : bool
9065 0 : BytecodeEmitter::emitDeleteName(ParseNode* node)
9066 : {
9067 0 : MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteName));
9068 0 : MOZ_ASSERT(node->isArity(PN_UNARY));
9069 :
9070 0 : ParseNode* nameExpr = node->pn_kid;
9071 0 : MOZ_ASSERT(nameExpr->isKind(ParseNodeKind::Name));
9072 :
9073 0 : return emitAtomOp(nameExpr, JSOP_DELNAME);
9074 : }
9075 :
9076 : bool
9077 266 : BytecodeEmitter::emitDeleteProperty(ParseNode* node)
9078 : {
9079 266 : MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteProp));
9080 266 : MOZ_ASSERT(node->isArity(PN_UNARY));
9081 :
9082 266 : ParseNode* propExpr = node->pn_kid;
9083 266 : MOZ_ASSERT(propExpr->isKind(ParseNodeKind::Dot));
9084 :
9085 532 : if (propExpr->as<PropertyAccess>().isSuper()) {
9086 : // Still have to calculate the base, even though we are are going
9087 : // to throw unconditionally, as calculating the base could also
9088 : // throw.
9089 0 : if (!emit1(JSOP_SUPERBASE))
9090 : return false;
9091 :
9092 0 : return emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER);
9093 : }
9094 :
9095 532 : JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
9096 266 : return emitPropOp(propExpr, delOp);
9097 : }
9098 :
9099 : bool
9100 1 : BytecodeEmitter::emitDeleteElement(ParseNode* node)
9101 : {
9102 94 : MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteElem));
9103 0 : MOZ_ASSERT(node->isArity(PN_UNARY));
9104 :
9105 0 : ParseNode* elemExpr = node->pn_kid;
9106 94 : MOZ_ASSERT(elemExpr->isKind(ParseNodeKind::Elem));
9107 :
9108 0 : if (elemExpr->as<PropertyByValue>().isSuper()) {
9109 : // Still have to calculate everything, even though we're gonna throw
9110 : // since it may have side effects
9111 0 : if (!emitTree(elemExpr->pn_right))
9112 : return false;
9113 :
9114 0 : if (!emit1(JSOP_SUPERBASE))
9115 : return false;
9116 0 : if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
9117 : return false;
9118 :
9119 : // Another wrinkle: Balance the stack from the emitter's point of view.
9120 : // Execution will not reach here, as the last bytecode threw.
9121 0 : return emit1(JSOP_POP);
9122 : }
9123 :
9124 0 : JSOp delOp = sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
9125 0 : return emitElemOp(elemExpr, delOp);
9126 : }
9127 :
9128 : bool
9129 0 : BytecodeEmitter::emitDeleteExpression(ParseNode* node)
9130 : {
9131 0 : MOZ_ASSERT(node->isKind(ParseNodeKind::DeleteExpr));
9132 0 : MOZ_ASSERT(node->isArity(PN_UNARY));
9133 :
9134 0 : ParseNode* expression = node->pn_kid;
9135 :
9136 : // If useless, just emit JSOP_TRUE; otherwise convert |delete <expr>| to
9137 : // effectively |<expr>, true|.
9138 0 : bool useful = false;
9139 0 : if (!checkSideEffects(expression, &useful))
9140 : return false;
9141 :
9142 0 : if (useful) {
9143 0 : if (!emitTree(expression))
9144 : return false;
9145 0 : if (!emit1(JSOP_POP))
9146 : return false;
9147 : }
9148 :
9149 0 : return emit1(JSOP_TRUE);
9150 : }
9151 :
9152 : static const char *
9153 434 : SelfHostedCallFunctionName(JSAtom* name, JSContext* cx)
9154 : {
9155 0 : if (name == cx->names().callFunction)
9156 : return "callFunction";
9157 238 : if (name == cx->names().callContentFunction)
9158 : return "callContentFunction";
9159 1 : if (name == cx->names().constructContentFunction)
9160 : return "constructContentFunction";
9161 :
9162 0 : MOZ_CRASH("Unknown self-hosted call function name");
9163 : }
9164 :
9165 : bool
9166 0 : BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
9167 : {
9168 : // Special-casing of callFunction to emit bytecode that directly
9169 : // invokes the callee with the correct |this| object and arguments.
9170 : // callFunction(fun, thisArg, arg0, arg1) thus becomes:
9171 : // - emit lookup for fun
9172 : // - emit lookup for thisArg
9173 : // - emit lookups for arg0, arg1
9174 : //
9175 : // argc is set to the amount of actually emitted args and the
9176 : // emitting of args below is disabled by setting emitArgs to false.
9177 434 : ParseNode* pn2 = pn->pn_head;
9178 0 : const char* errorName = SelfHostedCallFunctionName(pn2->name(), cx);
9179 :
9180 434 : if (pn->pn_count < 3) {
9181 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, "2", "s");
9182 0 : return false;
9183 : }
9184 :
9185 0 : JSOp callOp = pn->getOp();
9186 434 : if (callOp != JSOP_CALL) {
9187 0 : reportError(pn, JSMSG_NOT_CONSTRUCTOR, errorName);
9188 0 : return false;
9189 : }
9190 :
9191 0 : bool constructing = pn2->name() == cx->names().constructContentFunction;
9192 434 : ParseNode* funNode = pn2->pn_next;
9193 434 : if (constructing) {
9194 : callOp = JSOP_NEW;
9195 0 : } else if (funNode->getKind() == ParseNodeKind::Name &&
9196 1056 : funNode->name() == cx->names().std_Function_apply) {
9197 0 : callOp = JSOP_FUNAPPLY;
9198 : }
9199 :
9200 434 : if (!emitTree(funNode))
9201 : return false;
9202 :
9203 : #ifdef DEBUG
9204 868 : if (emitterMode == BytecodeEmitter::SelfHosting &&
9205 1302 : pn2->name() == cx->names().callFunction)
9206 : {
9207 0 : if (!emit1(JSOP_DEBUGCHECKSELFHOSTED))
9208 : return false;
9209 : }
9210 : #endif
9211 :
9212 0 : ParseNode* thisOrNewTarget = funNode->pn_next;
9213 434 : if (constructing) {
9214 : // Save off the new.target value, but here emit a proper |this| for a
9215 : // constructing call.
9216 43 : if (!emit1(JSOP_IS_CONSTRUCTING))
9217 : return false;
9218 : } else {
9219 : // It's |this|, emit it.
9220 391 : if (!emitTree(thisOrNewTarget))
9221 : return false;
9222 : }
9223 :
9224 1312 : for (ParseNode* argpn = thisOrNewTarget->pn_next; argpn; argpn = argpn->pn_next) {
9225 878 : if (!emitTree(argpn))
9226 : return false;
9227 : }
9228 :
9229 0 : if (constructing) {
9230 43 : if (!emitTree(thisOrNewTarget))
9231 : return false;
9232 : }
9233 :
9234 434 : uint32_t argc = pn->pn_count - 3;
9235 0 : if (!emitCall(callOp, argc))
9236 : return false;
9237 :
9238 : checkTypeSet(callOp);
9239 : return true;
9240 : }
9241 :
9242 : bool
9243 0 : BytecodeEmitter::emitSelfHostedResumeGenerator(ParseNode* pn)
9244 : {
9245 : // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'return')
9246 0 : if (pn->pn_count != 4) {
9247 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, "resumeGenerator", "1", "s");
9248 0 : return false;
9249 : }
9250 :
9251 6 : ParseNode* funNode = pn->pn_head; // The resumeGenerator node.
9252 :
9253 6 : ParseNode* genNode = funNode->pn_next;
9254 0 : if (!emitTree(genNode))
9255 : return false;
9256 :
9257 1 : ParseNode* valNode = genNode->pn_next;
9258 1 : if (!emitTree(valNode))
9259 : return false;
9260 :
9261 0 : ParseNode* kindNode = valNode->pn_next;
9262 6 : MOZ_ASSERT(kindNode->isKind(ParseNodeKind::String));
9263 0 : uint16_t operand = GeneratorObject::getResumeKind(cx, kindNode->pn_atom);
9264 0 : MOZ_ASSERT(!kindNode->pn_next);
9265 :
9266 12 : if (!emitCall(JSOP_RESUME, operand))
9267 : return false;
9268 :
9269 6 : return true;
9270 : }
9271 :
9272 : bool
9273 0 : BytecodeEmitter::emitSelfHostedForceInterpreter()
9274 : {
9275 1 : if (!emit1(JSOP_FORCEINTERPRETER))
9276 : return false;
9277 1 : if (!emit1(JSOP_UNDEFINED))
9278 : return false;
9279 1 : return true;
9280 : }
9281 :
9282 : bool
9283 7 : BytecodeEmitter::emitSelfHostedAllowContentIter(ParseNode* pn)
9284 : {
9285 0 : if (pn->pn_count != 2) {
9286 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, "allowContentIter", "1", "");
9287 0 : return false;
9288 : }
9289 :
9290 : // We're just here as a sentinel. Pass the value through directly.
9291 0 : return emitTree(pn->pn_head->pn_next);
9292 : }
9293 :
9294 : bool
9295 82 : BytecodeEmitter::emitSelfHostedDefineDataProperty(ParseNode* pn)
9296 : {
9297 : // Only optimize when 3 arguments are passed (we use 4 to include |this|).
9298 82 : MOZ_ASSERT(pn->pn_count == 4);
9299 :
9300 82 : ParseNode* funNode = pn->pn_head; // The _DefineDataProperty node.
9301 :
9302 0 : ParseNode* objNode = funNode->pn_next;
9303 0 : if (!emitTree(objNode))
9304 : return false;
9305 :
9306 0 : ParseNode* idNode = objNode->pn_next;
9307 82 : if (!emitTree(idNode))
9308 : return false;
9309 :
9310 0 : ParseNode* valNode = idNode->pn_next;
9311 0 : if (!emitTree(valNode))
9312 : return false;
9313 :
9314 : // This will leave the object on the stack instead of pushing |undefined|,
9315 : // but that's fine because the self-hosted code doesn't use the return
9316 : // value.
9317 82 : return emit1(JSOP_INITELEM);
9318 : }
9319 :
9320 : bool
9321 0 : BytecodeEmitter::emitSelfHostedHasOwn(ParseNode* pn)
9322 : {
9323 0 : if (pn->pn_count != 3) {
9324 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, "hasOwn", "2", "");
9325 0 : return false;
9326 : }
9327 :
9328 0 : ParseNode* funNode = pn->pn_head; // The hasOwn node.
9329 :
9330 25 : ParseNode* idNode = funNode->pn_next;
9331 25 : if (!emitTree(idNode))
9332 : return false;
9333 :
9334 25 : ParseNode* objNode = idNode->pn_next;
9335 25 : if (!emitTree(objNode))
9336 : return false;
9337 :
9338 0 : return emit1(JSOP_HASOWN);
9339 : }
9340 :
9341 : bool
9342 1 : BytecodeEmitter::emitSelfHostedGetPropertySuper(ParseNode* pn)
9343 : {
9344 1 : if (pn->pn_count != 4) {
9345 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, "getPropertySuper", "3", "");
9346 0 : return false;
9347 : }
9348 :
9349 1 : ParseNode* funNode = pn->pn_head; // The getPropertySuper node.
9350 :
9351 1 : ParseNode* objNode = funNode->pn_next;
9352 1 : ParseNode* idNode = objNode->pn_next;
9353 1 : ParseNode* receiverNode = idNode->pn_next;
9354 :
9355 1 : if (!emitTree(idNode))
9356 : return false;
9357 :
9358 1 : if (!emitTree(receiverNode))
9359 : return false;
9360 :
9361 1 : if (!emitTree(objNode))
9362 : return false;
9363 :
9364 0 : return emitElemOpBase(JSOP_GETELEM_SUPER);
9365 : }
9366 :
9367 : bool
9368 0 : BytecodeEmitter::isRestParameter(ParseNode* pn)
9369 : {
9370 0 : if (!sc->isFunctionBox())
9371 : return false;
9372 :
9373 0 : FunctionBox* funbox = sc->asFunctionBox();
9374 0 : RootedFunction fun(cx, funbox->function());
9375 101 : if (!funbox->hasRest())
9376 : return false;
9377 :
9378 0 : if (!pn->isKind(ParseNodeKind::Name)) {
9379 3 : if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(ParseNodeKind::Call)) {
9380 1 : ParseNode* pn2 = pn->pn_head;
9381 2 : if (pn2->getKind() == ParseNodeKind::Name &&
9382 0 : pn2->name() == cx->names().allowContentIter)
9383 : {
9384 0 : return isRestParameter(pn2->pn_next);
9385 : }
9386 : }
9387 : return false;
9388 : }
9389 :
9390 35 : JSAtom* name = pn->name();
9391 35 : Maybe<NameLocation> paramLoc = locationOfNameBoundInFunctionScope(name);
9392 1 : if (paramLoc && lookupName(name) == *paramLoc) {
9393 70 : FunctionScope::Data* bindings = funbox->functionScopeBindings();
9394 1 : if (bindings->nonPositionalFormalStart > 0) {
9395 : // |paramName| can be nullptr when the rest destructuring syntax is
9396 : // used: `function f(...[]) {}`.
9397 : JSAtom* paramName =
9398 105 : bindings->trailingNames[bindings->nonPositionalFormalStart - 1].name();
9399 35 : return paramName && name == paramName;
9400 : }
9401 : }
9402 :
9403 : return false;
9404 : }
9405 :
9406 : bool
9407 43274 : BytecodeEmitter::emitCallee(ParseNode* callee, ParseNode* call, bool* callop)
9408 : {
9409 1 : switch (callee->getKind()) {
9410 : case ParseNodeKind::Name:
9411 18362 : if (!emitGetName(callee, *callop))
9412 : return false;
9413 : break;
9414 : case ParseNodeKind::Dot:
9415 33777 : MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
9416 1 : if (callee->as<PropertyAccess>().isSuper()) {
9417 48 : if (!emitSuperPropOp(callee, JSOP_GETPROP_SUPER, /* isCall = */ *callop))
9418 : return false;
9419 : } else {
9420 1 : if (!emitPropOp(callee, *callop ? JSOP_CALLPROP : JSOP_GETPROP))
9421 : return false;
9422 : }
9423 :
9424 : break;
9425 : case ParseNodeKind::Elem:
9426 0 : MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
9427 120 : if (callee->as<PropertyByValue>().isSuper()) {
9428 0 : if (!emitSuperElemOp(callee, JSOP_GETELEM_SUPER, /* isCall = */ *callop))
9429 : return false;
9430 : } else {
9431 60 : if (!emitElemOp(callee, *callop ? JSOP_CALLELEM : JSOP_GETELEM))
9432 : return false;
9433 60 : if (*callop) {
9434 60 : if (!emit1(JSOP_SWAP))
9435 : return false;
9436 : }
9437 : }
9438 :
9439 : break;
9440 : case ParseNodeKind::Function:
9441 : /*
9442 : * Top level lambdas which are immediately invoked should be
9443 : * treated as only running once. Every time they execute we will
9444 : * create new types and scripts for their contents, to increase
9445 : * the quality of type information within them and enable more
9446 : * backend optimizations. Note that this does not depend on the
9447 : * lambda being invoked at most once (it may be named or be
9448 : * accessed via foo.caller indirection), as multiple executions
9449 : * will just cause the inner scripts to be repeatedly cloned.
9450 : */
9451 122 : MOZ_ASSERT(!emittingRunOnceLambda);
9452 0 : if (checkRunOnceContext()) {
9453 0 : emittingRunOnceLambda = true;
9454 28 : if (!emitTree(callee))
9455 : return false;
9456 28 : emittingRunOnceLambda = false;
9457 : } else {
9458 94 : if (!emitTree(callee))
9459 : return false;
9460 : }
9461 0 : *callop = false;
9462 122 : break;
9463 : case ParseNodeKind::SuperBase:
9464 79 : MOZ_ASSERT(call->isKind(ParseNodeKind::SuperCall));
9465 0 : MOZ_ASSERT(parser->astGenerator().isSuperBase(callee));
9466 0 : if (!emit1(JSOP_SUPERFUN))
9467 : return false;
9468 : break;
9469 : default:
9470 0 : if (!emitTree(callee))
9471 : return false;
9472 0 : *callop = false; /* trigger JSOP_UNDEFINED after */
9473 0 : break;
9474 : }
9475 :
9476 : return true;
9477 : }
9478 :
9479 : bool
9480 0 : BytecodeEmitter::emitPipeline(ParseNode* pn)
9481 : {
9482 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
9483 0 : MOZ_ASSERT(pn->pn_count >= 2);
9484 :
9485 0 : if (!emitTree(pn->pn_head))
9486 : return false;
9487 :
9488 0 : ParseNode* callee = pn->pn_head->pn_next;
9489 :
9490 0 : do {
9491 0 : bool callop = true;
9492 0 : if (!emitCallee(callee, pn, &callop))
9493 0 : return false;
9494 :
9495 : // Emit room for |this|
9496 0 : if (!callop) {
9497 0 : if (!emit1(JSOP_UNDEFINED))
9498 : return false;
9499 : }
9500 :
9501 0 : if (!emit2(JSOP_PICK, 2))
9502 : return false;
9503 :
9504 0 : if (!emitCall(JSOP_CALL, 1, pn))
9505 : return false;
9506 :
9507 0 : checkTypeSet(JSOP_CALL);
9508 0 : } while ((callee = callee->pn_next));
9509 :
9510 : return true;
9511 : }
9512 :
9513 : bool
9514 43830 : BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
9515 : {
9516 : bool callop =
9517 46771 : pn->isKind(ParseNodeKind::Call) || pn->isKind(ParseNodeKind::TaggedTemplate);
9518 : /*
9519 : * Emit callable invocation or operator new (constructor call) code.
9520 : * First, emit code for the left operand to evaluate the callable or
9521 : * constructable object expression.
9522 : *
9523 : * For operator new, we emit JSOP_GETPROP instead of JSOP_CALLPROP, etc.
9524 : * This is necessary to interpose the lambda-initialized method read
9525 : * barrier -- see the code in jsinterp.cpp for JSOP_LAMBDA followed by
9526 : * JSOP_{SET,INIT}PROP.
9527 : *
9528 : * Then (or in a call case that has no explicit reference-base
9529 : * object) we emit JSOP_UNDEFINED to produce the undefined |this|
9530 : * value required for calls (which non-strict mode functions
9531 : * will box into the global object).
9532 : */
9533 43830 : uint32_t argc = pn->pn_count - 1;
9534 :
9535 43830 : if (argc >= ARGC_LIMIT) {
9536 0 : reportError(pn, callop ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
9537 0 : return false;
9538 : }
9539 :
9540 0 : ParseNode* pn2 = pn->pn_head;
9541 87660 : bool spread = JOF_OPTYPE(pn->getOp()) == JOF_BYTE;
9542 :
9543 0 : if (pn2->isKind(ParseNodeKind::Name) && emitterMode == BytecodeEmitter::SelfHosting && !spread) {
9544 : // Calls to "forceInterpreter", "callFunction",
9545 : // "callContentFunction", or "resumeGenerator" in self-hosted
9546 : // code generate inline bytecode.
9547 15330 : if (pn2->name() == cx->names().callFunction ||
9548 11495 : pn2->name() == cx->names().callContentFunction ||
9549 0 : pn2->name() == cx->names().constructContentFunction)
9550 : {
9551 434 : return emitSelfHostedCallFunction(pn);
9552 : }
9553 0 : if (pn2->name() == cx->names().resumeGenerator)
9554 6 : return emitSelfHostedResumeGenerator(pn);
9555 8067 : if (pn2->name() == cx->names().forceInterpreter)
9556 0 : return emitSelfHostedForceInterpreter();
9557 0 : if (pn2->name() == cx->names().allowContentIter)
9558 7 : return emitSelfHostedAllowContentIter(pn);
9559 8043 : if (pn2->name() == cx->names().defineDataPropertyIntrinsic && pn->pn_count == 4)
9560 82 : return emitSelfHostedDefineDataProperty(pn);
9561 0 : if (pn2->name() == cx->names().hasOwn)
9562 0 : return emitSelfHostedHasOwn(pn);
9563 0 : if (pn2->name() == cx->names().getPropertySuper)
9564 1 : return emitSelfHostedGetPropertySuper(pn);
9565 : // Fall through
9566 : }
9567 :
9568 43274 : if (!emitCallee(pn2, pn, &callop))
9569 : return false;
9570 :
9571 124114 : bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
9572 0 : pn->getOp() == JSOP_SUPERCALL || pn->getOp() == JSOP_SPREADSUPERCALL;
9573 :
9574 :
9575 : // Emit room for |this|.
9576 43274 : if (!callop) {
9577 3081 : if (isNewOp) {
9578 0 : if (!emit1(JSOP_IS_CONSTRUCTING))
9579 : return false;
9580 : } else {
9581 147 : if (!emit1(JSOP_UNDEFINED))
9582 : return false;
9583 : }
9584 : }
9585 :
9586 : /*
9587 : * Emit code for each argument in order, then emit the JSOP_*CALL or
9588 : * JSOP_NEW bytecode with a two-byte immediate telling how many args
9589 : * were pushed on the operand stack.
9590 : */
9591 43273 : if (!spread) {
9592 0 : for (ParseNode* pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
9593 0 : if (!emitTree(pn3))
9594 : return false;
9595 : }
9596 :
9597 43139 : if (isNewOp) {
9598 2930 : if (pn->isKind(ParseNodeKind::SuperCall)) {
9599 77 : if (!emit1(JSOP_NEWTARGET))
9600 : return false;
9601 : } else {
9602 : // Repush the callee as new.target
9603 2853 : if (!emitDupAt(argc + 1))
9604 : return false;
9605 : }
9606 : }
9607 : } else {
9608 135 : ParseNode* args = pn2->pn_next;
9609 135 : bool emitOptCode = (argc == 1) && isRestParameter(args->pn_kid);
9610 270 : InternalIfEmitter ifNotOptimizable(this);
9611 :
9612 135 : if (emitOptCode) {
9613 : // Emit a preparation code to optimize the spread call with a rest
9614 : // parameter:
9615 : //
9616 : // function f(...args) {
9617 : // g(...args);
9618 : // }
9619 : //
9620 : // If the spread operand is a rest parameter and it's optimizable
9621 : // array, skip spread operation and pass it directly to spread call
9622 : // operation. See the comment in OptimizeSpreadCall in
9623 : // Interpreter.cpp for the optimizable conditons.
9624 :
9625 35 : if (!emitTree(args->pn_kid))
9626 0 : return false;
9627 :
9628 35 : if (!emit1(JSOP_OPTIMIZE_SPREADCALL))
9629 : return false;
9630 :
9631 0 : if (!emit1(JSOP_NOT))
9632 : return false;
9633 :
9634 0 : if (!ifNotOptimizable.emitThen())
9635 : return false;
9636 :
9637 35 : if (!emit1(JSOP_POP))
9638 : return false;
9639 : }
9640 :
9641 135 : if (!emitArray(args, argc))
9642 : return false;
9643 :
9644 135 : if (emitOptCode) {
9645 35 : if (!ifNotOptimizable.emitEnd())
9646 : return false;
9647 : }
9648 :
9649 135 : if (isNewOp) {
9650 0 : if (pn->isKind(ParseNodeKind::SuperCall)) {
9651 0 : if (!emit1(JSOP_NEWTARGET))
9652 : return false;
9653 : } else {
9654 2 : if (!emitDupAt(2))
9655 : return false;
9656 : }
9657 : }
9658 : }
9659 :
9660 0 : if (!spread) {
9661 86278 : if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
9662 18285 : if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
9663 : return false;
9664 : checkTypeSet(JSOP_CALL_IGNORES_RV);
9665 : } else {
9666 0 : if (!emitCall(pn->getOp(), argc, pn))
9667 : return false;
9668 0 : checkTypeSet(pn->getOp());
9669 : }
9670 : } else {
9671 270 : if (!emit1(pn->getOp()))
9672 : return false;
9673 135 : checkTypeSet(pn->getOp());
9674 : }
9675 129804 : if (pn->isOp(JSOP_EVAL) ||
9676 86512 : pn->isOp(JSOP_STRICTEVAL) ||
9677 0 : pn->isOp(JSOP_SPREADEVAL) ||
9678 43256 : pn->isOp(JSOP_STRICTSPREADEVAL))
9679 : {
9680 0 : uint32_t lineNum = parser->errorReporter().lineAt(pn->pn_pos.begin);
9681 18 : if (!emitUint32Operand(JSOP_LINENO, lineNum))
9682 : return false;
9683 : }
9684 :
9685 : return true;
9686 : }
9687 :
9688 : static const JSOp ParseNodeKindToJSOp[] = {
9689 : // JSOP_NOP is for pipeline operator which does not emit its own JSOp
9690 : // but has highest precedence in binary operators
9691 : JSOP_NOP,
9692 : JSOP_OR,
9693 : JSOP_AND,
9694 : JSOP_BITOR,
9695 : JSOP_BITXOR,
9696 : JSOP_BITAND,
9697 : JSOP_STRICTEQ,
9698 : JSOP_EQ,
9699 : JSOP_STRICTNE,
9700 : JSOP_NE,
9701 : JSOP_LT,
9702 : JSOP_LE,
9703 : JSOP_GT,
9704 : JSOP_GE,
9705 : JSOP_INSTANCEOF,
9706 : JSOP_IN,
9707 : JSOP_LSH,
9708 : JSOP_RSH,
9709 : JSOP_URSH,
9710 : JSOP_ADD,
9711 : JSOP_SUB,
9712 : JSOP_MUL,
9713 : JSOP_DIV,
9714 : JSOP_MOD,
9715 : JSOP_POW
9716 : };
9717 :
9718 : static inline JSOp
9719 0 : BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk)
9720 : {
9721 11850 : MOZ_ASSERT(pnk >= ParseNodeKind::BinOpFirst);
9722 11850 : MOZ_ASSERT(pnk <= ParseNodeKind::BinOpLast);
9723 0 : return ParseNodeKindToJSOp[size_t(pnk) - size_t(ParseNodeKind::BinOpFirst)];
9724 : }
9725 :
9726 : bool
9727 0 : BytecodeEmitter::emitRightAssociative(ParseNode* pn)
9728 : {
9729 : // ** is the only right-associative operator.
9730 0 : MOZ_ASSERT(pn->isKind(ParseNodeKind::Pow));
9731 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
9732 :
9733 : // Right-associative operator chain.
9734 0 : for (ParseNode* subexpr = pn->pn_head; subexpr; subexpr = subexpr->pn_next) {
9735 0 : if (!emitTree(subexpr))
9736 : return false;
9737 : }
9738 0 : for (uint32_t i = 0; i < pn->pn_count - 1; i++) {
9739 0 : if (!emit1(JSOP_POW))
9740 : return false;
9741 : }
9742 : return true;
9743 : }
9744 :
9745 : bool
9746 0 : BytecodeEmitter::emitLeftAssociative(ParseNode* pn)
9747 : {
9748 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
9749 :
9750 : // Left-associative operator chain.
9751 11850 : if (!emitTree(pn->pn_head))
9752 : return false;
9753 11850 : JSOp op = BinaryOpParseNodeKindToJSOp(pn->getKind());
9754 11850 : ParseNode* nextExpr = pn->pn_head->pn_next;
9755 13180 : do {
9756 13180 : if (!emitTree(nextExpr))
9757 : return false;
9758 13180 : if (!emit1(op))
9759 : return false;
9760 13180 : } while ((nextExpr = nextExpr->pn_next));
9761 : return true;
9762 : }
9763 :
9764 : bool
9765 4454 : BytecodeEmitter::emitLogical(ParseNode* pn)
9766 : {
9767 4454 : MOZ_ASSERT(pn->isArity(PN_LIST));
9768 6962 : MOZ_ASSERT(pn->isKind(ParseNodeKind::Or) || pn->isKind(ParseNodeKind::And));
9769 :
9770 : /*
9771 : * JSOP_OR converts the operand on the stack to boolean, leaves the original
9772 : * value on the stack and jumps if true; otherwise it falls into the next
9773 : * bytecode, which pops the left operand and then evaluates the right operand.
9774 : * The jump goes around the right operand evaluation.
9775 : *
9776 : * JSOP_AND converts the operand on the stack to boolean and jumps if false;
9777 : * otherwise it falls into the right operand's bytecode.
9778 : */
9779 :
9780 0 : TDZCheckCache tdzCache(this);
9781 :
9782 : /* Left-associative operator chain: avoid too much recursion. */
9783 0 : ParseNode* pn2 = pn->pn_head;
9784 4454 : if (!emitTree(pn2))
9785 : return false;
9786 0 : JSOp op = pn->isKind(ParseNodeKind::Or) ? JSOP_OR : JSOP_AND;
9787 4454 : JumpList jump;
9788 4454 : if (!emitJump(op, &jump))
9789 : return false;
9790 0 : if (!emit1(JSOP_POP))
9791 : return false;
9792 :
9793 : /* Emit nodes between the head and the tail. */
9794 0 : while ((pn2 = pn2->pn_next)->pn_next) {
9795 946 : if (!emitTree(pn2))
9796 : return false;
9797 0 : if (!emitJump(op, &jump))
9798 : return false;
9799 946 : if (!emit1(JSOP_POP))
9800 : return false;
9801 : }
9802 4454 : if (!emitTree(pn2))
9803 : return false;
9804 :
9805 4454 : if (!emitJumpTargetAndPatch(jump))
9806 : return false;
9807 0 : return true;
9808 : }
9809 :
9810 : bool
9811 8 : BytecodeEmitter::emitSequenceExpr(ParseNode* pn,
9812 : ValueUsage valueUsage /* = ValueUsage::WantValue */)
9813 : {
9814 19 : for (ParseNode* child = pn->pn_head; ; child = child->pn_next) {
9815 30 : if (!updateSourceCoordNotes(child->pn_pos.begin))
9816 : return false;
9817 19 : if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage))
9818 : return false;
9819 19 : if (!child->pn_next)
9820 : break;
9821 0 : if (!emit1(JSOP_POP))
9822 : return false;
9823 : }
9824 : return true;
9825 : }
9826 :
9827 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
9828 : // the comment on emitSwitch.
9829 : MOZ_NEVER_INLINE bool
9830 0 : BytecodeEmitter::emitIncOrDec(ParseNode* pn)
9831 : {
9832 648 : switch (pn->pn_kid->getKind()) {
9833 : case ParseNodeKind::Dot:
9834 116 : return emitPropIncDec(pn);
9835 : case ParseNodeKind::Elem:
9836 0 : return emitElemIncDec(pn);
9837 : case ParseNodeKind::Call:
9838 0 : return emitCallIncDec(pn);
9839 : default:
9840 527 : return emitNameIncDec(pn);
9841 : }
9842 : }
9843 :
9844 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
9845 : // the comment on emitSwitch.
9846 : MOZ_NEVER_INLINE bool
9847 0 : BytecodeEmitter::emitLabeledStatement(const LabeledStatement* pn)
9848 : {
9849 : /*
9850 : * Emit a JSOP_LABEL instruction. The argument is the offset to the statement
9851 : * following the labeled statement.
9852 : */
9853 : uint32_t index;
9854 0 : if (!makeAtomIndex(pn->label(), &index))
9855 : return false;
9856 :
9857 0 : JumpList top;
9858 0 : if (!emitJump(JSOP_LABEL, &top))
9859 : return false;
9860 :
9861 : /* Emit code for the labeled statement. */
9862 0 : LabelControl controlInfo(this, pn->label(), offset());
9863 :
9864 0 : if (!emitTree(pn->statement()))
9865 : return false;
9866 :
9867 : /* Patch the JSOP_LABEL offset. */
9868 0 : JumpTarget brk{ lastNonJumpTargetOffset() };
9869 0 : patchJumpsToTarget(top, brk);
9870 :
9871 0 : if (!controlInfo.patchBreaks(this))
9872 : return false;
9873 :
9874 0 : return true;
9875 : }
9876 :
9877 : bool
9878 0 : BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional,
9879 : ValueUsage valueUsage /* = ValueUsage::WantValue */)
9880 : {
9881 : /* Emit the condition, then branch if false to the else part. */
9882 971 : if (!emitTree(&conditional.condition()))
9883 : return false;
9884 :
9885 971 : IfEmitter ifThenElse(this);
9886 971 : if (!ifThenElse.emitCond())
9887 : return false;
9888 :
9889 971 : if (!emitTree(&conditional.thenExpression(), valueUsage))
9890 : return false;
9891 :
9892 0 : if (!ifThenElse.emitElse())
9893 : return false;
9894 :
9895 971 : if (!emitTree(&conditional.elseExpression(), valueUsage))
9896 : return false;
9897 :
9898 971 : if (!ifThenElse.emitEnd())
9899 : return false;
9900 0 : MOZ_ASSERT(ifThenElse.pushed() == 1);
9901 :
9902 : return true;
9903 : }
9904 :
9905 : bool
9906 4855 : BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, PropListType type)
9907 : {
9908 0 : for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) {
9909 16285 : if (!updateSourceCoordNotes(propdef->pn_pos.begin))
9910 : return false;
9911 :
9912 : // Handle __proto__: v specially because *only* this form, and no other
9913 : // involving "__proto__", performs [[Prototype]] mutation.
9914 16285 : if (propdef->isKind(ParseNodeKind::MutateProto)) {
9915 16 : MOZ_ASSERT(type == ObjectLiteral);
9916 16 : if (!emitTree(propdef->pn_kid))
9917 : return false;
9918 0 : objp.set(nullptr);
9919 16 : if (!emit1(JSOP_MUTATEPROTO))
9920 : return false;
9921 : continue;
9922 : }
9923 :
9924 16269 : if (propdef->isKind(ParseNodeKind::Spread)) {
9925 13 : MOZ_ASSERT(type == ObjectLiteral);
9926 :
9927 0 : if (!emit1(JSOP_DUP))
9928 : return false;
9929 :
9930 0 : if (!emitTree(propdef->pn_kid))
9931 : return false;
9932 :
9933 0 : if (!emitCopyDataProperties(CopyOption::Unfiltered))
9934 : return false;
9935 :
9936 13 : objp.set(nullptr);
9937 0 : continue;
9938 : }
9939 :
9940 0 : bool extraPop = false;
9941 16256 : if (type == ClassBody && propdef->as<ClassMethod>().isStatic()) {
9942 57 : extraPop = true;
9943 0 : if (!emit1(JSOP_DUP2))
9944 : return false;
9945 57 : if (!emit1(JSOP_POP))
9946 : return false;
9947 : }
9948 :
9949 : /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
9950 0 : ParseNode* key = propdef->pn_left;
9951 0 : bool isIndex = false;
9952 16256 : if (key->isKind(ParseNodeKind::Number)) {
9953 0 : if (!emitNumberOp(key->pn_dval))
9954 : return false;
9955 : isIndex = true;
9956 0 : } else if (key->isKind(ParseNodeKind::ObjectPropertyName) ||
9957 0 : key->isKind(ParseNodeKind::String))
9958 : {
9959 : // EmitClass took care of constructor already.
9960 19452 : if (type == ClassBody && key->pn_atom == cx->names().constructor &&
9961 1 : !propdef->as<ClassMethod>().isStatic())
9962 : {
9963 : continue;
9964 : }
9965 : } else {
9966 58 : if (!emitComputedPropertyName(key))
9967 : return false;
9968 : isIndex = true;
9969 : }
9970 :
9971 : /* Emit code for the property initializer. */
9972 1 : if (!emitTree(propdef->pn_right))
9973 : return false;
9974 :
9975 32184 : JSOp op = propdef->getOp();
9976 16092 : MOZ_ASSERT(op == JSOP_INITPROP ||
9977 : op == JSOP_INITPROP_GETTER ||
9978 : op == JSOP_INITPROP_SETTER);
9979 :
9980 16092 : FunctionPrefixKind prefixKind = op == JSOP_INITPROP_GETTER ? FunctionPrefixKind::Get
9981 15167 : : op == JSOP_INITPROP_SETTER ? FunctionPrefixKind::Set
9982 16092 : : FunctionPrefixKind::None;
9983 :
9984 16092 : if (op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER)
9985 1023 : objp.set(nullptr);
9986 :
9987 39373 : if (propdef->pn_right->isKind(ParseNodeKind::Function) &&
9988 14378 : propdef->pn_right->pn_funbox->needsHomeObject())
9989 : {
9990 162 : MOZ_ASSERT(propdef->pn_right->pn_funbox->function()->allowSuperProperty());
9991 0 : bool isAsync = propdef->pn_right->pn_funbox->isAsync();
9992 0 : if (isAsync) {
9993 5 : if (!emit1(JSOP_SWAP))
9994 : return false;
9995 : }
9996 54 : if (!emit2(JSOP_INITHOMEOBJECT, isIndex + isAsync))
9997 : return false;
9998 54 : if (isAsync) {
9999 0 : if (!emit1(JSOP_POP))
10000 : return false;
10001 : }
10002 : }
10003 :
10004 : // Class methods are not enumerable.
10005 16092 : if (type == ClassBody) {
10006 1387 : switch (op) {
10007 : case JSOP_INITPROP: op = JSOP_INITHIDDENPROP; break;
10008 249 : case JSOP_INITPROP_GETTER: op = JSOP_INITHIDDENPROP_GETTER; break;
10009 22 : case JSOP_INITPROP_SETTER: op = JSOP_INITHIDDENPROP_SETTER; break;
10010 0 : default: MOZ_CRASH("Invalid op");
10011 : }
10012 : }
10013 :
10014 16092 : if (isIndex) {
10015 68 : objp.set(nullptr);
10016 0 : switch (op) {
10017 : case JSOP_INITPROP: op = JSOP_INITELEM; break;
10018 1 : case JSOP_INITHIDDENPROP: op = JSOP_INITHIDDENELEM; break;
10019 0 : case JSOP_INITPROP_GETTER: op = JSOP_INITELEM_GETTER; break;
10020 0 : case JSOP_INITHIDDENPROP_GETTER: op = JSOP_INITHIDDENELEM_GETTER; break;
10021 0 : case JSOP_INITPROP_SETTER: op = JSOP_INITELEM_SETTER; break;
10022 0 : case JSOP_INITHIDDENPROP_SETTER: op = JSOP_INITHIDDENELEM_SETTER; break;
10023 0 : default: MOZ_CRASH("Invalid op");
10024 : }
10025 136 : if (propdef->pn_right->isDirectRHSAnonFunction()) {
10026 10 : if (!emitDupAt(1))
10027 : return false;
10028 10 : if (!emit2(JSOP_SETFUNNAME, uint8_t(prefixKind)))
10029 : return false;
10030 : }
10031 68 : if (!emit1(op))
10032 : return false;
10033 : } else {
10034 16421 : MOZ_ASSERT(key->isKind(ParseNodeKind::ObjectPropertyName) ||
10035 : key->isKind(ParseNodeKind::String));
10036 :
10037 : uint32_t index;
10038 16024 : if (!makeAtomIndex(key->pn_atom, &index))
10039 0 : return false;
10040 :
10041 16023 : if (objp) {
10042 0 : MOZ_ASSERT(type == ObjectLiteral);
10043 0 : MOZ_ASSERT(!IsHiddenInitOp(op));
10044 0 : MOZ_ASSERT(!objp->inDictionaryMode());
10045 22892 : Rooted<jsid> id(cx, AtomToId(key->pn_atom));
10046 0 : if (!NativeDefineDataProperty(cx, objp, id, UndefinedHandleValue,
10047 : JSPROP_ENUMERATE))
10048 : {
10049 0 : return false;
10050 : }
10051 22892 : if (objp->inDictionaryMode())
10052 0 : objp.set(nullptr);
10053 : }
10054 :
10055 0 : if (propdef->pn_right->isDirectRHSAnonFunction()) {
10056 480 : MOZ_ASSERT(prefixKind == FunctionPrefixKind::None);
10057 :
10058 960 : RootedAtom keyName(cx, key->pn_atom);
10059 480 : if (!setOrEmitSetFunName(propdef->pn_right, keyName))
10060 0 : return false;
10061 : }
10062 16023 : if (!emitIndex32(op, index))
10063 : return false;
10064 : }
10065 :
10066 0 : if (extraPop) {
10067 0 : if (!emit1(JSOP_POP))
10068 : return false;
10069 : }
10070 : }
10071 : return true;
10072 : }
10073 :
10074 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
10075 : // the comment on emitSwitch.
10076 : MOZ_NEVER_INLINE bool
10077 0 : BytecodeEmitter::emitObject(ParseNode* pn)
10078 : {
10079 4660 : if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && checkSingletonContext())
10080 17 : return emitSingletonInitialiser(pn);
10081 :
10082 : /*
10083 : * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
10084 : * a new object and defining (in source order) each property on the object
10085 : * (or mutating the object's [[Prototype]], in the case of __proto__).
10086 : */
10087 4643 : ptrdiff_t offset = this->offset();
10088 4643 : if (!emitNewInit(JSProto_Object))
10089 : return false;
10090 :
10091 : // Try to construct the shape of the object as we go, so we can emit a
10092 : // JSOP_NEWOBJECT with the final shape instead.
10093 : // In the case of computed property names and indices, we cannot fix the
10094 : // shape at bytecode compile time. When the shape cannot be determined,
10095 : // |obj| is nulled out.
10096 :
10097 : // No need to do any guessing for the object kind, since we know the upper
10098 : // bound of how many properties we plan to have.
10099 9286 : gc::AllocKind kind = gc::GetGCObjectKind(pn->pn_count);
10100 9286 : RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
10101 4643 : if (!obj)
10102 : return false;
10103 :
10104 4643 : if (!emitPropertyList(pn, &obj, ObjectLiteral))
10105 : return false;
10106 :
10107 0 : if (obj) {
10108 : // The object survived and has a predictable shape: update the original
10109 : // bytecode.
10110 4380 : if (!replaceNewInitWithNewObject(obj, offset))
10111 : return false;
10112 : }
10113 :
10114 : return true;
10115 : }
10116 :
10117 : bool
10118 0 : BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset)
10119 : {
10120 4380 : ObjectBox* objbox = parser->newObjectBox(obj);
10121 4380 : if (!objbox)
10122 : return false;
10123 :
10124 : static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
10125 : "newinit and newobject must have equal length to edit in-place");
10126 :
10127 4380 : uint32_t index = objectList.add(objbox);
10128 4380 : jsbytecode* code = this->code(offset);
10129 :
10130 4380 : MOZ_ASSERT(code[0] == JSOP_NEWINIT);
10131 0 : code[0] = JSOP_NEWOBJECT;
10132 0 : SET_UINT32(code, index);
10133 :
10134 0 : return true;
10135 : }
10136 :
10137 : bool
10138 2700 : BytecodeEmitter::emitArrayLiteral(ParseNode* pn)
10139 : {
10140 0 : if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head) {
10141 0 : if (checkSingletonContext()) {
10142 : // Bake in the object entirely if it will only be created once.
10143 26 : return emitSingletonInitialiser(pn);
10144 : }
10145 :
10146 : // If the array consists entirely of primitive values, make a
10147 : // template object with copy on write elements that can be reused
10148 : // every time the initializer executes. Don't do this if the array is
10149 : // small: copying the elements lazily is not worth it in that case.
10150 : static const size_t MinElementsForCopyOnWrite = 5;
10151 0 : if (emitterMode != BytecodeEmitter::SelfHosting &&
10152 1030 : pn->pn_count >= MinElementsForCopyOnWrite)
10153 : {
10154 259 : RootedValue value(cx);
10155 125 : if (!pn->getConstantValue(cx, ParseNode::ForCopyOnWriteArray, &value))
10156 116 : return false;
10157 125 : if (!value.isMagic(JS_GENERIC_MAGIC)) {
10158 : // Note: the group of the template object might not yet reflect
10159 : // that the object has copy on write elements. When the
10160 : // interpreter or JIT compiler fetches the template, it should
10161 : // use ObjectGroup::getOrFixupCopyOnWriteObject to make sure the
10162 : // group for the template is accurate. We don't do this here as we
10163 : // want to use ObjectGroup::allocationSiteGroup, which requires a
10164 : // finished script.
10165 116 : JSObject* obj = &value.toObject();
10166 0 : MOZ_ASSERT(obj->is<ArrayObject>() &&
10167 : obj->as<ArrayObject>().denseElementsAreCopyOnWrite());
10168 :
10169 116 : ObjectBox* objbox = parser->newObjectBox(obj);
10170 0 : if (!objbox)
10171 : return false;
10172 :
10173 232 : return emitObjectOp(objbox, JSOP_NEWARRAY_COPYONWRITE);
10174 : }
10175 : }
10176 : }
10177 :
10178 0 : return emitArray(pn->pn_head, pn->pn_count);
10179 : }
10180 :
10181 : bool
10182 2693 : BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
10183 : {
10184 :
10185 : /*
10186 : * Emit code for [a, b, c] that is equivalent to constructing a new
10187 : * array and in source order evaluating each element value and adding
10188 : * it to the array, without invoking latent setters. We use the
10189 : * JSOP_NEWINIT and JSOP_INITELEM_ARRAY bytecodes to ignore setters and
10190 : * to avoid dup'ing and popping the array as each element is added, as
10191 : * JSOP_SETELEM/JSOP_SETPROP would do.
10192 : */
10193 :
10194 0 : uint32_t nspread = 0;
10195 0 : for (ParseNode* elt = pn; elt; elt = elt->pn_next) {
10196 1 : if (elt->isKind(ParseNodeKind::Spread))
10197 242 : nspread++;
10198 : }
10199 :
10200 : // Array literal's length is limited to NELEMENTS_LIMIT in parser.
10201 : static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT <= INT32_MAX,
10202 : "array literals' maximum length must not exceed limits "
10203 : "required by BaselineCompiler::emit_JSOP_NEWARRAY, "
10204 : "BaselineCompiler::emit_JSOP_INITELEM_ARRAY, "
10205 : "and DoSetElemFallback's handling of JSOP_INITELEM_ARRAY");
10206 2693 : MOZ_ASSERT(count >= nspread);
10207 0 : MOZ_ASSERT(count <= NativeObject::MAX_DENSE_ELEMENTS_COUNT,
10208 : "the parser must throw an error if the array exceeds maximum "
10209 : "length");
10210 :
10211 : // For arrays with spread, this is a very pessimistic allocation, the
10212 : // minimum possible final size.
10213 0 : if (!emitUint32Operand(JSOP_NEWARRAY, count - nspread)) // ARRAY
10214 : return false;
10215 :
10216 : ParseNode* pn2 = pn;
10217 : uint32_t index;
10218 : bool afterSpread = false;
10219 12207 : for (index = 0; pn2; index++, pn2 = pn2->pn_next) {
10220 9483 : if (!afterSpread && pn2->isKind(ParseNodeKind::Spread)) {
10221 0 : afterSpread = true;
10222 224 : if (!emitNumberOp(index)) // ARRAY INDEX
10223 : return false;
10224 : }
10225 0 : if (!updateSourceCoordNotes(pn2->pn_pos.begin))
10226 : return false;
10227 :
10228 4757 : bool allowSelfHostedIter = false;
10229 0 : if (pn2->isKind(ParseNodeKind::Elision)) {
10230 0 : if (!emit1(JSOP_HOLE))
10231 : return false;
10232 : } else {
10233 : ParseNode* expr;
10234 0 : if (pn2->isKind(ParseNodeKind::Spread)) {
10235 0 : expr = pn2->pn_kid;
10236 :
10237 485 : if (emitterMode == BytecodeEmitter::SelfHosting &&
10238 244 : expr->isKind(ParseNodeKind::Call) &&
10239 0 : expr->pn_head->name() == cx->names().allowContentIter)
10240 : {
10241 1 : allowSelfHostedIter = true;
10242 : }
10243 : } else {
10244 : expr = pn2;
10245 : }
10246 0 : if (!emitTree(expr)) // ARRAY INDEX? VALUE
10247 : return false;
10248 : }
10249 0 : if (pn2->isKind(ParseNodeKind::Spread)) {
10250 0 : if (!emitIterator()) // ARRAY INDEX NEXT ITER
10251 : return false;
10252 242 : if (!emit2(JSOP_PICK, 3)) // INDEX NEXT ITER ARRAY
10253 : return false;
10254 242 : if (!emit2(JSOP_PICK, 3)) // NEXT ITER ARRAY INDEX
10255 : return false;
10256 242 : if (!emitSpread(allowSelfHostedIter)) // ARRAY INDEX
10257 : return false;
10258 4515 : } else if (afterSpread) {
10259 0 : if (!emit1(JSOP_INITELEM_INC))
10260 : return false;
10261 : } else {
10262 0 : if (!emitUint32Operand(JSOP_INITELEM_ARRAY, index))
10263 : return false;
10264 : }
10265 : }
10266 0 : MOZ_ASSERT(index == count);
10267 2693 : if (afterSpread) {
10268 224 : if (!emit1(JSOP_POP)) // ARRAY
10269 : return false;
10270 : }
10271 : return true;
10272 : }
10273 :
10274 : static inline JSOp
10275 6481 : UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk)
10276 : {
10277 0 : switch (pnk) {
10278 : case ParseNodeKind::Throw: return JSOP_THROW;
10279 0 : case ParseNodeKind::Void: return JSOP_VOID;
10280 5055 : case ParseNodeKind::Not: return JSOP_NOT;
10281 0 : case ParseNodeKind::BitNot: return JSOP_BITNOT;
10282 1 : case ParseNodeKind::Pos: return JSOP_POS;
10283 0 : case ParseNodeKind::Neg: return JSOP_NEG;
10284 0 : default: MOZ_CRASH("unexpected unary op");
10285 : }
10286 : }
10287 :
10288 : bool
10289 0 : BytecodeEmitter::emitUnary(ParseNode* pn)
10290 : {
10291 6481 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
10292 : return false;
10293 6481 : if (!emitTree(pn->pn_kid))
10294 : return false;
10295 6481 : return emit1(UnaryOpParseNodeKindToJSOp(pn->getKind()));
10296 : }
10297 :
10298 : bool
10299 713 : BytecodeEmitter::emitTypeof(ParseNode* node, JSOp op)
10300 : {
10301 713 : MOZ_ASSERT(op == JSOP_TYPEOF || op == JSOP_TYPEOFEXPR);
10302 :
10303 713 : if (!updateSourceCoordNotes(node->pn_pos.begin))
10304 : return false;
10305 :
10306 713 : if (!emitTree(node->pn_kid))
10307 : return false;
10308 :
10309 0 : return emit1(op);
10310 : }
10311 :
10312 : bool
10313 0 : BytecodeEmitter::emitFunctionFormalParametersAndBody(ParseNode *pn)
10314 : {
10315 0 : MOZ_ASSERT(pn->isKind(ParseNodeKind::ParamsBody));
10316 :
10317 0 : ParseNode* funBody = pn->last();
10318 13041 : FunctionBox* funbox = sc->asFunctionBox();
10319 :
10320 0 : TDZCheckCache tdzCache(this);
10321 :
10322 13041 : if (funbox->hasParameterExprs) {
10323 0 : EmitterScope funEmitterScope(this);
10324 471 : if (!funEmitterScope.enterFunction(this, funbox))
10325 : return false;
10326 :
10327 0 : if (!emitInitializeFunctionSpecialNames())
10328 : return false;
10329 :
10330 0 : if (!emitFunctionFormalParameters(pn))
10331 : return false;
10332 :
10333 : {
10334 0 : Maybe<EmitterScope> extraVarEmitterScope;
10335 :
10336 0 : if (funbox->hasExtraBodyVarScope()) {
10337 0 : extraVarEmitterScope.emplace(this);
10338 0 : if (!extraVarEmitterScope->enterFunctionExtraBodyVar(this, funbox))
10339 0 : return false;
10340 :
10341 : // After emitting expressions for all parameters, copy over any
10342 : // formal parameters which have been redeclared as vars. For
10343 : // example, in the following, the var y in the body scope is 42:
10344 : //
10345 : // function f(x, y = 42) { var y; }
10346 : //
10347 177 : RootedAtom name(cx);
10348 144 : if (funbox->extraVarScopeBindings() && funbox->functionScopeBindings()) {
10349 286 : for (BindingIter bi(*funbox->functionScopeBindings(), true); bi; bi++) {
10350 182 : name = bi.name();
10351 :
10352 : // There may not be a var binding of the same name.
10353 455 : if (!locationOfNameBoundInScope(name, extraVarEmitterScope.ptr()))
10354 0 : continue;
10355 :
10356 : // The '.this' and '.generator' function special
10357 : // bindings should never appear in the extra var
10358 : // scope. 'arguments', however, may.
10359 0 : MOZ_ASSERT(name != cx->names().dotThis &&
10360 : name != cx->names().dotGenerator);
10361 :
10362 0 : NameLocation paramLoc = *locationOfNameBoundInScope(name, &funEmitterScope);
10363 : auto emitRhs = [&name, ¶mLoc](BytecodeEmitter* bce,
10364 : const NameLocation&, bool)
10365 0 : {
10366 0 : return bce->emitGetNameAtLocation(name, paramLoc);
10367 0 : };
10368 :
10369 0 : if (!emitInitializeName(name, emitRhs))
10370 0 : return false;
10371 0 : if (!emit1(JSOP_POP))
10372 : return false;
10373 : }
10374 : }
10375 : }
10376 :
10377 471 : if (!emitFunctionBody(funBody))
10378 : return false;
10379 :
10380 0 : if (extraVarEmitterScope && !extraVarEmitterScope->leave(this))
10381 : return false;
10382 : }
10383 :
10384 471 : return funEmitterScope.leave(this);
10385 : }
10386 :
10387 : // No parameter expressions. Enter the function body scope and emit
10388 : // everything.
10389 : //
10390 : // One caveat is that Debugger considers ops in the prologue to be
10391 : // unreachable (i.e. cannot set a breakpoint on it). If there are no
10392 : // parameter exprs, any unobservable environment ops (like pushing the
10393 : // call object, setting '.this', etc) need to go in the prologue, else it
10394 : // messes up breakpoint tests.
10395 0 : EmitterScope emitterScope(this);
10396 :
10397 12570 : switchToPrologue();
10398 12570 : if (!emitterScope.enterFunction(this, funbox))
10399 : return false;
10400 :
10401 12570 : if (!emitInitializeFunctionSpecialNames())
10402 : return false;
10403 12570 : switchToMain();
10404 :
10405 0 : if (!emitFunctionFormalParameters(pn))
10406 : return false;
10407 :
10408 12570 : if (!emitFunctionBody(funBody))
10409 : return false;
10410 :
10411 0 : return emitterScope.leave(this);
10412 : }
10413 :
10414 : bool
10415 13041 : BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
10416 : {
10417 13041 : ParseNode* funBody = pn->last();
10418 13041 : FunctionBox* funbox = sc->asFunctionBox();
10419 0 : EmitterScope* funScope = innermostEmitterScope();
10420 :
10421 13041 : bool hasParameterExprs = funbox->hasParameterExprs;
10422 0 : bool hasRest = funbox->hasRest();
10423 :
10424 13041 : uint16_t argSlot = 0;
10425 0 : for (ParseNode* arg = pn->pn_head; arg != funBody; arg = arg->pn_next, argSlot++) {
10426 13507 : ParseNode* bindingElement = arg;
10427 13507 : ParseNode* initializer = nullptr;
10428 0 : if (arg->isKind(ParseNodeKind::Assign)) {
10429 543 : bindingElement = arg->pn_left;
10430 543 : initializer = arg->pn_right;
10431 : }
10432 :
10433 : // Left-hand sides are either simple names or destructuring patterns.
10434 0 : MOZ_ASSERT(bindingElement->isKind(ParseNodeKind::Name) ||
10435 : bindingElement->isKind(ParseNodeKind::Array) ||
10436 : bindingElement->isKind(ParseNodeKind::Object));
10437 :
10438 : // The rest parameter doesn't have an initializer.
10439 13507 : bool isRest = hasRest && arg->pn_next == funBody;
10440 0 : MOZ_ASSERT_IF(isRest, !initializer);
10441 :
10442 13507 : bool isDestructuring = !bindingElement->isKind(ParseNodeKind::Name);
10443 :
10444 : // ES 14.1.19 says if BindingElement contains an expression in the
10445 : // production FormalParameter : BindingElement, it is evaluated in a
10446 : // new var environment. This is needed to prevent vars from escaping
10447 : // direct eval in parameter expressions.
10448 0 : Maybe<EmitterScope> paramExprVarScope;
10449 13507 : if (funbox->hasDirectEvalInParameterExpr && (isDestructuring || initializer)) {
10450 0 : paramExprVarScope.emplace(this);
10451 0 : if (!paramExprVarScope->enterParameterExpressionVar(this))
10452 0 : return false;
10453 : }
10454 :
10455 : // First push the RHS if there is a default expression or if it is
10456 : // rest.
10457 :
10458 13507 : if (initializer) {
10459 : // If we have an initializer, emit the initializer and assign it
10460 : // to the argument slot. TDZ is taken care of afterwards.
10461 543 : MOZ_ASSERT(hasParameterExprs);
10462 543 : if (!emitArgOp(JSOP_GETARG, argSlot))
10463 0 : return false;
10464 543 : if (!emit1(JSOP_DUP))
10465 : return false;
10466 543 : if (!emit1(JSOP_UNDEFINED))
10467 : return false;
10468 0 : if (!emit1(JSOP_STRICTEQ))
10469 : return false;
10470 : // Emit source note to enable Ion compilation.
10471 543 : if (!newSrcNote(SRC_IF))
10472 : return false;
10473 543 : JumpList jump;
10474 543 : if (!emitJump(JSOP_IFEQ, &jump))
10475 : return false;
10476 0 : if (!emit1(JSOP_POP))
10477 : return false;
10478 0 : if (!emitInitializerInBranch(initializer, bindingElement))
10479 : return false;
10480 0 : if (!emitJumpTargetAndPatch(jump))
10481 : return false;
10482 12964 : } else if (isRest) {
10483 151 : if (!emit1(JSOP_REST))
10484 : return false;
10485 : checkTypeSet(JSOP_REST);
10486 : }
10487 :
10488 : // Initialize the parameter name.
10489 :
10490 13507 : if (isDestructuring) {
10491 : // If we had an initializer or the rest parameter, the value is
10492 : // already on the stack.
10493 108 : if (!initializer && !isRest && !emitArgOp(JSOP_GETARG, argSlot))
10494 : return false;
10495 :
10496 : // If there's an parameter expression var scope, the destructuring
10497 : // declaration needs to initialize the name in the function scope,
10498 : // which is not the innermost scope.
10499 108 : if (!emitDestructuringOps(bindingElement,
10500 : paramExprVarScope
10501 : ? DestructuringFormalParameterInVarScope
10502 108 : : DestructuringDeclaration))
10503 : {
10504 : return false;
10505 : }
10506 :
10507 108 : if (!emit1(JSOP_POP))
10508 : return false;
10509 : } else {
10510 26798 : RootedAtom paramName(cx, bindingElement->name());
10511 0 : NameLocation paramLoc = *locationOfNameBoundInScope(paramName, funScope);
10512 :
10513 0 : if (hasParameterExprs) {
10514 : auto emitRhs = [argSlot, initializer, isRest](BytecodeEmitter* bce,
10515 : const NameLocation&, bool)
10516 1112 : {
10517 : // If we had an initializer or a rest parameter, the value is
10518 : // already on the stack.
10519 0 : if (!initializer && !isRest)
10520 574 : return bce->emitArgOp(JSOP_GETARG, argSlot);
10521 : return true;
10522 0 : };
10523 :
10524 1112 : if (!emitSetOrInitializeNameAtLocation(paramName, paramLoc, emitRhs, true))
10525 0 : return false;
10526 1112 : if (!emit1(JSOP_POP))
10527 : return false;
10528 12287 : } else if (isRest) {
10529 : // The rest value is already on top of the stack.
10530 : auto nop = [](BytecodeEmitter*, const NameLocation&, bool) {
10531 : return true;
10532 : };
10533 :
10534 0 : if (!emitSetOrInitializeNameAtLocation(paramName, paramLoc, nop, true))
10535 : return false;
10536 151 : if (!emit1(JSOP_POP))
10537 : return false;
10538 : }
10539 : }
10540 :
10541 13507 : if (paramExprVarScope) {
10542 0 : if (!paramExprVarScope->leave(this))
10543 : return false;
10544 : }
10545 : }
10546 :
10547 : return true;
10548 : }
10549 :
10550 : bool
10551 0 : BytecodeEmitter::emitInitializeFunctionSpecialNames()
10552 : {
10553 13041 : FunctionBox* funbox = sc->asFunctionBox();
10554 :
10555 : auto emitInitializeFunctionSpecialName = [](BytecodeEmitter* bce, HandlePropertyName name,
10556 6527 : JSOp op)
10557 : {
10558 : // A special name must be slotful, either on the frame or on the
10559 : // call environment.
10560 19581 : MOZ_ASSERT(bce->lookupName(name).hasKnownSlot());
10561 :
10562 : auto emitInitial = [op](BytecodeEmitter* bce, const NameLocation&, bool) {
10563 : return bce->emit1(op);
10564 0 : };
10565 :
10566 0 : if (!bce->emitInitializeName(name, emitInitial))
10567 : return false;
10568 0 : if (!bce->emit1(JSOP_POP))
10569 : return false;
10570 :
10571 : return true;
10572 : };
10573 :
10574 : // Do nothing if the function doesn't have an arguments binding.
10575 13041 : if (funbox->argumentsHasLocalBinding()) {
10576 0 : if (!emitInitializeFunctionSpecialName(this, cx->names().arguments, JSOP_ARGUMENTS))
10577 : return false;
10578 : }
10579 :
10580 : // Do nothing if the function doesn't have a this-binding (this
10581 : // happens for instance if it doesn't use this/eval or if it's an
10582 : // arrow function).
10583 0 : if (funbox->hasThisBinding()) {
10584 0 : if (!emitInitializeFunctionSpecialName(this, cx->names().dotThis, JSOP_FUNCTIONTHIS))
10585 : return false;
10586 : }
10587 :
10588 : return true;
10589 : }
10590 :
10591 : bool
10592 0 : BytecodeEmitter::emitFunctionBody(ParseNode* funBody)
10593 : {
10594 13041 : FunctionBox* funbox = sc->asFunctionBox();
10595 :
10596 13041 : if (!emitTree(funBody))
10597 : return false;
10598 :
10599 0 : if (funbox->needsFinalYield()) {
10600 : // If we fall off the end of a generator, do a final yield.
10601 0 : bool needsIteratorResult = funbox->needsIteratorResult();
10602 0 : if (needsIteratorResult) {
10603 0 : if (!emitPrepareIteratorResult())
10604 : return false;
10605 : }
10606 :
10607 729 : if (!emit1(JSOP_UNDEFINED))
10608 : return false;
10609 :
10610 729 : if (needsIteratorResult) {
10611 40 : if (!emitFinishIteratorResult(true))
10612 : return false;
10613 : }
10614 :
10615 729 : if (!emit1(JSOP_SETRVAL))
10616 : return false;
10617 :
10618 729 : if (!emitGetDotGeneratorInInnermostScope())
10619 : return false;
10620 :
10621 : // No need to check for finally blocks, etc as in EmitReturn.
10622 729 : if (!emitYieldOp(JSOP_FINALYIELDRVAL))
10623 : return false;
10624 : } else {
10625 : // Non-generator functions just return |undefined|. The
10626 : // JSOP_RETRVAL emitted below will do that, except if the
10627 : // script has a finally block: there can be a non-undefined
10628 : // value in the return value slot. Make sure the return value
10629 : // is |undefined|.
10630 12312 : if (hasTryFinally) {
10631 54 : if (!emit1(JSOP_UNDEFINED))
10632 : return false;
10633 54 : if (!emit1(JSOP_SETRVAL))
10634 : return false;
10635 : }
10636 : }
10637 :
10638 13041 : if (funbox->isDerivedClassConstructor()) {
10639 79 : if (!emitCheckDerivedClassConstructorReturn())
10640 : return false;
10641 : }
10642 :
10643 : return true;
10644 : }
10645 :
10646 : bool
10647 0 : BytecodeEmitter::emitLexicalInitialization(ParseNode* pn)
10648 : {
10649 : // The caller has pushed the RHS to the top of the stack. Assert that the
10650 : // name is lexical and no BIND[G]NAME ops were emitted.
10651 1359 : auto assertLexical = [](BytecodeEmitter*, const NameLocation& loc, bool emittedBindOp) {
10652 1359 : MOZ_ASSERT(loc.isLexical());
10653 1359 : MOZ_ASSERT(!emittedBindOp);
10654 1359 : return true;
10655 : };
10656 0 : return emitInitializeName(pn, assertLexical);
10657 : }
10658 :
10659 : // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
10660 : // (BindingClassDeclarationEvaluation).
10661 : bool
10662 0 : BytecodeEmitter::emitClass(ParseNode* pn)
10663 : {
10664 212 : ClassNode& classNode = pn->as<ClassNode>();
10665 :
10666 0 : ClassNames* names = classNode.names();
10667 :
10668 0 : ParseNode* heritageExpression = classNode.heritage();
10669 :
10670 0 : ParseNode* classMethods = classNode.methodList();
10671 212 : ParseNode* constructor = nullptr;
10672 419 : for (ParseNode* mn = classMethods->pn_head; mn; mn = mn->pn_next) {
10673 371 : ClassMethod& method = mn->as<ClassMethod>();
10674 0 : ParseNode& methodName = method.name();
10675 1083 : if (!method.isStatic() &&
10676 0 : (methodName.isKind(ParseNodeKind::ObjectPropertyName) ||
10677 712 : methodName.isKind(ParseNodeKind::String)) &&
10678 0 : methodName.pn_atom == cx->names().constructor)
10679 : {
10680 164 : constructor = &method.method();
10681 164 : break;
10682 : }
10683 : }
10684 :
10685 424 : bool savedStrictness = sc->setLocalStrictMode(true);
10686 :
10687 424 : Maybe<TDZCheckCache> tdzCache;
10688 0 : Maybe<EmitterScope> emitterScope;
10689 212 : if (names) {
10690 192 : tdzCache.emplace(this);
10691 192 : emitterScope.emplace(this);
10692 0 : if (!emitterScope->enterLexical(this, ScopeKind::Lexical, classNode.scopeBindings()))
10693 : return false;
10694 : }
10695 :
10696 : // Pseudocode for class declarations:
10697 : //
10698 : // class extends BaseExpression {
10699 : // constructor() { ... }
10700 : // ...
10701 : // }
10702 : //
10703 : //
10704 : // if defined <BaseExpression> {
10705 : // let heritage = BaseExpression;
10706 : //
10707 : // if (heritage !== null) {
10708 : // funProto = heritage;
10709 : // objProto = heritage.prototype;
10710 : // } else {
10711 : // funProto = %FunctionPrototype%;
10712 : // objProto = null;
10713 : // }
10714 : // } else {
10715 : // objProto = %ObjectPrototype%;
10716 : // }
10717 : //
10718 : // let homeObject = ObjectCreate(objProto);
10719 : //
10720 : // if defined <constructor> {
10721 : // if defined <BaseExpression> {
10722 : // cons = DefineMethod(<constructor>, proto=homeObject, funProto=funProto);
10723 : // } else {
10724 : // cons = DefineMethod(<constructor>, proto=homeObject);
10725 : // }
10726 : // } else {
10727 : // if defined <BaseExpression> {
10728 : // cons = DefaultDerivedConstructor(proto=homeObject, funProto=funProto);
10729 : // } else {
10730 : // cons = DefaultConstructor(proto=homeObject);
10731 : // }
10732 : // }
10733 : //
10734 : // cons.prototype = homeObject;
10735 : // homeObject.constructor = cons;
10736 : //
10737 : // EmitPropertyList(...)
10738 :
10739 : // This is kind of silly. In order to the get the home object defined on
10740 : // the constructor, we have to make it second, but we want the prototype
10741 : // on top for EmitPropertyList, because we expect static properties to be
10742 : // rarer. The result is a few more swaps than we would like. Such is life.
10743 212 : if (heritageExpression) {
10744 0 : InternalIfEmitter ifThenElse(this);
10745 :
10746 116 : if (!emitTree(heritageExpression)) // ... HERITAGE
10747 0 : return false;
10748 :
10749 : // Heritage must be null or a non-generator constructor
10750 116 : if (!emit1(JSOP_CHECKCLASSHERITAGE)) // ... HERITAGE
10751 : return false;
10752 :
10753 : // [IF] (heritage !== null)
10754 116 : if (!emit1(JSOP_DUP)) // ... HERITAGE HERITAGE
10755 : return false;
10756 116 : if (!emit1(JSOP_NULL)) // ... HERITAGE HERITAGE NULL
10757 : return false;
10758 116 : if (!emit1(JSOP_STRICTNE)) // ... HERITAGE NE
10759 : return false;
10760 :
10761 : // [THEN] funProto = heritage, objProto = heritage.prototype
10762 0 : if (!ifThenElse.emitThenElse())
10763 : return false;
10764 116 : if (!emit1(JSOP_DUP)) // ... HERITAGE HERITAGE
10765 : return false;
10766 348 : if (!emitAtomOp(cx->names().prototype, JSOP_GETPROP)) // ... HERITAGE PROTO
10767 : return false;
10768 :
10769 : // [ELSE] funProto = %FunctionPrototype%, objProto = null
10770 116 : if (!ifThenElse.emitElse())
10771 : return false;
10772 116 : if (!emit1(JSOP_POP)) // ...
10773 : return false;
10774 0 : if (!emit2(JSOP_BUILTINPROTO, JSProto_Function)) // ... PROTO
10775 : return false;
10776 116 : if (!emit1(JSOP_NULL)) // ... PROTO NULL
10777 : return false;
10778 :
10779 : // [ENDIF]
10780 0 : if (!ifThenElse.emitEnd())
10781 : return false;
10782 :
10783 116 : if (!emit1(JSOP_OBJWITHPROTO)) // ... HERITAGE HOMEOBJ
10784 : return false;
10785 0 : if (!emit1(JSOP_SWAP)) // ... HOMEOBJ HERITAGE
10786 : return false;
10787 : } else {
10788 96 : if (!emitNewInit(JSProto_Object)) // ... HOMEOBJ
10789 : return false;
10790 : }
10791 :
10792 : // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
10793 : // is not used, an implicit value of %FunctionPrototype% is implied.
10794 :
10795 0 : if (constructor) {
10796 164 : if (!emitFunction(constructor, !!heritageExpression)) // ... HOMEOBJ CONSTRUCTOR
10797 : return false;
10798 328 : if (constructor->pn_funbox->needsHomeObject()) {
10799 0 : if (!emit2(JSOP_INITHOMEOBJECT, 0)) // ... HOMEOBJ CONSTRUCTOR
10800 : return false;
10801 : }
10802 : } else {
10803 : // In the case of default class constructors, emit the start and end
10804 : // offsets in the source buffer as source notes so that when we
10805 : // actually make the constructor during execution, we can give it the
10806 : // correct toString output.
10807 48 : ptrdiff_t classStart = ptrdiff_t(pn->pn_pos.begin);
10808 48 : ptrdiff_t classEnd = ptrdiff_t(pn->pn_pos.end);
10809 0 : if (!newSrcNote3(SRC_CLASS_SPAN, classStart, classEnd))
10810 : return false;
10811 :
10812 64 : JSAtom *name = names ? names->innerBinding()->pn_atom : cx->names().empty;
10813 48 : if (heritageExpression) {
10814 0 : if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR)) // ... HOMEOBJ CONSTRUCTOR
10815 : return false;
10816 : } else {
10817 11 : if (!emitAtomOp(name, JSOP_CLASSCONSTRUCTOR)) // ... HOMEOBJ CONSTRUCTOR
10818 : return false;
10819 : }
10820 : }
10821 :
10822 212 : if (!emit1(JSOP_SWAP)) // ... CONSTRUCTOR HOMEOBJ
10823 : return false;
10824 :
10825 212 : if (!emit1(JSOP_DUP2)) // ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR HOMEOBJ
10826 : return false;
10827 636 : if (!emitAtomOp(cx->names().prototype, JSOP_INITLOCKEDPROP)) // ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR
10828 : return false;
10829 636 : if (!emitAtomOp(cx->names().constructor, JSOP_INITHIDDENPROP)) // ... CONSTRUCTOR HOMEOBJ
10830 : return false;
10831 :
10832 636 : RootedPlainObject obj(cx);
10833 212 : if (!emitPropertyList(classMethods, &obj, ClassBody)) // ... CONSTRUCTOR HOMEOBJ
10834 : return false;
10835 :
10836 0 : if (!emit1(JSOP_POP)) // ... CONSTRUCTOR
10837 : return false;
10838 :
10839 212 : if (names) {
10840 192 : ParseNode* innerName = names->innerBinding();
10841 0 : if (!emitLexicalInitialization(innerName)) // ... CONSTRUCTOR
10842 : return false;
10843 :
10844 : // Pop the inner scope.
10845 192 : if (!emitterScope->leave(this))
10846 : return false;
10847 192 : emitterScope.reset();
10848 :
10849 192 : ParseNode* outerName = names->outerBinding();
10850 192 : if (outerName) {
10851 0 : if (!emitLexicalInitialization(outerName)) // ... CONSTRUCTOR
10852 : return false;
10853 : // Only class statements make outer bindings, and they do not leave
10854 : // themselves on the stack.
10855 165 : if (!emit1(JSOP_POP)) // ...
10856 : return false;
10857 : }
10858 : }
10859 :
10860 : // The CONSTRUCTOR is left on stack if this is an expression.
10861 :
10862 424 : MOZ_ALWAYS_TRUE(sc->setLocalStrictMode(savedStrictness));
10863 :
10864 : return true;
10865 : }
10866 :
10867 : bool
10868 0 : BytecodeEmitter::emitExportDefault(ParseNode* pn)
10869 : {
10870 0 : if (!emitTree(pn->pn_left))
10871 : return false;
10872 :
10873 0 : if (pn->pn_right) {
10874 0 : if (!emitLexicalInitialization(pn->pn_right))
10875 : return false;
10876 :
10877 0 : if (pn->pn_left->isDirectRHSAnonFunction()) {
10878 0 : HandlePropertyName name = cx->names().default_;
10879 0 : if (!setOrEmitSetFunName(pn->pn_left, name))
10880 : return false;
10881 : }
10882 :
10883 0 : if (!emit1(JSOP_POP))
10884 : return false;
10885 : }
10886 :
10887 : return true;
10888 : }
10889 :
10890 : bool
10891 0 : BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
10892 : EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */)
10893 : {
10894 475431 : if (!CheckRecursionLimit(cx))
10895 : return false;
10896 :
10897 475437 : EmitLevelManager elm(this);
10898 :
10899 : /* Emit notes to tell the current bytecode's source line number.
10900 : However, a couple trees require special treatment; see the
10901 : relevant emitter functions for details. */
10902 475437 : if (emitLineNote == EMIT_LINENOTE && !ParseNodeRequiresSpecialLineNumberNotes(pn)) {
10903 454948 : if (!updateLineNumberNotes(pn->pn_pos.begin))
10904 : return false;
10905 : }
10906 :
10907 475411 : switch (pn->getKind()) {
10908 : case ParseNodeKind::Function:
10909 12272 : if (!emitFunction(pn))
10910 : return false;
10911 : break;
10912 :
10913 : case ParseNodeKind::ParamsBody:
10914 13041 : if (!emitFunctionFormalParametersAndBody(pn))
10915 : return false;
10916 : break;
10917 :
10918 : case ParseNodeKind::If:
10919 12834 : if (!emitIf(pn))
10920 : return false;
10921 : break;
10922 :
10923 : case ParseNodeKind::Switch:
10924 0 : if (!emitSwitch(pn))
10925 : return false;
10926 : break;
10927 :
10928 : case ParseNodeKind::While:
10929 0 : if (!emitWhile(pn))
10930 : return false;
10931 : break;
10932 :
10933 : case ParseNodeKind::DoWhile:
10934 0 : if (!emitDo(pn))
10935 : return false;
10936 : break;
10937 :
10938 : case ParseNodeKind::For:
10939 188 : if (!emitFor(pn))
10940 : return false;
10941 : break;
10942 :
10943 : case ParseNodeKind::Break:
10944 1260 : if (!emitBreak(pn->as<BreakStatement>().label()))
10945 : return false;
10946 : break;
10947 :
10948 : case ParseNodeKind::Continue:
10949 265 : if (!emitContinue(pn->as<ContinueStatement>().label()))
10950 : return false;
10951 : break;
10952 :
10953 : case ParseNodeKind::With:
10954 0 : if (!emitWith(pn))
10955 : return false;
10956 : break;
10957 :
10958 : case ParseNodeKind::Try:
10959 1074 : if (!emitTry(pn))
10960 : return false;
10961 : break;
10962 :
10963 : case ParseNodeKind::Catch:
10964 1003 : if (!emitCatch(pn))
10965 : return false;
10966 : break;
10967 :
10968 : case ParseNodeKind::Var:
10969 3527 : if (!emitDeclarationList(pn))
10970 : return false;
10971 : break;
10972 :
10973 : case ParseNodeKind::Return:
10974 11321 : if (!emitReturn(pn))
10975 : return false;
10976 : break;
10977 :
10978 : case ParseNodeKind::YieldStar:
10979 9 : if (!emitYieldStar(pn->pn_kid))
10980 : return false;
10981 : break;
10982 :
10983 : case ParseNodeKind::Generator:
10984 729 : if (!emit1(JSOP_GENERATOR))
10985 : return false;
10986 : break;
10987 :
10988 : case ParseNodeKind::InitialYield:
10989 729 : if (!emitInitialYield(pn))
10990 : return false;
10991 : break;
10992 :
10993 : case ParseNodeKind::Yield:
10994 44 : if (!emitYield(pn))
10995 : return false;
10996 : break;
10997 :
10998 : case ParseNodeKind::Await:
10999 1222 : if (!emitAwaitInInnermostScope(pn))
11000 : return false;
11001 : break;
11002 :
11003 : case ParseNodeKind::StatementList:
11004 30549 : if (!emitStatementList(pn))
11005 : return false;
11006 : break;
11007 :
11008 : case ParseNodeKind::EmptyStatement:
11009 : break;
11010 :
11011 : case ParseNodeKind::ExpressionStatement:
11012 32140 : if (!emitExpressionStatement(pn))
11013 : return false;
11014 : break;
11015 :
11016 : case ParseNodeKind::Label:
11017 0 : if (!emitLabeledStatement(&pn->as<LabeledStatement>()))
11018 : return false;
11019 : break;
11020 :
11021 : case ParseNodeKind::Comma:
11022 8 : if (!emitSequenceExpr(pn, valueUsage))
11023 : return false;
11024 : break;
11025 :
11026 : case ParseNodeKind::Assign:
11027 : case ParseNodeKind::AddAssign:
11028 : case ParseNodeKind::SubAssign:
11029 : case ParseNodeKind::BitOrAssign:
11030 : case ParseNodeKind::BitXorAssign:
11031 : case ParseNodeKind::BitAndAssign:
11032 : case ParseNodeKind::LshAssign:
11033 : case ParseNodeKind::RshAssign:
11034 : case ParseNodeKind::UrshAssign:
11035 : case ParseNodeKind::MulAssign:
11036 : case ParseNodeKind::DivAssign:
11037 : case ParseNodeKind::ModAssign:
11038 : case ParseNodeKind::PowAssign:
11039 12891 : if (!emitAssignment(pn->pn_left, pn->getKind(), pn->pn_right))
11040 : return false;
11041 : break;
11042 :
11043 : case ParseNodeKind::Conditional:
11044 971 : if (!emitConditionalExpression(pn->as<ConditionalExpression>(), valueUsage))
11045 : return false;
11046 : break;
11047 :
11048 : case ParseNodeKind::Or:
11049 : case ParseNodeKind::And:
11050 0 : if (!emitLogical(pn))
11051 : return false;
11052 : break;
11053 :
11054 : case ParseNodeKind::Add:
11055 : case ParseNodeKind::Sub:
11056 : case ParseNodeKind::BitOr:
11057 : case ParseNodeKind::BitXor:
11058 : case ParseNodeKind::BitAnd:
11059 : case ParseNodeKind::StrictEq:
11060 : case ParseNodeKind::Eq:
11061 : case ParseNodeKind::StrictNe:
11062 : case ParseNodeKind::Ne:
11063 : case ParseNodeKind::Lt:
11064 : case ParseNodeKind::Le:
11065 : case ParseNodeKind::Gt:
11066 : case ParseNodeKind::Ge:
11067 : case ParseNodeKind::In:
11068 : case ParseNodeKind::InstanceOf:
11069 : case ParseNodeKind::Lsh:
11070 : case ParseNodeKind::Rsh:
11071 : case ParseNodeKind::Ursh:
11072 : case ParseNodeKind::Star:
11073 : case ParseNodeKind::Div:
11074 : case ParseNodeKind::Mod:
11075 11850 : if (!emitLeftAssociative(pn))
11076 : return false;
11077 : break;
11078 :
11079 : case ParseNodeKind::Pow:
11080 0 : if (!emitRightAssociative(pn))
11081 : return false;
11082 : break;
11083 :
11084 : case ParseNodeKind::Pipeline:
11085 0 : if (!emitPipeline(pn))
11086 : return false;
11087 : break;
11088 :
11089 : case ParseNodeKind::TypeOfName:
11090 553 : if (!emitTypeof(pn, JSOP_TYPEOF))
11091 : return false;
11092 : break;
11093 :
11094 : case ParseNodeKind::TypeOfExpr:
11095 0 : if (!emitTypeof(pn, JSOP_TYPEOFEXPR))
11096 : return false;
11097 : break;
11098 :
11099 : case ParseNodeKind::Throw:
11100 : case ParseNodeKind::Void:
11101 : case ParseNodeKind::Not:
11102 : case ParseNodeKind::BitNot:
11103 : case ParseNodeKind::Pos:
11104 : case ParseNodeKind::Neg:
11105 6481 : if (!emitUnary(pn))
11106 : return false;
11107 : break;
11108 :
11109 : case ParseNodeKind::PreIncrement:
11110 : case ParseNodeKind::PreDecrement:
11111 : case ParseNodeKind::PostIncrement:
11112 : case ParseNodeKind::PostDecrement:
11113 648 : if (!emitIncOrDec(pn))
11114 : return false;
11115 : break;
11116 :
11117 : case ParseNodeKind::DeleteName:
11118 0 : if (!emitDeleteName(pn))
11119 : return false;
11120 : break;
11121 :
11122 : case ParseNodeKind::DeleteProp:
11123 266 : if (!emitDeleteProperty(pn))
11124 : return false;
11125 : break;
11126 :
11127 : case ParseNodeKind::DeleteElem:
11128 94 : if (!emitDeleteElement(pn))
11129 : return false;
11130 : break;
11131 :
11132 : case ParseNodeKind::DeleteExpr:
11133 0 : if (!emitDeleteExpression(pn))
11134 : return false;
11135 : break;
11136 :
11137 : case ParseNodeKind::Dot:
11138 57344 : if (pn->as<PropertyAccess>().isSuper()) {
11139 12 : if (!emitSuperPropOp(pn, JSOP_GETPROP_SUPER))
11140 : return false;
11141 : } else {
11142 0 : if (!emitPropOp(pn, JSOP_GETPROP))
11143 : return false;
11144 : }
11145 : break;
11146 :
11147 : case ParseNodeKind::Elem:
11148 5094 : if (pn->as<PropertyByValue>().isSuper()) {
11149 0 : if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
11150 : return false;
11151 : } else {
11152 2547 : if (!emitElemOp(pn, JSOP_GETELEM))
11153 : return false;
11154 : }
11155 : break;
11156 :
11157 : case ParseNodeKind::New:
11158 : case ParseNodeKind::TaggedTemplate:
11159 : case ParseNodeKind::Call:
11160 : case ParseNodeKind::SuperCall:
11161 43830 : if (!emitCallOrNew(pn, valueUsage))
11162 : return false;
11163 : break;
11164 :
11165 : case ParseNodeKind::LexicalScope:
11166 31777 : if (!emitLexicalScope(pn))
11167 : return false;
11168 : break;
11169 :
11170 : case ParseNodeKind::Const:
11171 : case ParseNodeKind::Let:
11172 0 : if (!emitDeclarationList(pn))
11173 : return false;
11174 : break;
11175 :
11176 : case ParseNodeKind::Import:
11177 0 : MOZ_ASSERT(sc->isModuleContext());
11178 : break;
11179 :
11180 : case ParseNodeKind::Export:
11181 0 : MOZ_ASSERT(sc->isModuleContext());
11182 0 : if (pn->pn_kid->getKind() != ParseNodeKind::ExportSpecList) {
11183 0 : if (!emitTree(pn->pn_kid))
11184 : return false;
11185 : }
11186 : break;
11187 :
11188 : case ParseNodeKind::ExportDefault:
11189 0 : MOZ_ASSERT(sc->isModuleContext());
11190 0 : if (!emitExportDefault(pn))
11191 : return false;
11192 : break;
11193 :
11194 : case ParseNodeKind::ExportFrom:
11195 0 : MOZ_ASSERT(sc->isModuleContext());
11196 : break;
11197 :
11198 : case ParseNodeKind::CallSiteObj:
11199 0 : if (!emitCallSiteObject(pn))
11200 : return false;
11201 : break;
11202 :
11203 : case ParseNodeKind::Array:
11204 2700 : if (!emitArrayLiteral(pn))
11205 : return false;
11206 : break;
11207 :
11208 : case ParseNodeKind::Object:
11209 4660 : if (!emitObject(pn))
11210 : return false;
11211 : break;
11212 :
11213 : case ParseNodeKind::Name:
11214 119239 : if (!emitGetName(pn))
11215 : return false;
11216 : break;
11217 :
11218 : case ParseNodeKind::TemplateStringList:
11219 0 : if (!emitTemplateString(pn))
11220 : return false;
11221 : break;
11222 :
11223 : case ParseNodeKind::TemplateString:
11224 : case ParseNodeKind::String:
11225 0 : if (!emitAtomOp(pn, JSOP_STRING))
11226 : return false;
11227 : break;
11228 :
11229 : case ParseNodeKind::Number:
11230 7716 : if (!emitNumberOp(pn->pn_dval))
11231 : return false;
11232 : break;
11233 :
11234 : case ParseNodeKind::RegExp:
11235 592 : if (!emitRegExp(objectList.add(pn->as<RegExpLiteral>().objbox())))
11236 : return false;
11237 : break;
11238 :
11239 : case ParseNodeKind::True:
11240 : case ParseNodeKind::False:
11241 : case ParseNodeKind::Null:
11242 : case ParseNodeKind::RawUndefined:
11243 0 : if (!emit1(pn->getOp()))
11244 : return false;
11245 : break;
11246 :
11247 : case ParseNodeKind::This:
11248 0 : if (!emitThisLiteral(pn))
11249 : return false;
11250 : break;
11251 :
11252 : case ParseNodeKind::Debugger:
11253 0 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
11254 : return false;
11255 0 : if (!emit1(JSOP_DEBUGGER))
11256 : return false;
11257 : break;
11258 :
11259 : case ParseNodeKind::Class:
11260 0 : if (!emitClass(pn))
11261 : return false;
11262 : break;
11263 :
11264 : case ParseNodeKind::NewTarget:
11265 0 : if (!emit1(JSOP_NEWTARGET))
11266 : return false;
11267 : break;
11268 :
11269 : case ParseNodeKind::ImportMeta:
11270 0 : if (!emit1(JSOP_IMPORTMETA))
11271 : return false;
11272 : break;
11273 :
11274 : case ParseNodeKind::SetThis:
11275 0 : if (!emitSetThis(pn))
11276 : return false;
11277 : break;
11278 :
11279 : case ParseNodeKind::PosHolder:
11280 0 : MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder");
11281 :
11282 : default:
11283 0 : MOZ_ASSERT(0);
11284 : }
11285 :
11286 : /* bce->emitLevel == 1 means we're last on the stack, so finish up. */
11287 0 : if (emitLevel == 1) {
11288 13449 : if (!updateSourceCoordNotes(pn->pn_pos.end))
11289 : return false;
11290 : }
11291 : return true;
11292 : }
11293 :
11294 : bool
11295 1874 : BytecodeEmitter::emitTreeInBranch(ParseNode* pn,
11296 : ValueUsage valueUsage /* = ValueUsage::WantValue */)
11297 : {
11298 : // Code that may be conditionally executed always need their own TDZ
11299 : // cache.
11300 3748 : TDZCheckCache tdzCache(this);
11301 3748 : return emitTree(pn, valueUsage);
11302 : }
11303 :
11304 : static bool
11305 0 : AllocSrcNote(JSContext* cx, SrcNotesVector& notes, unsigned* index)
11306 : {
11307 638368 : if (!notes.growBy(1)) {
11308 0 : ReportOutOfMemory(cx);
11309 0 : return false;
11310 : }
11311 :
11312 0 : *index = notes.length() - 1;
11313 638398 : return true;
11314 : }
11315 :
11316 : bool
11317 1 : BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp)
11318 : {
11319 514999 : SrcNotesVector& notes = this->notes();
11320 : unsigned index;
11321 515003 : if (!AllocSrcNote(cx, notes, &index))
11322 : return false;
11323 :
11324 : /*
11325 : * Compute delta from the last annotated bytecode's offset. If it's too
11326 : * big to fit in sn, allocate one or more xdelta notes and reset sn.
11327 : */
11328 515023 : ptrdiff_t offset = this->offset();
11329 1030046 : ptrdiff_t delta = offset - lastNoteOffset();
11330 0 : current->lastNoteOffset = offset;
11331 515023 : if (delta >= SN_DELTA_LIMIT) {
11332 : do {
11333 0 : ptrdiff_t xdelta = Min(delta, SN_XDELTA_MASK);
11334 0 : SN_MAKE_XDELTA(¬es[index], xdelta);
11335 0 : delta -= xdelta;
11336 0 : if (!AllocSrcNote(cx, notes, &index))
11337 : return false;
11338 0 : } while (delta >= SN_DELTA_LIMIT);
11339 : }
11340 :
11341 : /*
11342 : * Initialize type and delta, then allocate the minimum number of notes
11343 : * needed for type's arity. Usually, we won't need more, but if an offset
11344 : * does take two bytes, setSrcNoteOffset will grow notes.
11345 : */
11346 0 : SN_MAKE_NOTE(¬es[index], type, delta);
11347 696424 : for (int n = (int)js_SrcNoteSpec[type].arity; n > 0; n--) {
11348 0 : if (!newSrcNote(SRC_NULL))
11349 : return false;
11350 : }
11351 :
11352 0 : if (indexp)
11353 0 : *indexp = index;
11354 : return true;
11355 : }
11356 :
11357 : bool
11358 173832 : BytecodeEmitter::newSrcNote2(SrcNoteType type, ptrdiff_t offset, unsigned* indexp)
11359 : {
11360 : unsigned index;
11361 0 : if (!newSrcNote(type, &index))
11362 : return false;
11363 0 : if (!setSrcNoteOffset(index, 0, offset))
11364 : return false;
11365 173844 : if (indexp)
11366 1521 : *indexp = index;
11367 : return true;
11368 : }
11369 :
11370 : bool
11371 407 : BytecodeEmitter::newSrcNote3(SrcNoteType type, ptrdiff_t offset1, ptrdiff_t offset2,
11372 : unsigned* indexp)
11373 : {
11374 : unsigned index;
11375 1 : if (!newSrcNote(type, &index))
11376 : return false;
11377 407 : if (!setSrcNoteOffset(index, 0, offset1))
11378 : return false;
11379 407 : if (!setSrcNoteOffset(index, 1, offset2))
11380 : return false;
11381 407 : if (indexp)
11382 359 : *indexp = index;
11383 : return true;
11384 : }
11385 :
11386 : bool
11387 0 : BytecodeEmitter::addToSrcNoteDelta(jssrcnote* sn, ptrdiff_t delta)
11388 : {
11389 : /*
11390 : * Called only from finishTakingSrcNotes to add to main script note
11391 : * deltas, and only by a small positive amount.
11392 : */
11393 0 : MOZ_ASSERT(current == &main);
11394 0 : MOZ_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT);
11395 :
11396 7111 : ptrdiff_t base = SN_DELTA(sn);
11397 0 : ptrdiff_t limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
11398 7111 : ptrdiff_t newdelta = base + delta;
11399 0 : if (newdelta < limit) {
11400 0 : SN_SET_DELTA(sn, newdelta);
11401 : } else {
11402 : jssrcnote xdelta;
11403 0 : SN_MAKE_XDELTA(&xdelta, delta);
11404 602 : if (!main.notes.insert(sn, xdelta))
11405 0 : return false;
11406 : }
11407 : return true;
11408 : }
11409 :
11410 : bool
11411 0 : BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offset)
11412 : {
11413 183611 : if (!SN_REPRESENTABLE_OFFSET(offset)) {
11414 0 : reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
11415 0 : return false;
11416 : }
11417 :
11418 0 : SrcNotesVector& notes = this->notes();
11419 :
11420 : /* Find the offset numbered which (i.e., skip exactly which offsets). */
11421 0 : jssrcnote* sn = ¬es[index];
11422 0 : MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
11423 1 : MOZ_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
11424 0 : for (sn++; which; sn++, which--) {
11425 0 : if (*sn & SN_4BYTE_OFFSET_FLAG)
11426 0 : sn += 3;
11427 : }
11428 :
11429 : /*
11430 : * See if the new offset requires four bytes either by being too big or if
11431 : * the offset has already been inflated (in which case, we need to stay big
11432 : * to not break the srcnote encoding if this isn't the last srcnote).
11433 : */
11434 0 : if (offset > (ptrdiff_t)SN_4BYTE_OFFSET_MASK || (*sn & SN_4BYTE_OFFSET_FLAG)) {
11435 : /* Maybe this offset was already set to a four-byte value. */
11436 31650 : if (!(*sn & SN_4BYTE_OFFSET_FLAG)) {
11437 : /* Insert three dummy bytes that will be overwritten shortly. */
11438 31650 : jssrcnote dummy = 0;
11439 94950 : if (!(sn = notes.insert(sn, dummy)) ||
11440 63300 : !(sn = notes.insert(sn, dummy)) ||
11441 31650 : !(sn = notes.insert(sn, dummy)))
11442 : {
11443 0 : ReportOutOfMemory(cx);
11444 0 : return false;
11445 : }
11446 : }
11447 31650 : *sn++ = (jssrcnote)(SN_4BYTE_OFFSET_FLAG | (offset >> 24));
11448 0 : *sn++ = (jssrcnote)(offset >> 16);
11449 0 : *sn++ = (jssrcnote)(offset >> 8);
11450 : }
11451 0 : *sn = (jssrcnote)offset;
11452 183611 : return true;
11453 : }
11454 :
11455 : bool
11456 13449 : BytecodeEmitter::finishTakingSrcNotes(uint32_t* out)
11457 : {
11458 0 : MOZ_ASSERT(current == &main);
11459 :
11460 0 : MOZ_ASSERT(prologue.notes.length() == 0);
11461 0 : MOZ_ASSERT(prologue.lastNoteOffset == 0);
11462 :
11463 : // We may need to adjust the offset of the first main note, by adding to
11464 : // its delta and possibly even prepending SRC_XDELTA notes to it to account
11465 : // for prologue bytecodes.
11466 0 : ptrdiff_t offset = prologueOffset();
11467 0 : MOZ_ASSERT(offset >= 0);
11468 0 : if (offset > 0 && main.notes.length() != 0) {
11469 : // NB: Use as much of the first main note's delta as we can.
11470 13018 : jssrcnote* sn = main.notes.begin();
11471 6509 : ptrdiff_t delta = SN_IS_XDELTA(sn)
11472 0 : ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
11473 12953 : : SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
11474 0 : if (offset < delta)
11475 0 : delta = offset;
11476 : for (;;) {
11477 0 : if (!addToSrcNoteDelta(sn, delta))
11478 : return false;
11479 7111 : offset -= delta;
11480 7111 : if (offset == 0)
11481 : break;
11482 602 : delta = Min(offset, SN_XDELTA_MASK);
11483 0 : sn = main.notes.begin();
11484 : }
11485 : }
11486 :
11487 : // The + 1 is to account for the final SN_MAKE_TERMINATOR that is appended
11488 : // when the notes are copied to their final destination by copySrcNotes.
11489 0 : *out = main.notes.length() + 1;
11490 0 : return true;
11491 : }
11492 :
11493 : void
11494 13449 : BytecodeEmitter::copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes)
11495 : {
11496 13449 : MOZ_ASSERT(prologue.notes.length() == 0);
11497 0 : unsigned mainCount = main.notes.length();
11498 : // nsrcnotes includes SN_MAKE_TERMINATOR in addition to main.notes.
11499 0 : MOZ_ASSERT(mainCount == nsrcnotes - 1);
11500 26898 : PodCopy(destination, main.notes.begin(), mainCount);
11501 0 : SN_MAKE_TERMINATOR(&destination[mainCount]);
11502 0 : }
11503 :
11504 : void
11505 42 : CGConstList::finish(ConstArray* array)
11506 : {
11507 42 : MOZ_ASSERT(length() == array->length);
11508 :
11509 321 : for (unsigned i = 0; i < length(); i++)
11510 0 : array->vector[i] = list[i];
11511 42 : }
11512 :
11513 : /*
11514 : * Find the index of the given object for code generator.
11515 : *
11516 : * Since the emitter refers to each parsed object only once, for the index we
11517 : * use the number of already indexed objects. We also add the object to a list
11518 : * to convert the list to a fixed-size array when we complete code generation,
11519 : * see js::CGObjectList::finish below.
11520 : */
11521 : unsigned
11522 17178 : CGObjectList::add(ObjectBox* objbox)
11523 : {
11524 0 : MOZ_ASSERT(!objbox->emitLink);
11525 0 : objbox->emitLink = lastbox;
11526 0 : lastbox = objbox;
11527 0 : return length++;
11528 : }
11529 :
11530 : void
11531 3904 : CGObjectList::finish(ObjectArray* array)
11532 : {
11533 3904 : MOZ_ASSERT(length <= INDEX_LIMIT);
11534 0 : MOZ_ASSERT(length == array->length);
11535 :
11536 0 : js::GCPtrObject* cursor = array->vector + array->length;
11537 0 : ObjectBox* objbox = lastbox;
11538 0 : do {
11539 0 : --cursor;
11540 0 : MOZ_ASSERT(!*cursor);
11541 0 : MOZ_ASSERT(objbox->object->isTenured());
11542 34356 : *cursor = objbox->object;
11543 0 : } while ((objbox = objbox->emitLink) != nullptr);
11544 3905 : MOZ_ASSERT(cursor == array->vector);
11545 3905 : }
11546 :
11547 : void
11548 0 : CGScopeList::finish(ScopeArray* array)
11549 : {
11550 0 : MOZ_ASSERT(length() <= INDEX_LIMIT);
11551 0 : MOZ_ASSERT(length() == array->length);
11552 0 : for (uint32_t i = 0; i < length(); i++)
11553 92492 : array->vector[i].init(vector[i]);
11554 13449 : }
11555 :
11556 : bool
11557 7653 : CGTryNoteList::append(JSTryNoteKind kind, uint32_t stackDepth, size_t start, size_t end)
11558 : {
11559 7653 : MOZ_ASSERT(start <= end);
11560 7653 : MOZ_ASSERT(size_t(uint32_t(start)) == start);
11561 7653 : MOZ_ASSERT(size_t(uint32_t(end)) == end);
11562 :
11563 : JSTryNote note;
11564 7653 : note.kind = kind;
11565 7653 : note.stackDepth = stackDepth;
11566 7653 : note.start = uint32_t(start);
11567 7653 : note.length = uint32_t(end - start);
11568 :
11569 7653 : return list.append(note);
11570 : }
11571 :
11572 : void
11573 2320 : CGTryNoteList::finish(TryNoteArray* array)
11574 : {
11575 2320 : MOZ_ASSERT(length() == array->length);
11576 :
11577 0 : for (unsigned i = 0; i < length(); i++)
11578 0 : array->vector[i] = list[i];
11579 0 : }
11580 :
11581 : bool
11582 0 : CGScopeNoteList::append(uint32_t scopeIndex, uint32_t offset, bool inPrologue,
11583 : uint32_t parent)
11584 : {
11585 : CGScopeNote note;
11586 0 : mozilla::PodZero(¬e);
11587 :
11588 13762 : note.index = scopeIndex;
11589 0 : note.start = offset;
11590 0 : note.parent = parent;
11591 0 : note.startInPrologue = inPrologue;
11592 :
11593 0 : return list.append(note);
11594 : }
11595 :
11596 : void
11597 0 : CGScopeNoteList::recordEnd(uint32_t index, uint32_t offset, bool inPrologue)
11598 : {
11599 0 : MOZ_ASSERT(index < length());
11600 13762 : MOZ_ASSERT(list[index].length == 0);
11601 0 : list[index].end = offset;
11602 : list[index].endInPrologue = inPrologue;
11603 : }
11604 :
11605 : void
11606 : CGScopeNoteList::finish(ScopeNoteArray* array, uint32_t prologueLength)
11607 : {
11608 : MOZ_ASSERT(length() == array->length);
11609 :
11610 : for (unsigned i = 0; i < length(); i++) {
11611 : if (!list[i].startInPrologue)
11612 : list[i].start += prologueLength;
11613 : if (!list[i].endInPrologue && list[i].end != UINT32_MAX)
11614 : list[i].end += prologueLength;
11615 : MOZ_ASSERT(list[i].end >= list[i].start);
11616 : list[i].length = list[i].end - list[i].start;
11617 : array->vector[i] = list[i];
11618 : }
11619 : }
11620 :
11621 : void
11622 : CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength)
11623 : {
11624 : MOZ_ASSERT(length() == array.length());
11625 :
11626 : for (unsigned i = 0; i < length(); i++)
11627 : array[i] = prologueLength + list[i];
11628 : }
11629 :
11630 : /*
11631 : * We should try to get rid of offsetBias (always 0 or 1, where 1 is
11632 : * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR.
11633 : */
11634 : const JSSrcNoteSpec js_SrcNoteSpec[] = {
11635 : #define DEFINE_SRC_NOTE_SPEC(sym, name, arity) { name, arity },
11636 : FOR_EACH_SRC_NOTE_TYPE(DEFINE_SRC_NOTE_SPEC)
11637 : #undef DEFINE_SRC_NOTE_SPEC
11638 : };
11639 :
11640 : static int
11641 : SrcNoteArity(jssrcnote* sn)
11642 : {
11643 : MOZ_ASSERT(SN_TYPE(sn) < SRC_LAST);
11644 : return js_SrcNoteSpec[SN_TYPE(sn)].arity;
11645 : }
11646 :
11647 : JS_FRIEND_API(unsigned)
11648 : js::SrcNoteLength(jssrcnote* sn)
11649 : {
11650 : unsigned arity;
11651 : jssrcnote* base;
11652 :
11653 : arity = SrcNoteArity(sn);
11654 : for (base = sn++; arity; sn++, arity--) {
11655 : if (*sn & SN_4BYTE_OFFSET_FLAG)
11656 : sn += 3;
11657 : }
11658 : return sn - base;
11659 : }
11660 :
11661 : JS_FRIEND_API(ptrdiff_t)
11662 : js::GetSrcNoteOffset(jssrcnote* sn, unsigned which)
11663 : {
11664 : /* Find the offset numbered which (i.e., skip exactly which offsets). */
11665 : MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
11666 : MOZ_ASSERT((int) which < SrcNoteArity(sn));
11667 : for (sn++; which; sn++, which--) {
11668 : if (*sn & SN_4BYTE_OFFSET_FLAG)
11669 : sn += 3;
11670 : }
11671 : if (*sn & SN_4BYTE_OFFSET_FLAG) {
11672 : return (ptrdiff_t)(((uint32_t)(sn[0] & SN_4BYTE_OFFSET_MASK) << 24)
11673 : | (sn[1] << 16)
11674 : | (sn[2] << 8)
11675 : | sn[3]);
11676 : }
11677 : return (ptrdiff_t)*sn;
11678 : }
|