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 "jsatom.h"
23 : #include "jscntxt.h"
24 : #include "jsfun.h"
25 : #include "jsnum.h"
26 : #include "jsopcode.h"
27 : #include "jsscript.h"
28 : #include "jstypes.h"
29 : #include "jsutil.h"
30 :
31 : #include "ds/Nestable.h"
32 : #include "frontend/Parser.h"
33 : #include "frontend/TokenStream.h"
34 : #include "vm/Debugger.h"
35 : #include "vm/GeneratorObject.h"
36 : #include "vm/Stack.h"
37 : #include "wasm/AsmJS.h"
38 :
39 : #include "jsatominlines.h"
40 : #include "jsobjinlines.h"
41 : #include "jsscriptinlines.h"
42 :
43 : #include "frontend/ParseNode-inl.h"
44 : #include "vm/EnvironmentObject-inl.h"
45 : #include "vm/NativeObject-inl.h"
46 :
47 : using namespace js;
48 : using namespace js::gc;
49 : using namespace js::frontend;
50 :
51 : using mozilla::AssertedCast;
52 : using mozilla::DebugOnly;
53 : using mozilla::Maybe;
54 : using mozilla::Nothing;
55 : using mozilla::NumberIsInt32;
56 : using mozilla::PodCopy;
57 : using mozilla::Some;
58 : using mozilla::Unused;
59 :
60 : class BreakableControl;
61 : class LabelControl;
62 : class LoopControl;
63 : class ForOfLoopControl;
64 : class TryFinallyControl;
65 :
66 : static bool
67 227412 : ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn)
68 : {
69 227412 : return pn->getKind() == PNK_WHILE || pn->getKind() == PNK_FOR;
70 : }
71 :
72 : // A cache that tracks superfluous TDZ checks.
73 : //
74 : // Each basic block should have a TDZCheckCache in scope. Some NestableControl
75 : // subclasses contain a TDZCheckCache.
76 40420 : class BytecodeEmitter::TDZCheckCache : public Nestable<BytecodeEmitter::TDZCheckCache>
77 : {
78 : PooledMapPtr<CheckTDZMap> cache_;
79 :
80 23035 : MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
81 23035 : return cache_ || cache_.acquire(bce->cx);
82 : }
83 :
84 : public:
85 40415 : explicit TDZCheckCache(BytecodeEmitter* bce)
86 40415 : : Nestable<TDZCheckCache>(&bce->innermostTDZCheckCache),
87 40415 : cache_(bce->cx->frontendCollectionPool())
88 40415 : { }
89 :
90 : Maybe<MaybeCheckTDZ> needsTDZCheck(BytecodeEmitter* bce, JSAtom* name);
91 : MOZ_MUST_USE bool noteTDZCheck(BytecodeEmitter* bce, JSAtom* name, MaybeCheckTDZ check);
92 : };
93 :
94 1773 : class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl>
95 : {
96 : StatementKind kind_;
97 :
98 : // The innermost scope when this was pushed.
99 : EmitterScope* emitterScope_;
100 :
101 : protected:
102 1773 : NestableControl(BytecodeEmitter* bce, StatementKind kind)
103 1773 : : Nestable<NestableControl>(&bce->innermostNestableControl),
104 : kind_(kind),
105 1773 : emitterScope_(bce->innermostEmitterScope)
106 1773 : { }
107 :
108 : public:
109 : using Nestable<NestableControl>::enclosing;
110 : using Nestable<NestableControl>::findNearest;
111 :
112 1564 : StatementKind kind() const {
113 1564 : return kind_;
114 : }
115 :
116 1912 : EmitterScope* emitterScope() const {
117 1912 : return emitterScope_;
118 : }
119 :
120 : template <typename T>
121 : bool is() const;
122 :
123 : template <typename T>
124 2806 : T& as() {
125 2806 : MOZ_ASSERT(this->is<T>());
126 2806 : return static_cast<T&>(*this);
127 : }
128 : };
129 :
130 : // Template specializations are disallowed in different namespaces; specialize
131 : // all the NestableControl subtypes up front.
132 : namespace js {
133 : namespace frontend {
134 :
135 : template <>
136 : bool
137 2726 : BytecodeEmitter::NestableControl::is<BreakableControl>() const
138 : {
139 2726 : return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
140 : }
141 :
142 : template <>
143 : bool
144 4177 : BytecodeEmitter::NestableControl::is<LabelControl>() const
145 : {
146 4177 : return kind_ == StatementKind::Label;
147 : }
148 :
149 : template <>
150 : bool
151 2731 : BytecodeEmitter::NestableControl::is<LoopControl>() const
152 : {
153 2731 : return StatementKindIsLoop(kind_);
154 : }
155 :
156 : template <>
157 : bool
158 536 : BytecodeEmitter::NestableControl::is<ForOfLoopControl>() const
159 : {
160 536 : return kind_ == StatementKind::ForOfLoop;
161 : }
162 :
163 : template <>
164 : bool
165 972 : BytecodeEmitter::NestableControl::is<TryFinallyControl>() const
166 : {
167 972 : return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
168 : }
169 :
170 : } // namespace frontend
171 : } // namespace js
172 :
173 1284 : class BreakableControl : public BytecodeEmitter::NestableControl
174 : {
175 : public:
176 : // Offset of the last break.
177 : JumpList breaks;
178 :
179 1284 : BreakableControl(BytecodeEmitter* bce, StatementKind kind)
180 1284 : : NestableControl(bce, kind)
181 : {
182 1284 : MOZ_ASSERT(is<BreakableControl>());
183 1284 : }
184 :
185 1226 : MOZ_MUST_USE bool patchBreaks(BytecodeEmitter* bce) {
186 1226 : return bce->emitJumpTargetAndPatch(breaks);
187 : }
188 : };
189 :
190 0 : class LabelControl : public BreakableControl
191 : {
192 : RootedAtom label_;
193 :
194 : // The code offset when this was pushed. Used for effectfulness checking.
195 : ptrdiff_t startOffset_;
196 :
197 : public:
198 0 : LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
199 0 : : BreakableControl(bce, StatementKind::Label),
200 : label_(bce->cx, label),
201 0 : startOffset_(startOffset)
202 0 : { }
203 :
204 0 : HandleAtom label() const {
205 0 : return label_;
206 : }
207 :
208 0 : ptrdiff_t startOffset() const {
209 0 : return startOffset_;
210 : }
211 : };
212 :
213 1074 : class LoopControl : public BreakableControl
214 : {
215 : // Loops' children are emitted in dominance order, so they can always
216 : // have a TDZCheckCache.
217 : BytecodeEmitter::TDZCheckCache tdzCache_;
218 :
219 : // Stack depth when this loop was pushed on the control stack.
220 : int32_t stackDepth_;
221 :
222 : // The loop nesting depth. Used as a hint to Ion.
223 : uint32_t loopDepth_;
224 :
225 : // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
226 : bool canIonOsr_;
227 :
228 : public:
229 : // The target of continue statement jumps, e.g., the update portion of a
230 : // for(;;) loop.
231 : JumpTarget continueTarget;
232 :
233 : // Offset of the last continue in the loop.
234 : JumpList continues;
235 :
236 1074 : LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
237 1074 : : BreakableControl(bce, loopKind),
238 : tdzCache_(bce),
239 1074 : continueTarget({ -1 })
240 : {
241 1074 : MOZ_ASSERT(is<LoopControl>());
242 :
243 1074 : LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
244 :
245 1074 : stackDepth_ = bce->stackDepth;
246 1074 : loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
247 :
248 : int loopSlots;
249 1074 : if (loopKind == StatementKind::Spread)
250 58 : loopSlots = 3;
251 1016 : else if (loopKind == StatementKind::ForInLoop || loopKind == StatementKind::ForOfLoop)
252 372 : loopSlots = 2;
253 : else
254 644 : loopSlots = 0;
255 :
256 1074 : MOZ_ASSERT(loopSlots <= stackDepth_);
257 :
258 1074 : if (enclosingLoop) {
259 180 : canIonOsr_ = (enclosingLoop->canIonOsr_ &&
260 90 : stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
261 : } else {
262 984 : canIonOsr_ = stackDepth_ == loopSlots;
263 : }
264 1074 : }
265 :
266 2148 : uint32_t loopDepth() const {
267 2148 : return loopDepth_;
268 : }
269 :
270 1074 : bool canIonOsr() const {
271 1074 : return canIonOsr_;
272 : }
273 :
274 336 : MOZ_MUST_USE bool emitSpecialBreakForDone(BytecodeEmitter* bce) {
275 : // This doesn't pop stack values, nor handle any other controls.
276 : // Should be called on the toplevel of the loop.
277 336 : MOZ_ASSERT(bce->stackDepth == stackDepth_);
278 336 : MOZ_ASSERT(bce->innermostNestableControl == this);
279 :
280 336 : if (!bce->newSrcNote(SRC_BREAK))
281 0 : return false;
282 336 : if (!bce->emitJump(JSOP_GOTO, &breaks))
283 0 : return false;
284 :
285 336 : return true;
286 : }
287 :
288 1016 : MOZ_MUST_USE bool patchBreaksAndContinues(BytecodeEmitter* bce) {
289 1016 : MOZ_ASSERT(continueTarget.offset != -1);
290 1016 : if (!patchBreaks(bce))
291 0 : return false;
292 1016 : bce->patchJumpsToTarget(continues, continueTarget);
293 1016 : return true;
294 : }
295 : };
296 :
297 489 : class TryFinallyControl : public BytecodeEmitter::NestableControl
298 : {
299 : bool emittingSubroutine_;
300 :
301 : public:
302 : // The subroutine when emitting a finally block.
303 : JumpList gosubs;
304 :
305 : // Offset of the last catch guard, if any.
306 : JumpList guardJump;
307 :
308 489 : TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
309 489 : : NestableControl(bce, kind),
310 489 : emittingSubroutine_(false)
311 : {
312 489 : MOZ_ASSERT(is<TryFinallyControl>());
313 489 : }
314 :
315 41 : void setEmittingSubroutine() {
316 41 : emittingSubroutine_ = true;
317 41 : }
318 :
319 16 : bool emittingSubroutine() const {
320 16 : return emittingSubroutine_;
321 : }
322 : };
323 :
324 : static inline void
325 250 : MarkAllBindingsClosedOver(LexicalScope::Data& data)
326 : {
327 250 : BindingName* names = data.names;
328 638 : for (uint32_t i = 0; i < data.length; i++)
329 388 : names[i] = BindingName(names[i].name(), true);
330 250 : }
331 :
332 : // A scope that introduces bindings.
333 9111 : class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterScope>
334 : {
335 : // The cache of bound names that may be looked up in the
336 : // scope. Initially populated as the set of names this scope binds. As
337 : // names are looked up in enclosing scopes, they are cached on the
338 : // current scope.
339 : PooledMapPtr<NameLocationMap> nameCache_;
340 :
341 : // If this scope's cache does not include free names, such as the
342 : // global scope, the NameLocation to return.
343 : Maybe<NameLocation> fallbackFreeNameLocation_;
344 :
345 : // True if there is a corresponding EnvironmentObject on the environment
346 : // chain, false if all bindings are stored in frame slots on the stack.
347 : bool hasEnvironment_;
348 :
349 : // The number of enclosing environments. Used for error checking.
350 : uint8_t environmentChainLength_;
351 :
352 : // The next usable slot on the frame for not-closed over bindings.
353 : //
354 : // The initial frame slot when assigning slots to bindings is the
355 : // enclosing scope's nextFrameSlot. For the first scope in a frame,
356 : // the initial frame slot is 0.
357 : uint32_t nextFrameSlot_;
358 :
359 : // The index in the BytecodeEmitter's interned scope vector, otherwise
360 : // ScopeNote::NoScopeIndex.
361 : uint32_t scopeIndex_;
362 :
363 : // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
364 : // block scope note list. Otherwise ScopeNote::NoScopeNote.
365 : uint32_t noteIndex_;
366 :
367 9108 : MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce) {
368 9108 : return nameCache_.acquire(bce->cx);
369 : }
370 :
371 : template <typename BindingIter>
372 18033 : MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi) {
373 36066 : if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
374 18033 : bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT)
375 : {
376 0 : bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
377 0 : return false;
378 : }
379 18033 : return true;
380 : }
381 :
382 8840 : MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce) {
383 : uint32_t hops;
384 8840 : if (EmitterScope* emitterScope = enclosing(&bce))
385 7418 : hops = emitterScope->environmentChainLength_;
386 : else
387 1422 : hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
388 :
389 8840 : if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
390 0 : bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
391 0 : return false;
392 : }
393 :
394 8840 : environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
395 8840 : return true;
396 : }
397 :
398 7669 : void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi) {
399 7669 : nextFrameSlot_ = bi.nextFrameSlot();
400 7669 : if (nextFrameSlot_ > bce->maxFixedSlots)
401 4996 : bce->maxFixedSlots = nextFrameSlot_;
402 7669 : MOZ_ASSERT_IF(bce->sc->isFunctionBox() &&
403 : (bce->sc->asFunctionBox()->isStarGenerator() ||
404 : bce->sc->asFunctionBox()->isLegacyGenerator() ||
405 : bce->sc->asFunctionBox()->isAsync()),
406 : bce->maxFixedSlots == 0);
407 7669 : }
408 :
409 27447 : MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, JSAtom* name, NameLocation loc) {
410 27447 : NameLocationMap& cache = *nameCache_;
411 27447 : NameLocationMap::AddPtr p = cache.lookupForAdd(name);
412 27447 : MOZ_ASSERT(!p);
413 27447 : if (!cache.add(p, name, loc)) {
414 0 : ReportOutOfMemory(bce->cx);
415 0 : return false;
416 : }
417 27447 : return true;
418 : }
419 :
420 117916 : Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce, JSAtom* name) {
421 117916 : if (NameLocationMap::Ptr p = nameCache_->lookup(name))
422 75959 : return Some(p->value().wrapped);
423 41957 : if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name))
424 11523 : return fallbackFreeNameLocation_;
425 30434 : return Nothing();
426 : }
427 :
428 : friend bool BytecodeEmitter::needsImplicitThis();
429 :
430 48382 : EmitterScope* enclosing(BytecodeEmitter** bce) const {
431 : // There is an enclosing scope with access to the same frame.
432 48382 : if (EmitterScope* inFrame = enclosingInFrame())
433 22058 : return inFrame;
434 :
435 : // We are currently compiling the enclosing script, look in the
436 : // enclosing BCE.
437 26324 : if ((*bce)->parent) {
438 20737 : *bce = (*bce)->parent;
439 20737 : return (*bce)->innermostEmitterScope;
440 : }
441 :
442 5587 : return nullptr;
443 : }
444 :
445 9108 : Scope* enclosingScope(BytecodeEmitter* bce) const {
446 9108 : if (EmitterScope* es = enclosing(&bce))
447 7418 : return es->scope(bce);
448 :
449 : // The enclosing script is already compiled or the current script is the
450 : // global script.
451 1690 : return bce->sc->compilationEnclosingScope();
452 : }
453 :
454 11523 : static bool nameCanBeFree(BytecodeEmitter* bce, JSAtom* name) {
455 : // '.generator' cannot be accessed by name.
456 11523 : return name != bce->cx->names().dotGenerator;
457 : }
458 :
459 : static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops);
460 : NameLocation searchAndCache(BytecodeEmitter* bce, JSAtom* name);
461 :
462 : template <typename ScopeCreator>
463 : MOZ_MUST_USE bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
464 : template <typename ScopeCreator>
465 : MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope);
466 : MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
467 :
468 : MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
469 : uint32_t slotEnd);
470 :
471 : public:
472 9108 : explicit EmitterScope(BytecodeEmitter* bce)
473 9108 : : Nestable<EmitterScope>(&bce->innermostEmitterScope),
474 9108 : nameCache_(bce->cx->frontendCollectionPool()),
475 : hasEnvironment_(false),
476 : environmentChainLength_(0),
477 : nextFrameSlot_(0),
478 : scopeIndex_(ScopeNote::NoScopeIndex),
479 18216 : noteIndex_(ScopeNote::NoScopeNoteIndex)
480 9108 : { }
481 :
482 : void dump(BytecodeEmitter* bce);
483 :
484 : MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
485 : Handle<LexicalScope::Data*> bindings);
486 : MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
487 : MOZ_MUST_USE bool enterComprehensionFor(BytecodeEmitter* bce,
488 : Handle<LexicalScope::Data*> bindings);
489 : MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
490 : MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox);
491 : MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
492 : MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc);
493 : MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
494 : MOZ_MUST_USE bool enterModule(BytecodeEmitter* module, ModuleSharedContext* modulesc);
495 : MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce);
496 : MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce);
497 :
498 : MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false);
499 :
500 31964 : uint32_t index() const {
501 31964 : MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, "Did you forget to intern a Scope?");
502 31964 : return scopeIndex_;
503 : }
504 :
505 9809 : uint32_t noteIndex() const {
506 9809 : return noteIndex_;
507 : }
508 :
509 26399 : Scope* scope(const BytecodeEmitter* bce) const {
510 26399 : return bce->scopeList.vector[index()];
511 : }
512 :
513 39414 : bool hasEnvironment() const {
514 39414 : return hasEnvironment_;
515 : }
516 :
517 : // The first frame slot used.
518 3396 : uint32_t frameSlotStart() const {
519 3396 : if (EmitterScope* inFrame = enclosingInFrame())
520 3396 : return inFrame->nextFrameSlot_;
521 0 : return 0;
522 : }
523 :
524 : // The last frame slot used + 1.
525 3292 : uint32_t frameSlotEnd() const {
526 3292 : return nextFrameSlot_;
527 : }
528 :
529 : uint32_t numFrameSlots() const {
530 : return frameSlotEnd() - frameSlotStart();
531 : }
532 :
533 98496 : EmitterScope* enclosingInFrame() const {
534 98496 : return Nestable<EmitterScope>::enclosing();
535 : }
536 :
537 89957 : NameLocation lookup(BytecodeEmitter* bce, JSAtom* name) {
538 110002 : if (Maybe<NameLocation> loc = lookupInCache(bce, name))
539 69912 : return *loc;
540 20045 : return searchAndCache(bce, name);
541 : }
542 :
543 : Maybe<NameLocation> locationBoundInScope(BytecodeEmitter* bce, JSAtom* name,
544 : EmitterScope* target);
545 : };
546 :
547 : void
548 0 : BytecodeEmitter::EmitterScope::dump(BytecodeEmitter* bce)
549 : {
550 0 : fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce)->kind()), this);
551 :
552 0 : for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
553 0 : const NameLocation& l = r.front().value();
554 :
555 0 : JSAutoByteString bytes;
556 0 : if (!AtomToPrintableString(bce->cx, r.front().key(), &bytes))
557 0 : return;
558 0 : if (l.kind() != NameLocation::Kind::Dynamic)
559 0 : fprintf(stdout, " %s %s ", BindingKindString(l.bindingKind()), bytes.ptr());
560 : else
561 0 : fprintf(stdout, " %s ", bytes.ptr());
562 :
563 0 : switch (l.kind()) {
564 : case NameLocation::Kind::Dynamic:
565 0 : fprintf(stdout, "dynamic\n");
566 0 : break;
567 : case NameLocation::Kind::Global:
568 0 : fprintf(stdout, "global\n");
569 0 : break;
570 : case NameLocation::Kind::Intrinsic:
571 0 : fprintf(stdout, "intrinsic\n");
572 0 : break;
573 : case NameLocation::Kind::NamedLambdaCallee:
574 0 : fprintf(stdout, "named lambda callee\n");
575 0 : break;
576 : case NameLocation::Kind::Import:
577 0 : fprintf(stdout, "import\n");
578 0 : break;
579 : case NameLocation::Kind::ArgumentSlot:
580 0 : fprintf(stdout, "arg slot=%u\n", l.argumentSlot());
581 0 : break;
582 : case NameLocation::Kind::FrameSlot:
583 0 : fprintf(stdout, "frame slot=%u\n", l.frameSlot());
584 0 : break;
585 : case NameLocation::Kind::EnvironmentCoordinate:
586 0 : fprintf(stdout, "environment hops=%u slot=%u\n",
587 0 : l.environmentCoordinate().hops(), l.environmentCoordinate().slot());
588 0 : break;
589 : case NameLocation::Kind::DynamicAnnexBVar:
590 0 : fprintf(stdout, "dynamic annex b var\n");
591 0 : break;
592 : }
593 : }
594 :
595 0 : fprintf(stdout, "\n");
596 : }
597 :
598 : template <typename ScopeCreator>
599 : bool
600 9108 : BytecodeEmitter::EmitterScope::internScope(BytecodeEmitter* bce, ScopeCreator createScope)
601 : {
602 18216 : RootedScope enclosing(bce->cx, enclosingScope(bce));
603 9108 : Scope* scope = createScope(bce->cx, enclosing);
604 9108 : if (!scope)
605 0 : return false;
606 9108 : hasEnvironment_ = scope->hasEnvironment();
607 9108 : scopeIndex_ = bce->scopeList.length();
608 9108 : return bce->scopeList.append(scope);
609 : }
610 :
611 : template <typename ScopeCreator>
612 : bool
613 5672 : BytecodeEmitter::EmitterScope::internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope)
614 : {
615 5672 : MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX, "There can be only one body scope");
616 5672 : bce->bodyScopeIndex = bce->scopeList.length();
617 5672 : return internScope(bce, createScope);
618 : }
619 :
620 : bool
621 3045 : BytecodeEmitter::EmitterScope::appendScopeNote(BytecodeEmitter* bce)
622 : {
623 3045 : MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),
624 : "Scope notes are not needed for body-level scopes.");
625 3045 : noteIndex_ = bce->scopeNoteList.length();
626 6090 : return bce->scopeNoteList.append(index(), bce->offset(), bce->inPrologue(),
627 6090 : enclosingInFrame() ? enclosingInFrame()->noteIndex()
628 3045 : : ScopeNote::NoScopeNoteIndex);
629 : }
630 :
631 : #ifdef DEBUG
632 : static bool
633 3393 : NameIsOnEnvironment(Scope* scope, JSAtom* name)
634 : {
635 32001 : for (BindingIter bi(scope); bi; bi++) {
636 : // If found, the name must already be on the environment or an import,
637 : // or else there is a bug in the closed-over name analysis in the
638 : // Parser.
639 29998 : if (bi.name() == name) {
640 1390 : BindingLocation::Kind kind = bi.location().kind();
641 :
642 1390 : if (bi.hasArgumentSlot()) {
643 156 : JSScript* script = scope->as<FunctionScope>().script();
644 156 : if (!script->strict() && !script->functionHasParameterExprs()) {
645 : // Check for duplicate positional formal parameters.
646 174 : for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
647 115 : if (bi2.name() == name)
648 59 : kind = bi2.location().kind();
649 : }
650 : }
651 : }
652 :
653 482 : return kind == BindingLocation::Kind::Global ||
654 1390 : kind == BindingLocation::Kind::Environment ||
655 1390 : kind == BindingLocation::Kind::Import;
656 : }
657 : }
658 :
659 : // If not found, assume it's on the global or dynamically accessed.
660 2003 : return true;
661 : }
662 : #endif
663 :
664 : /* static */ NameLocation
665 2475 : BytecodeEmitter::EmitterScope::searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops)
666 : {
667 3393 : for (ScopeIter si(scope); si; si++) {
668 3393 : MOZ_ASSERT(NameIsOnEnvironment(si.scope(), name));
669 :
670 3393 : bool hasEnv = si.hasSyntacticEnvironment();
671 :
672 3393 : switch (si.kind()) {
673 : case ScopeKind::Function:
674 621 : if (hasEnv) {
675 485 : JSScript* script = si.scope()->as<FunctionScope>().script();
676 485 : if (script->funHasExtensibleScope())
677 2475 : return NameLocation::Dynamic();
678 :
679 1413 : for (BindingIter bi(si.scope()); bi; bi++) {
680 1247 : if (bi.name() != name)
681 928 : continue;
682 :
683 319 : BindingLocation bindLoc = bi.location();
684 794 : if (bi.hasArgumentSlot() &&
685 378 : !script->strict() &&
686 59 : !script->functionHasParameterExprs())
687 : {
688 : // Check for duplicate positional formal parameters.
689 174 : for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
690 115 : if (bi2.name() == name)
691 59 : bindLoc = bi2.location();
692 : }
693 : }
694 :
695 319 : MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
696 319 : return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
697 : }
698 : }
699 302 : break;
700 :
701 : case ScopeKind::FunctionBodyVar:
702 : case ScopeKind::ParameterExpressionVar:
703 : case ScopeKind::Lexical:
704 : case ScopeKind::NamedLambda:
705 : case ScopeKind::StrictNamedLambda:
706 : case ScopeKind::SimpleCatch:
707 : case ScopeKind::Catch:
708 763 : if (hasEnv) {
709 1208 : for (BindingIter bi(si.scope()); bi; bi++) {
710 940 : if (bi.name() != name)
711 793 : continue;
712 :
713 : // The name must already have been marked as closed
714 : // over. If this assertion is hit, there is a bug in the
715 : // name analysis.
716 147 : BindingLocation bindLoc = bi.location();
717 147 : MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
718 147 : return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
719 : }
720 : }
721 616 : break;
722 :
723 : case ScopeKind::Module:
724 0 : if (hasEnv) {
725 0 : for (BindingIter bi(si.scope()); bi; bi++) {
726 0 : if (bi.name() != name)
727 0 : continue;
728 :
729 0 : BindingLocation bindLoc = bi.location();
730 :
731 : // Imports are on the environment but are indirect
732 : // bindings and must be accessed dynamically instead of
733 : // using an EnvironmentCoordinate.
734 0 : if (bindLoc.kind() == BindingLocation::Kind::Import) {
735 0 : MOZ_ASSERT(si.kind() == ScopeKind::Module);
736 0 : return NameLocation::Import();
737 : }
738 :
739 0 : MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
740 0 : return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
741 : }
742 : }
743 0 : break;
744 :
745 : case ScopeKind::Eval:
746 : case ScopeKind::StrictEval:
747 : // As an optimization, if the eval doesn't have its own var
748 : // environment and its immediate enclosing scope is a global
749 : // scope, all accesses are global.
750 30 : if (!hasEnv && si.scope()->enclosing()->is<GlobalScope>())
751 0 : return NameLocation::Global(BindingKind::Var);
752 30 : return NameLocation::Dynamic();
753 :
754 : case ScopeKind::Global:
755 1349 : return NameLocation::Global(BindingKind::Var);
756 :
757 : case ScopeKind::With:
758 : case ScopeKind::NonSyntactic:
759 630 : return NameLocation::Dynamic();
760 :
761 : case ScopeKind::WasmFunction:
762 0 : MOZ_CRASH("No direct eval inside wasm functions");
763 : }
764 :
765 918 : if (hasEnv) {
766 434 : MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
767 434 : hops++;
768 : }
769 : }
770 :
771 0 : MOZ_CRASH("Malformed scope chain");
772 : }
773 :
774 : NameLocation
775 20045 : BytecodeEmitter::EmitterScope::searchAndCache(BytecodeEmitter* bce, JSAtom* name)
776 : {
777 40090 : Maybe<NameLocation> loc;
778 20045 : uint8_t hops = hasEnvironment() ? 1 : 0;
779 40090 : DebugOnly<bool> inCurrentScript = enclosingInFrame();
780 :
781 : // Start searching in the current compilation.
782 30434 : for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) {
783 27959 : loc = es->lookupInCache(bce, name);
784 27959 : if (loc) {
785 17570 : if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate)
786 1735 : *loc = loc->addHops(hops);
787 17570 : break;
788 : }
789 :
790 10389 : if (es->hasEnvironment())
791 2722 : hops++;
792 :
793 : #ifdef DEBUG
794 10389 : if (!es->enclosingInFrame())
795 6338 : inCurrentScript = false;
796 : #endif
797 : }
798 :
799 : // If the name is not found in the current compilation, walk the Scope
800 : // chain encompassing the compilation.
801 20045 : if (!loc) {
802 2475 : inCurrentScript = false;
803 2475 : loc = Some(searchInEnclosingScope(name, bce->sc->compilationEnclosingScope(), hops));
804 : }
805 :
806 : // Each script has its own frame. A free name that is accessed
807 : // from an inner script must not be a frame slot access. If this
808 : // assertion is hit, it is a bug in the free name analysis in the
809 : // parser.
810 20045 : MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot);
811 :
812 : // It is always correct to not cache the location. Ignore OOMs to make
813 : // lookups infallible.
814 20045 : if (!putNameInCache(bce, name, *loc))
815 0 : bce->cx->recoverFromOutOfMemory();
816 :
817 40090 : return *loc;
818 : }
819 :
820 : Maybe<NameLocation>
821 7173 : BytecodeEmitter::EmitterScope::locationBoundInScope(BytecodeEmitter* bce, JSAtom* name,
822 : EmitterScope* target)
823 : {
824 : // The target scope must be an intra-frame enclosing scope of this
825 : // one. Count the number of extra hops to reach it.
826 7173 : uint8_t extraHops = 0;
827 7478 : for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
828 305 : if (es->hasEnvironment())
829 303 : extraHops++;
830 : }
831 :
832 : // Caches are prepopulated with bound names. So if the name is bound in a
833 : // particular scope, it must already be in the cache. Furthermore, don't
834 : // consult the fallback location as we only care about binding names.
835 7173 : Maybe<NameLocation> loc;
836 7173 : if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) {
837 6832 : NameLocation l = p->value().wrapped;
838 6832 : if (l.kind() == NameLocation::Kind::EnvironmentCoordinate)
839 980 : loc = Some(l.addHops(extraHops));
840 : else
841 5852 : loc = Some(l);
842 : }
843 7173 : return loc;
844 : }
845 :
846 : bool
847 3465 : BytecodeEmitter::EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
848 : uint32_t slotEnd)
849 : {
850 : // Lexical bindings throw ReferenceErrors if they are used before
851 : // initialization. See ES6 8.1.1.1.6.
852 : //
853 : // For completeness, lexical bindings are initialized in ES6 by calling
854 : // InitializeBinding, after which touching the binding will no longer
855 : // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
856 : // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
857 3465 : if (slotStart != slotEnd) {
858 3056 : if (!bce->emit1(JSOP_UNINITIALIZED))
859 0 : return false;
860 7763 : for (uint32_t slot = slotStart; slot < slotEnd; slot++) {
861 4707 : if (!bce->emitLocalOp(JSOP_INITLEXICAL, slot))
862 0 : return false;
863 : }
864 3056 : if (!bce->emit1(JSOP_POP))
865 0 : return false;
866 : }
867 :
868 3465 : return true;
869 : }
870 :
871 : bool
872 351 : BytecodeEmitter::EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce)
873 : {
874 351 : return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
875 : }
876 :
877 : bool
878 2941 : BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
879 : Handle<LexicalScope::Data*> bindings)
880 : {
881 2941 : MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
882 2941 : MOZ_ASSERT(this == bce->innermostEmitterScope);
883 :
884 2941 : if (!ensureCache(bce))
885 0 : return false;
886 :
887 : // Marks all names as closed over if the the context requires it. This
888 : // cannot be done in the Parser as we may not know if the context requires
889 : // all bindings to be closed over until after parsing is finished. For
890 : // example, legacy generators require all bindings to be closed over but
891 : // it is unknown if a function is a legacy generator until the first
892 : // 'yield' expression is parsed.
893 : //
894 : // This is not a problem with other scopes, as all other scopes with
895 : // bindings are body-level. At the time of their creation, whether or not
896 : // the context requires all bindings to be closed over is already known.
897 2941 : if (bce->sc->allBindingsClosedOver())
898 245 : MarkAllBindingsClosedOver(*bindings);
899 :
900 : // Resolve bindings.
901 2941 : TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
902 2941 : uint32_t firstFrameSlot = frameSlotStart();
903 2941 : BindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false);
904 12227 : for (; bi; bi++) {
905 4643 : if (!checkSlotLimits(bce, bi))
906 0 : return false;
907 :
908 4643 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
909 4643 : if (!putNameInCache(bce, bi.name(), loc))
910 0 : return false;
911 :
912 4643 : if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
913 0 : return false;
914 : }
915 :
916 2941 : updateFrameFixedSlots(bce, bi);
917 :
918 : // Create and intern the VM scope.
919 : auto createScope = [kind, bindings, firstFrameSlot](JSContext* cx,
920 2941 : HandleScope enclosing)
921 2941 : {
922 : return LexicalScope::create(cx, kind, bindings, firstFrameSlot, enclosing);
923 5882 : };
924 2941 : if (!internScope(bce, createScope))
925 0 : return false;
926 :
927 2941 : if (ScopeKindIsInBody(kind) && hasEnvironment()) {
928 : // After interning the VM scope we can get the scope index.
929 453 : if (!bce->emitInternedScopeOp(index(), JSOP_PUSHLEXICALENV))
930 0 : return false;
931 : }
932 :
933 : // Lexical scopes need notes to be mapped from a pc.
934 2941 : if (!appendScopeNote(bce))
935 0 : return false;
936 :
937 : // Put frame slots in TDZ. Environment slots are poisoned during
938 : // environment creation.
939 : //
940 : // This must be done after appendScopeNote to be considered in the extent
941 : // of the scope.
942 2941 : if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd()))
943 0 : return false;
944 :
945 2941 : return checkEnvironmentChainLength(bce);
946 : }
947 :
948 : bool
949 391 : BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
950 : {
951 391 : MOZ_ASSERT(this == bce->innermostEmitterScope);
952 391 : MOZ_ASSERT(funbox->namedLambdaBindings());
953 :
954 391 : if (!ensureCache(bce))
955 0 : return false;
956 :
957 : // See comment in enterLexical about allBindingsClosedOver.
958 391 : if (funbox->allBindingsClosedOver())
959 5 : MarkAllBindingsClosedOver(*funbox->namedLambdaBindings());
960 :
961 391 : BindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT, /* isNamedLambda = */ true);
962 391 : MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee);
963 :
964 : // The lambda name, if not closed over, is accessed via JSOP_CALLEE and
965 : // not a frame slot. Do not update frame slot information.
966 391 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
967 391 : if (!putNameInCache(bce, bi.name(), loc))
968 0 : return false;
969 :
970 391 : bi++;
971 391 : MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope");
972 :
973 782 : auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
974 : ScopeKind scopeKind =
975 391 : funbox->strict() ? ScopeKind::StrictNamedLambda : ScopeKind::NamedLambda;
976 782 : return LexicalScope::create(cx, scopeKind, funbox->namedLambdaBindings(),
977 782 : LOCALNO_LIMIT, enclosing);
978 391 : };
979 391 : if (!internScope(bce, createScope))
980 0 : return false;
981 :
982 391 : return checkEnvironmentChainLength(bce);
983 : }
984 :
985 : bool
986 0 : BytecodeEmitter::EmitterScope::enterComprehensionFor(BytecodeEmitter* bce,
987 : Handle<LexicalScope::Data*> bindings)
988 : {
989 0 : if (!enterLexical(bce, ScopeKind::Lexical, bindings))
990 0 : return false;
991 :
992 : // For comprehensions, initialize all lexical names up front to undefined
993 : // because they're now a dead feature and don't interact properly with
994 : // TDZ.
995 0 : auto nop = [](BytecodeEmitter*, const NameLocation&, bool) {
996 : return true;
997 0 : };
998 :
999 0 : if (!bce->emit1(JSOP_UNDEFINED))
1000 0 : return false;
1001 :
1002 0 : RootedAtom name(bce->cx);
1003 0 : for (BindingIter bi(*bindings, frameSlotStart(), /* isNamedLambda = */ false); bi; bi++) {
1004 0 : name = bi.name();
1005 0 : if (!bce->emitInitializeName(name, nop))
1006 0 : return false;
1007 : }
1008 :
1009 0 : if (!bce->emit1(JSOP_POP))
1010 0 : return false;
1011 :
1012 0 : return true;
1013 : }
1014 :
1015 : bool
1016 0 : BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
1017 : {
1018 0 : MOZ_ASSERT(this == bce->innermostEmitterScope);
1019 :
1020 0 : if (!ensureCache(bce))
1021 0 : return false;
1022 :
1023 : // Parameter expressions var scopes have no pre-set bindings and are
1024 : // always extensible, as they are needed for eval.
1025 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1026 :
1027 : // Create and intern the VM scope.
1028 0 : uint32_t firstFrameSlot = frameSlotStart();
1029 0 : auto createScope = [firstFrameSlot](JSContext* cx, HandleScope enclosing) {
1030 0 : return VarScope::create(cx, ScopeKind::ParameterExpressionVar,
1031 : /* data = */ nullptr, firstFrameSlot,
1032 : /* needsEnvironment = */ true, enclosing);
1033 0 : };
1034 0 : if (!internScope(bce, createScope))
1035 0 : return false;
1036 :
1037 0 : MOZ_ASSERT(hasEnvironment());
1038 0 : if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1039 0 : return false;
1040 :
1041 : // The extra var scope needs a note to be mapped from a pc.
1042 0 : if (!appendScopeNote(bce))
1043 0 : return false;
1044 :
1045 0 : return checkEnvironmentChainLength(bce);
1046 : }
1047 :
1048 : bool
1049 5404 : BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
1050 : {
1051 5404 : MOZ_ASSERT(this == bce->innermostEmitterScope);
1052 :
1053 : // If there are parameter expressions, there is an extra var scope.
1054 5404 : if (!funbox->hasExtraBodyVarScope())
1055 5300 : bce->setVarEmitterScope(this);
1056 :
1057 5404 : if (!ensureCache(bce))
1058 0 : return false;
1059 :
1060 : // Resolve body-level bindings, if there are any.
1061 5404 : auto bindings = funbox->functionScopeBindings();
1062 10808 : Maybe<uint32_t> lastLexicalSlot;
1063 5404 : if (bindings) {
1064 4624 : NameLocationMap& cache = *nameCache_;
1065 :
1066 4624 : BindingIter bi(*bindings, funbox->hasParameterExprs);
1067 30516 : for (; bi; bi++) {
1068 12946 : if (!checkSlotLimits(bce, bi))
1069 0 : return false;
1070 :
1071 12946 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1072 12946 : NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
1073 :
1074 : // The only duplicate bindings that occur are simple formal
1075 : // parameters, in which case the last position counts, so update the
1076 : // location.
1077 12946 : if (p) {
1078 0 : MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
1079 0 : MOZ_ASSERT(!funbox->hasDestructuringArgs);
1080 0 : MOZ_ASSERT(!funbox->hasRest());
1081 0 : p->value() = loc;
1082 0 : continue;
1083 : }
1084 :
1085 12946 : if (!cache.add(p, bi.name(), loc)) {
1086 0 : ReportOutOfMemory(bce->cx);
1087 0 : return false;
1088 : }
1089 : }
1090 :
1091 4624 : updateFrameFixedSlots(bce, bi);
1092 : } else {
1093 780 : nextFrameSlot_ = 0;
1094 : }
1095 :
1096 : // If the function's scope may be extended at runtime due to sloppy direct
1097 : // eval and there is no extra var scope, any names beyond the function
1098 : // scope must be accessed dynamically as we don't know if the name will
1099 : // become a 'var' binding due to direct eval.
1100 5404 : if (!funbox->hasParameterExprs && funbox->hasExtensibleScope())
1101 2 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1102 :
1103 : // In case of parameter expressions, the parameters are lexical
1104 : // bindings and have TDZ.
1105 5404 : if (funbox->hasParameterExprs && nextFrameSlot_) {
1106 173 : uint32_t paramFrameSlotEnd = 0;
1107 592 : for (BindingIter bi(*bindings, true); bi; bi++) {
1108 532 : if (!BindingKindIsLexical(bi.kind()))
1109 113 : break;
1110 :
1111 419 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1112 419 : if (loc.kind() == NameLocation::Kind::FrameSlot) {
1113 394 : MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot());
1114 394 : paramFrameSlotEnd = loc.frameSlot() + 1;
1115 : }
1116 : }
1117 :
1118 173 : if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd))
1119 0 : return false;
1120 : }
1121 :
1122 : // Create and intern the VM scope.
1123 21616 : auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
1124 10808 : RootedFunction fun(cx, funbox->function());
1125 27020 : return FunctionScope::create(cx, funbox->functionScopeBindings(),
1126 5404 : funbox->hasParameterExprs,
1127 5404 : funbox->needsCallObjectRegardlessOfBindings(),
1128 10808 : fun, enclosing);
1129 5404 : };
1130 5404 : if (!internBodyScope(bce, createScope))
1131 0 : return false;
1132 :
1133 5404 : return checkEnvironmentChainLength(bce);
1134 : }
1135 :
1136 : bool
1137 104 : BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox)
1138 : {
1139 104 : MOZ_ASSERT(funbox->hasParameterExprs);
1140 104 : MOZ_ASSERT(funbox->extraVarScopeBindings() ||
1141 : funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
1142 104 : MOZ_ASSERT(this == bce->innermostEmitterScope);
1143 :
1144 : // The extra var scope is never popped once it's entered. It replaces the
1145 : // function scope as the var emitter scope.
1146 104 : bce->setVarEmitterScope(this);
1147 :
1148 104 : if (!ensureCache(bce))
1149 0 : return false;
1150 :
1151 : // Resolve body-level bindings, if there are any.
1152 104 : uint32_t firstFrameSlot = frameSlotStart();
1153 104 : if (auto bindings = funbox->extraVarScopeBindings()) {
1154 104 : BindingIter bi(*bindings, firstFrameSlot);
1155 992 : for (; bi; bi++) {
1156 444 : if (!checkSlotLimits(bce, bi))
1157 0 : return false;
1158 :
1159 444 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1160 444 : if (!putNameInCache(bce, bi.name(), loc))
1161 0 : return false;
1162 : }
1163 :
1164 104 : updateFrameFixedSlots(bce, bi);
1165 : } else {
1166 0 : nextFrameSlot_ = firstFrameSlot;
1167 : }
1168 :
1169 : // If the extra var scope may be extended at runtime due to sloppy
1170 : // direct eval, any names beyond the var scope must be accessed
1171 : // dynamically as we don't know if the name will become a 'var' binding
1172 : // due to direct eval.
1173 104 : if (funbox->hasExtensibleScope())
1174 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1175 :
1176 : // Create and intern the VM scope.
1177 208 : auto createScope = [funbox, firstFrameSlot](JSContext* cx, HandleScope enclosing) {
1178 312 : return VarScope::create(cx, ScopeKind::FunctionBodyVar,
1179 : funbox->extraVarScopeBindings(), firstFrameSlot,
1180 104 : funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(),
1181 : enclosing);
1182 312 : };
1183 104 : if (!internScope(bce, createScope))
1184 0 : return false;
1185 :
1186 104 : if (hasEnvironment()) {
1187 10 : if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1188 0 : return false;
1189 : }
1190 :
1191 : // The extra var scope needs a note to be mapped from a pc.
1192 104 : if (!appendScopeNote(bce))
1193 0 : return false;
1194 :
1195 104 : return checkEnvironmentChainLength(bce);
1196 : }
1197 :
1198 : class DynamicBindingIter : public BindingIter
1199 : {
1200 : public:
1201 130 : explicit DynamicBindingIter(GlobalSharedContext* sc)
1202 130 : : BindingIter(*sc->bindings)
1203 130 : { }
1204 :
1205 0 : explicit DynamicBindingIter(EvalSharedContext* sc)
1206 0 : : BindingIter(*sc->bindings, /* strict = */ false)
1207 : {
1208 0 : MOZ_ASSERT(!sc->strict());
1209 0 : }
1210 :
1211 1474 : JSOp bindingOp() const {
1212 1474 : switch (kind()) {
1213 : case BindingKind::Var:
1214 304 : return JSOP_DEFVAR;
1215 : case BindingKind::Let:
1216 64 : return JSOP_DEFLET;
1217 : case BindingKind::Const:
1218 1106 : return JSOP_DEFCONST;
1219 : default:
1220 0 : MOZ_CRASH("Bad BindingKind");
1221 : }
1222 : }
1223 : };
1224 :
1225 : bool
1226 266 : BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
1227 : {
1228 266 : MOZ_ASSERT(this == bce->innermostEmitterScope);
1229 :
1230 266 : bce->setVarEmitterScope(this);
1231 :
1232 266 : if (!ensureCache(bce))
1233 0 : return false;
1234 :
1235 266 : if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
1236 : // In self-hosting, it is incorrect to consult the global scope because
1237 : // self-hosted scripts are cloned into their target compartments before
1238 : // they are run. Instead of Global, Intrinsic is used for all names.
1239 : //
1240 : // Intrinsic lookups are redirected to the special intrinsics holder
1241 : // in the global object, into which any missing values are cloned
1242 : // lazily upon first access.
1243 3 : fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic());
1244 :
1245 3 : auto createScope = [](JSContext* cx, HandleScope enclosing) {
1246 3 : MOZ_ASSERT(!enclosing);
1247 3 : return &cx->global()->emptyGlobalScope();
1248 : };
1249 3 : return internBodyScope(bce, createScope);
1250 : }
1251 :
1252 : // Resolve binding names and emit DEF{VAR,LET,CONST} prologue ops.
1253 263 : if (globalsc->bindings) {
1254 2054 : for (DynamicBindingIter bi(globalsc); bi; bi++) {
1255 1924 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1256 1924 : JSAtom* name = bi.name();
1257 1924 : if (!putNameInCache(bce, name, loc))
1258 0 : return false;
1259 :
1260 : // Define the name in the prologue. Do not emit DEFVAR for
1261 : // functions that we'll emit DEFFUN for.
1262 1924 : if (bi.isTopLevelFunction())
1263 450 : continue;
1264 :
1265 1474 : if (!bce->emitAtomOp(name, bi.bindingOp()))
1266 0 : return false;
1267 : }
1268 : }
1269 :
1270 : // Note that to save space, we don't add free names to the cache for
1271 : // global scopes. They are assumed to be global vars in the syntactic
1272 : // global scope, dynamic accesses under non-syntactic global scope.
1273 263 : if (globalsc->scopeKind() == ScopeKind::Global)
1274 124 : fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1275 : else
1276 139 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1277 :
1278 789 : auto createScope = [globalsc](JSContext* cx, HandleScope enclosing) {
1279 263 : MOZ_ASSERT(!enclosing);
1280 526 : return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
1281 263 : };
1282 263 : return internBodyScope(bce, createScope);
1283 : }
1284 :
1285 : bool
1286 2 : BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
1287 : {
1288 2 : MOZ_ASSERT(this == bce->innermostEmitterScope);
1289 :
1290 2 : bce->setVarEmitterScope(this);
1291 :
1292 2 : if (!ensureCache(bce))
1293 0 : return false;
1294 :
1295 : // For simplicity, treat all free name lookups in eval scripts as dynamic.
1296 2 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1297 :
1298 : // Create the `var` scope. Note that there is also a lexical scope, created
1299 : // separately in emitScript().
1300 4 : auto createScope = [evalsc](JSContext* cx, HandleScope enclosing) {
1301 2 : ScopeKind scopeKind = evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval;
1302 2 : return EvalScope::create(cx, scopeKind, evalsc->bindings, enclosing);
1303 2 : };
1304 2 : if (!internBodyScope(bce, createScope))
1305 0 : return false;
1306 :
1307 2 : if (hasEnvironment()) {
1308 2 : if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1309 0 : return false;
1310 : } else {
1311 : // Resolve binding names and emit DEFVAR prologue ops if we don't have
1312 : // an environment (i.e., a sloppy eval not in a parameter expression).
1313 : // Eval scripts always have their own lexical scope, but non-strict
1314 : // scopes may introduce 'var' bindings to the nearest var scope.
1315 : //
1316 : // TODO: We may optimize strict eval bindings in the future to be on
1317 : // the frame. For now, handle everything dynamically.
1318 0 : if (!hasEnvironment() && evalsc->bindings) {
1319 0 : for (DynamicBindingIter bi(evalsc); bi; bi++) {
1320 0 : MOZ_ASSERT(bi.bindingOp() == JSOP_DEFVAR);
1321 :
1322 0 : if (bi.isTopLevelFunction())
1323 0 : continue;
1324 :
1325 0 : if (!bce->emitAtomOp(bi.name(), JSOP_DEFVAR))
1326 0 : return false;
1327 : }
1328 : }
1329 :
1330 : // As an optimization, if the eval does not have its own var
1331 : // environment and is directly enclosed in a global scope, then all
1332 : // free name lookups are global.
1333 0 : if (scope(bce)->enclosing()->is<GlobalScope>())
1334 0 : fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1335 : }
1336 :
1337 2 : return true;
1338 : }
1339 :
1340 : bool
1341 0 : BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
1342 : {
1343 0 : MOZ_ASSERT(this == bce->innermostEmitterScope);
1344 :
1345 0 : bce->setVarEmitterScope(this);
1346 :
1347 0 : if (!ensureCache(bce))
1348 0 : return false;
1349 :
1350 : // Resolve body-level bindings, if there are any.
1351 0 : TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
1352 0 : Maybe<uint32_t> firstLexicalFrameSlot;
1353 0 : if (ModuleScope::Data* bindings = modulesc->bindings) {
1354 0 : BindingIter bi(*bindings);
1355 0 : for (; bi; bi++) {
1356 0 : if (!checkSlotLimits(bce, bi))
1357 0 : return false;
1358 :
1359 0 : NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1360 0 : if (!putNameInCache(bce, bi.name(), loc))
1361 0 : return false;
1362 :
1363 0 : if (BindingKindIsLexical(bi.kind())) {
1364 0 : if (loc.kind() == NameLocation::Kind::FrameSlot && !firstLexicalFrameSlot)
1365 0 : firstLexicalFrameSlot = Some(loc.frameSlot());
1366 :
1367 0 : if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
1368 0 : return false;
1369 : }
1370 : }
1371 :
1372 0 : updateFrameFixedSlots(bce, bi);
1373 : } else {
1374 0 : nextFrameSlot_ = 0;
1375 : }
1376 :
1377 : // Modules are toplevel, so any free names are global.
1378 0 : fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1379 :
1380 : // Put lexical frame slots in TDZ. Environment slots are poisoned during
1381 : // environment creation.
1382 0 : if (firstLexicalFrameSlot) {
1383 0 : if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd()))
1384 0 : return false;
1385 : }
1386 :
1387 : // Create and intern the VM scope.
1388 0 : auto createScope = [modulesc](JSContext* cx, HandleScope enclosing) {
1389 0 : return ModuleScope::create(cx, modulesc->bindings, modulesc->module(), enclosing);
1390 0 : };
1391 0 : if (!internBodyScope(bce, createScope))
1392 0 : return false;
1393 :
1394 0 : return checkEnvironmentChainLength(bce);
1395 : }
1396 :
1397 : bool
1398 0 : BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
1399 : {
1400 0 : MOZ_ASSERT(this == bce->innermostEmitterScope);
1401 :
1402 0 : if (!ensureCache(bce))
1403 0 : return false;
1404 :
1405 : // 'with' make all accesses dynamic and unanalyzable.
1406 0 : fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1407 :
1408 0 : auto createScope = [](JSContext* cx, HandleScope enclosing) {
1409 : return WithScope::create(cx, enclosing);
1410 0 : };
1411 0 : if (!internScope(bce, createScope))
1412 0 : return false;
1413 :
1414 0 : if (!bce->emitInternedScopeOp(index(), JSOP_ENTERWITH))
1415 0 : return false;
1416 :
1417 0 : if (!appendScopeNote(bce))
1418 0 : return false;
1419 :
1420 0 : return checkEnvironmentChainLength(bce);
1421 : }
1422 :
1423 : bool
1424 11166 : BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
1425 : {
1426 : // If we aren't leaving the scope due to a non-local jump (e.g., break),
1427 : // we must be the innermost scope.
1428 11166 : MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope);
1429 :
1430 11166 : ScopeKind kind = scope(bce)->kind();
1431 11166 : switch (kind) {
1432 : case ScopeKind::Lexical:
1433 : case ScopeKind::SimpleCatch:
1434 : case ScopeKind::Catch:
1435 4997 : if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV))
1436 0 : return false;
1437 4997 : break;
1438 :
1439 : case ScopeKind::With:
1440 0 : if (!bce->emit1(JSOP_LEAVEWITH))
1441 0 : return false;
1442 0 : break;
1443 :
1444 : case ScopeKind::ParameterExpressionVar:
1445 0 : MOZ_ASSERT(hasEnvironment());
1446 0 : if (!bce->emit1(JSOP_POPVARENV))
1447 0 : return false;
1448 0 : break;
1449 :
1450 : case ScopeKind::Function:
1451 : case ScopeKind::FunctionBodyVar:
1452 : case ScopeKind::NamedLambda:
1453 : case ScopeKind::StrictNamedLambda:
1454 : case ScopeKind::Eval:
1455 : case ScopeKind::StrictEval:
1456 : case ScopeKind::Global:
1457 : case ScopeKind::NonSyntactic:
1458 : case ScopeKind::Module:
1459 6169 : break;
1460 :
1461 : case ScopeKind::WasmFunction:
1462 0 : MOZ_CRASH("No wasm function scopes in JS");
1463 : }
1464 :
1465 : // Finish up the scope if we are leaving it in LIFO fashion.
1466 11166 : if (!nonLocal) {
1467 : // Popping scopes due to non-local jumps generate additional scope
1468 : // notes. See NonLocalExitControl::prepareForNonLocalJump.
1469 9111 : if (ScopeKindIsInBody(kind)) {
1470 : // The extra function var scope is never popped once it's pushed,
1471 : // so its scope note extends until the end of any possible code.
1472 3046 : uint32_t offset = kind == ScopeKind::FunctionBodyVar ? UINT32_MAX : bce->offset();
1473 3046 : bce->scopeNoteList.recordEnd(noteIndex_, offset, bce->inPrologue());
1474 : }
1475 : }
1476 :
1477 11166 : return true;
1478 : }
1479 :
1480 : Maybe<MaybeCheckTDZ>
1481 12738 : BytecodeEmitter::TDZCheckCache::needsTDZCheck(BytecodeEmitter* bce, JSAtom* name)
1482 : {
1483 12738 : if (!ensureCache(bce))
1484 0 : return Nothing();
1485 :
1486 12738 : CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
1487 12738 : if (p)
1488 5255 : return Some(p->value().wrapped);
1489 :
1490 7483 : MaybeCheckTDZ rv = CheckTDZ;
1491 16656 : for (TDZCheckCache* it = enclosing(); it; it = it->enclosing()) {
1492 16105 : if (it->cache_) {
1493 9567 : if (CheckTDZMap::Ptr p2 = it->cache_->lookup(name)) {
1494 6932 : rv = p2->value();
1495 6932 : break;
1496 : }
1497 : }
1498 : }
1499 :
1500 7483 : if (!cache_->add(p, name, rv)) {
1501 0 : ReportOutOfMemory(bce->cx);
1502 0 : return Nothing();
1503 : }
1504 :
1505 7483 : return Some(rv);
1506 : }
1507 :
1508 : bool
1509 10297 : BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
1510 : MaybeCheckTDZ check)
1511 : {
1512 10297 : if (!ensureCache(bce))
1513 0 : return false;
1514 :
1515 10297 : CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
1516 10297 : if (p) {
1517 4622 : MOZ_ASSERT(!check, "TDZ only needs to be checked once per binding per basic block.");
1518 4622 : p->value() = check;
1519 : } else {
1520 5675 : if (!cache_->add(p, name, check))
1521 0 : return false;
1522 : }
1523 :
1524 10297 : return true;
1525 : }
1526 :
1527 1164 : class MOZ_STACK_CLASS TryEmitter
1528 : {
1529 : public:
1530 : enum Kind {
1531 : TryCatch,
1532 : TryCatchFinally,
1533 : TryFinally
1534 : };
1535 : enum ShouldUseRetVal {
1536 : UseRetVal,
1537 : DontUseRetVal
1538 : };
1539 : enum ShouldUseControl {
1540 : UseControl,
1541 : DontUseControl,
1542 : };
1543 :
1544 : private:
1545 : BytecodeEmitter* bce_;
1546 : Kind kind_;
1547 : ShouldUseRetVal retValKind_;
1548 :
1549 : // Track jumps-over-catches and gosubs-to-finally for later fixup.
1550 : //
1551 : // When a finally block is active, non-local jumps (including
1552 : // jumps-over-catches) result in a GOSUB being written into the bytecode
1553 : // stream and fixed-up later.
1554 : //
1555 : // If ShouldUseControl is DontUseControl, all that handling is skipped.
1556 : // DontUseControl is used by yield* and the internal try-catch around
1557 : // IteratorClose. These internal uses must:
1558 : // * have only one catch block
1559 : // * have no catch guard
1560 : // * have JSOP_GOTO at the end of catch-block
1561 : // * have no non-local-jump
1562 : // * don't use finally block for normal completion of try-block and
1563 : // catch-block
1564 : //
1565 : // Additionally, a finally block may be emitted when ShouldUseControl is
1566 : // DontUseControl, even if the kind is not TryCatchFinally or TryFinally,
1567 : // because GOSUBs are not emitted. This internal use shares the
1568 : // requirements as above.
1569 : Maybe<TryFinallyControl> controlInfo_;
1570 :
1571 : int depth_;
1572 : unsigned noteIndex_;
1573 : ptrdiff_t tryStart_;
1574 : JumpList catchAndFinallyJump_;
1575 : JumpTarget tryEnd_;
1576 : JumpTarget finallyStart_;
1577 :
1578 : enum State {
1579 : Start,
1580 : Try,
1581 : TryEnd,
1582 : Catch,
1583 : CatchEnd,
1584 : Finally,
1585 : FinallyEnd,
1586 : End
1587 : };
1588 : State state_;
1589 :
1590 1164 : bool hasCatch() const {
1591 1164 : return kind_ == TryCatch || kind_ == TryCatchFinally;
1592 : }
1593 4489 : bool hasFinally() const {
1594 4489 : return kind_ == TryCatchFinally || kind_ == TryFinally;
1595 : }
1596 :
1597 : public:
1598 1164 : TryEmitter(BytecodeEmitter* bce, Kind kind, ShouldUseRetVal retValKind = UseRetVal,
1599 : ShouldUseControl controlKind = UseControl)
1600 1164 : : bce_(bce),
1601 : kind_(kind),
1602 : retValKind_(retValKind),
1603 : depth_(0),
1604 : noteIndex_(0),
1605 : tryStart_(0),
1606 1164 : state_(Start)
1607 : {
1608 1164 : if (controlKind == UseControl)
1609 489 : controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
1610 1164 : finallyStart_.offset = 0;
1611 1164 : }
1612 :
1613 3 : bool emitJumpOverCatchAndFinally() {
1614 3 : if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1615 0 : return false;
1616 3 : return true;
1617 : }
1618 :
1619 1164 : bool emitTry() {
1620 1164 : MOZ_ASSERT(state_ == Start);
1621 :
1622 : // Since an exception can be thrown at any place inside the try block,
1623 : // we need to restore the stack and the scope chain before we transfer
1624 : // the control to the exception handler.
1625 : //
1626 : // For that we store in a try note associated with the catch or
1627 : // finally block the stack depth upon the try entry. The interpreter
1628 : // uses this depth to properly unwind the stack and the scope chain.
1629 1164 : depth_ = bce_->stackDepth;
1630 :
1631 : // Record the try location, then emit the try block.
1632 1164 : if (!bce_->newSrcNote(SRC_TRY, ¬eIndex_))
1633 0 : return false;
1634 1164 : if (!bce_->emit1(JSOP_TRY))
1635 0 : return false;
1636 1164 : tryStart_ = bce_->offset();
1637 :
1638 1164 : state_ = Try;
1639 1164 : return true;
1640 : }
1641 :
1642 : private:
1643 1164 : bool emitTryEnd() {
1644 1164 : MOZ_ASSERT(state_ == Try);
1645 1164 : MOZ_ASSERT(depth_ == bce_->stackDepth);
1646 :
1647 : // GOSUB to finally, if present.
1648 1164 : if (hasFinally() && controlInfo_) {
1649 41 : if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
1650 0 : return false;
1651 : }
1652 :
1653 : // Source note points to the jump at the end of the try block.
1654 1164 : if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
1655 0 : return false;
1656 :
1657 : // Emit jump over catch and/or finally.
1658 1164 : if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1659 0 : return false;
1660 :
1661 1164 : if (!bce_->emitJumpTarget(&tryEnd_))
1662 0 : return false;
1663 :
1664 1164 : return true;
1665 : }
1666 :
1667 : public:
1668 1142 : bool emitCatch() {
1669 1142 : if (state_ == Try) {
1670 1142 : if (!emitTryEnd())
1671 0 : return false;
1672 : } else {
1673 0 : MOZ_ASSERT(state_ == Catch);
1674 0 : if (!emitCatchEnd(true))
1675 0 : return false;
1676 : }
1677 :
1678 1142 : MOZ_ASSERT(bce_->stackDepth == depth_);
1679 :
1680 1142 : if (retValKind_ == UseRetVal) {
1681 : // Clear the frame's return value that might have been set by the
1682 : // try block:
1683 : //
1684 : // eval("try { 1; throw 2 } catch(e) {}"); // undefined, not 1
1685 467 : if (!bce_->emit1(JSOP_UNDEFINED))
1686 0 : return false;
1687 467 : if (!bce_->emit1(JSOP_SETRVAL))
1688 0 : return false;
1689 : }
1690 :
1691 1142 : state_ = Catch;
1692 1142 : return true;
1693 : }
1694 :
1695 : private:
1696 1142 : bool emitCatchEnd(bool hasNext) {
1697 1142 : MOZ_ASSERT(state_ == Catch);
1698 :
1699 1142 : if (!controlInfo_)
1700 675 : return true;
1701 :
1702 : // gosub <finally>, if required.
1703 467 : if (hasFinally()) {
1704 19 : if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
1705 0 : return false;
1706 19 : MOZ_ASSERT(bce_->stackDepth == depth_);
1707 : }
1708 :
1709 : // Jump over the remaining catch blocks. This will get fixed
1710 : // up to jump to after catch/finally.
1711 467 : if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1712 0 : return false;
1713 :
1714 : // If this catch block had a guard clause, patch the guard jump to
1715 : // come here.
1716 467 : if (controlInfo_->guardJump.offset != -1) {
1717 0 : if (!bce_->emitJumpTargetAndPatch(controlInfo_->guardJump))
1718 0 : return false;
1719 0 : controlInfo_->guardJump.offset = -1;
1720 :
1721 : // If this catch block is the last one, rethrow, delegating
1722 : // execution of any finally block to the exception handler.
1723 0 : if (!hasNext) {
1724 0 : if (!bce_->emit1(JSOP_EXCEPTION))
1725 0 : return false;
1726 0 : if (!bce_->emit1(JSOP_THROW))
1727 0 : return false;
1728 : }
1729 : }
1730 :
1731 467 : return true;
1732 : }
1733 :
1734 : public:
1735 64 : bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
1736 : // If we are using controlInfo_ (i.e., emitting a syntactic try
1737 : // blocks), we must have specified up front if there will be a finally
1738 : // close. For internal try blocks, like those emitted for yield* and
1739 : // IteratorClose inside for-of loops, we can emitFinally even without
1740 : // specifying up front, since the internal try blocks emit no GOSUBs.
1741 64 : if (!controlInfo_) {
1742 23 : if (kind_ == TryCatch)
1743 20 : kind_ = TryCatchFinally;
1744 : } else {
1745 41 : MOZ_ASSERT(hasFinally());
1746 : }
1747 :
1748 64 : if (state_ == Try) {
1749 22 : if (!emitTryEnd())
1750 0 : return false;
1751 : } else {
1752 42 : MOZ_ASSERT(state_ == Catch);
1753 42 : if (!emitCatchEnd(false))
1754 0 : return false;
1755 : }
1756 :
1757 64 : MOZ_ASSERT(bce_->stackDepth == depth_);
1758 :
1759 64 : if (!bce_->emitJumpTarget(&finallyStart_))
1760 0 : return false;
1761 :
1762 64 : if (controlInfo_) {
1763 : // Fix up the gosubs that might have been emitted before non-local
1764 : // jumps to the finally code.
1765 41 : bce_->patchJumpsToTarget(controlInfo_->gosubs, finallyStart_);
1766 :
1767 : // Indicate that we're emitting a subroutine body.
1768 41 : controlInfo_->setEmittingSubroutine();
1769 : }
1770 64 : if (finallyPos) {
1771 41 : if (!bce_->updateSourceCoordNotes(finallyPos.value()))
1772 0 : return false;
1773 : }
1774 64 : if (!bce_->emit1(JSOP_FINALLY))
1775 0 : return false;
1776 :
1777 64 : if (retValKind_ == UseRetVal) {
1778 41 : if (!bce_->emit1(JSOP_GETRVAL))
1779 0 : return false;
1780 :
1781 : // Clear the frame's return value to make break/continue return
1782 : // correct value even if there's no other statement before them:
1783 : //
1784 : // eval("x: try { 1 } finally { break x; }"); // undefined, not 1
1785 41 : if (!bce_->emit1(JSOP_UNDEFINED))
1786 0 : return false;
1787 41 : if (!bce_->emit1(JSOP_SETRVAL))
1788 0 : return false;
1789 : }
1790 :
1791 64 : state_ = Finally;
1792 64 : return true;
1793 : }
1794 :
1795 : private:
1796 64 : bool emitFinallyEnd() {
1797 64 : MOZ_ASSERT(state_ == Finally);
1798 :
1799 64 : if (retValKind_ == UseRetVal) {
1800 41 : if (!bce_->emit1(JSOP_SETRVAL))
1801 0 : return false;
1802 : }
1803 :
1804 64 : if (!bce_->emit1(JSOP_RETSUB))
1805 0 : return false;
1806 :
1807 64 : bce_->hasTryFinally = true;
1808 64 : return true;
1809 : }
1810 :
1811 : public:
1812 1164 : bool emitEnd() {
1813 1164 : if (state_ == Catch) {
1814 1100 : MOZ_ASSERT(!hasFinally());
1815 1100 : if (!emitCatchEnd(false))
1816 0 : return false;
1817 : } else {
1818 64 : MOZ_ASSERT(state_ == Finally);
1819 64 : MOZ_ASSERT(hasFinally());
1820 64 : if (!emitFinallyEnd())
1821 0 : return false;
1822 : }
1823 :
1824 1164 : MOZ_ASSERT(bce_->stackDepth == depth_);
1825 :
1826 : // ReconstructPCStack needs a NOP here to mark the end of the last
1827 : // catch block.
1828 1164 : if (!bce_->emit1(JSOP_NOP))
1829 0 : return false;
1830 :
1831 : // Fix up the end-of-try/catch jumps to come here.
1832 1164 : if (!bce_->emitJumpTargetAndPatch(catchAndFinallyJump_))
1833 0 : return false;
1834 :
1835 : // Add the try note last, to let post-order give us the right ordering
1836 : // (first to last for a given nesting level, inner to outer by level).
1837 1164 : if (hasCatch()) {
1838 1142 : if (!bce_->tryNoteList.append(JSTRY_CATCH, depth_, tryStart_, tryEnd_.offset))
1839 0 : return false;
1840 : }
1841 :
1842 : // If we've got a finally, mark try+catch region with additional
1843 : // trynote to catch exceptions (re)thrown from a catch block or
1844 : // for the try{}finally{} case.
1845 1164 : if (hasFinally()) {
1846 64 : if (!bce_->tryNoteList.append(JSTRY_FINALLY, depth_, tryStart_, finallyStart_.offset))
1847 0 : return false;
1848 : }
1849 :
1850 1164 : state_ = End;
1851 1164 : return true;
1852 : }
1853 : };
1854 :
1855 : class MOZ_STACK_CLASS IfThenElseEmitter
1856 : {
1857 : BytecodeEmitter* bce_;
1858 : JumpList jumpAroundThen_;
1859 : JumpList jumpsAroundElse_;
1860 : unsigned noteIndex_;
1861 : int32_t thenDepth_;
1862 : #ifdef DEBUG
1863 : int32_t pushed_;
1864 : bool calculatedPushed_;
1865 : #endif
1866 : enum State {
1867 : Start,
1868 : If,
1869 : Cond,
1870 : IfElse,
1871 : Else,
1872 : End
1873 : };
1874 : State state_;
1875 :
1876 : public:
1877 9045 : explicit IfThenElseEmitter(BytecodeEmitter* bce)
1878 9045 : : bce_(bce),
1879 : noteIndex_(-1),
1880 : thenDepth_(0),
1881 : #ifdef DEBUG
1882 : pushed_(0),
1883 : calculatedPushed_(false),
1884 : #endif
1885 9045 : state_(Start)
1886 9045 : {}
1887 :
1888 9046 : ~IfThenElseEmitter()
1889 9046 : {}
1890 :
1891 : private:
1892 9215 : bool emitIf(State nextState) {
1893 9215 : MOZ_ASSERT(state_ == Start || state_ == Else);
1894 9215 : MOZ_ASSERT(nextState == If || nextState == IfElse || nextState == Cond);
1895 :
1896 : // Clear jumpAroundThen_ offset that points previous JSOP_IFEQ.
1897 9215 : if (state_ == Else)
1898 276 : jumpAroundThen_ = JumpList();
1899 :
1900 : // Emit an annotated branch-if-false around the then part.
1901 9215 : SrcNoteType type = nextState == If ? SRC_IF : nextState == IfElse ? SRC_IF_ELSE : SRC_COND;
1902 9215 : if (!bce_->newSrcNote(type, ¬eIndex_))
1903 0 : return false;
1904 9215 : if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_))
1905 0 : return false;
1906 :
1907 : // To restore stack depth in else part, save depth of the then part.
1908 : #ifdef DEBUG
1909 : // If DEBUG, this is also necessary to calculate |pushed_|.
1910 9215 : thenDepth_ = bce_->stackDepth;
1911 : #else
1912 : if (nextState == IfElse || nextState == Cond)
1913 : thenDepth_ = bce_->stackDepth;
1914 : #endif
1915 9215 : state_ = nextState;
1916 9215 : return true;
1917 : }
1918 :
1919 : public:
1920 6826 : bool emitIf() {
1921 6826 : return emitIf(If);
1922 : }
1923 :
1924 657 : bool emitCond() {
1925 657 : return emitIf(Cond);
1926 : }
1927 :
1928 1732 : bool emitIfElse() {
1929 1732 : return emitIf(IfElse);
1930 : }
1931 :
1932 2389 : bool emitElse() {
1933 2389 : MOZ_ASSERT(state_ == IfElse || state_ == Cond);
1934 :
1935 2389 : calculateOrCheckPushed();
1936 :
1937 : // Emit a jump from the end of our then part around the else part. The
1938 : // patchJumpsToTarget call at the bottom of this function will fix up
1939 : // the offset with jumpsAroundElse value.
1940 2389 : if (!bce_->emitJump(JSOP_GOTO, &jumpsAroundElse_))
1941 0 : return false;
1942 :
1943 : // Ensure the branch-if-false comes here, then emit the else.
1944 2389 : if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
1945 0 : return false;
1946 :
1947 : // Annotate SRC_IF_ELSE or SRC_COND with the offset from branch to
1948 : // jump, for IonMonkey's benefit. We can't just "back up" from the pc
1949 : // of the else clause, because we don't know whether an extended
1950 : // jump was required to leap from the end of the then clause over
1951 : // the else clause.
1952 2389 : if (!bce_->setSrcNoteOffset(noteIndex_, 0,
1953 2389 : jumpsAroundElse_.offset - jumpAroundThen_.offset))
1954 : {
1955 0 : return false;
1956 : }
1957 :
1958 : // Restore stack depth of the then part.
1959 2389 : bce_->stackDepth = thenDepth_;
1960 2389 : state_ = Else;
1961 2389 : return true;
1962 : }
1963 :
1964 8939 : bool emitEnd() {
1965 8939 : MOZ_ASSERT(state_ == If || state_ == Else);
1966 :
1967 8939 : calculateOrCheckPushed();
1968 :
1969 8939 : if (state_ == If) {
1970 : // No else part, fixup the branch-if-false to come here.
1971 6826 : if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
1972 0 : return false;
1973 : }
1974 :
1975 : // Patch all the jumps around else parts.
1976 8939 : if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_))
1977 0 : return false;
1978 :
1979 8939 : state_ = End;
1980 8939 : return true;
1981 : }
1982 :
1983 11328 : void calculateOrCheckPushed() {
1984 : #ifdef DEBUG
1985 11328 : if (!calculatedPushed_) {
1986 8939 : pushed_ = bce_->stackDepth - thenDepth_;
1987 8939 : calculatedPushed_ = true;
1988 : } else {
1989 2389 : MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_);
1990 : }
1991 : #endif
1992 11328 : }
1993 :
1994 : #ifdef DEBUG
1995 876 : int32_t pushed() const {
1996 876 : return pushed_;
1997 : }
1998 :
1999 : int32_t popped() const {
2000 : return -pushed_;
2001 : }
2002 : #endif
2003 : };
2004 :
2005 336 : class ForOfLoopControl : public LoopControl
2006 : {
2007 : // The stack depth of the iterator.
2008 : int32_t iterDepth_;
2009 :
2010 : // for-of loops, when throwing from non-iterator code (i.e. from the body
2011 : // or from evaluating the LHS of the loop condition), need to call
2012 : // IteratorClose. This is done by enclosing non-iterator code with
2013 : // try-catch and call IteratorClose in `catch` block.
2014 : // If IteratorClose itself throws, we must not re-call IteratorClose. Since
2015 : // non-local jumps like break and return call IteratorClose, whenever a
2016 : // non-local jump is emitted, we must tell catch block not to perform
2017 : // IteratorClose.
2018 : //
2019 : // for (x of y) {
2020 : // // Operations for iterator (IteratorNext etc) are outside of
2021 : // // try-block.
2022 : // try {
2023 : // ...
2024 : // if (...) {
2025 : // // Before non-local jump, clear iterator on the stack to tell
2026 : // // catch block not to perform IteratorClose.
2027 : // tmpIterator = iterator;
2028 : // iterator = undefined;
2029 : // IteratorClose(tmpIterator, { break });
2030 : // break;
2031 : // }
2032 : // ...
2033 : // } catch (e) {
2034 : // // Just throw again when iterator is cleared by non-local jump.
2035 : // if (iterator === undefined)
2036 : // throw e;
2037 : // IteratorClose(iterator, { throw, e });
2038 : // }
2039 : // }
2040 : Maybe<TryEmitter> tryCatch_;
2041 :
2042 : // Used to track if any yields were emitted between calls to to
2043 : // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
2044 : uint32_t numYieldsAtBeginCodeNeedingIterClose_;
2045 :
2046 : bool allowSelfHosted_;
2047 :
2048 : IteratorKind iterKind_;
2049 :
2050 : public:
2051 336 : ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
2052 : IteratorKind iterKind)
2053 336 : : LoopControl(bce, StatementKind::ForOfLoop),
2054 : iterDepth_(iterDepth),
2055 : numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
2056 : allowSelfHosted_(allowSelfHosted),
2057 336 : iterKind_(iterKind)
2058 : {
2059 336 : }
2060 :
2061 336 : bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
2062 672 : tryCatch_.emplace(bce, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
2063 336 : TryEmitter::DontUseControl);
2064 :
2065 336 : if (!tryCatch_->emitTry())
2066 0 : return false;
2067 :
2068 336 : MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
2069 336 : numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
2070 :
2071 336 : return true;
2072 : }
2073 :
2074 336 : bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
2075 336 : if (!tryCatch_->emitCatch()) // ITER ...
2076 0 : return false;
2077 :
2078 336 : if (!bce->emit1(JSOP_EXCEPTION)) // ITER ... EXCEPTION
2079 0 : return false;
2080 336 : unsigned slotFromTop = bce->stackDepth - iterDepth_;
2081 336 : if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
2082 0 : return false;
2083 :
2084 : // If ITER is undefined, it means the exception is thrown by
2085 : // IteratorClose for non-local jump, and we should't perform
2086 : // IteratorClose again here.
2087 336 : if (!bce->emit1(JSOP_UNDEFINED)) // ITER ... EXCEPTION ITER UNDEF
2088 0 : return false;
2089 336 : if (!bce->emit1(JSOP_STRICTNE)) // ITER ... EXCEPTION NE
2090 0 : return false;
2091 :
2092 672 : IfThenElseEmitter ifIteratorIsNotClosed(bce);
2093 336 : if (!ifIteratorIsNotClosed.emitIf()) // ITER ... EXCEPTION
2094 0 : return false;
2095 :
2096 336 : MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
2097 336 : if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
2098 0 : return false;
2099 336 : if (!emitIteratorClose(bce, CompletionKind::Throw)) // ITER ... EXCEPTION
2100 0 : return false;
2101 :
2102 336 : if (!ifIteratorIsNotClosed.emitEnd()) // ITER ... EXCEPTION
2103 0 : return false;
2104 :
2105 336 : if (!bce->emit1(JSOP_THROW)) // ITER ...
2106 0 : return false;
2107 :
2108 : // If any yields were emitted, then this for-of loop is inside a star
2109 : // generator and must handle the case of Generator.return. Like in
2110 : // yield*, it is handled with a finally block.
2111 336 : uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
2112 336 : if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
2113 20 : if (!tryCatch_->emitFinally())
2114 0 : return false;
2115 :
2116 40 : IfThenElseEmitter ifGeneratorClosing(bce);
2117 20 : if (!bce->emit1(JSOP_ISGENCLOSING)) // ITER ... FTYPE FVALUE CLOSING
2118 0 : return false;
2119 20 : if (!ifGeneratorClosing.emitIf()) // ITER ... FTYPE FVALUE
2120 0 : return false;
2121 20 : if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
2122 0 : return false;
2123 20 : if (!emitIteratorClose(bce, CompletionKind::Normal)) // ITER ... FTYPE FVALUE
2124 0 : return false;
2125 20 : if (!ifGeneratorClosing.emitEnd()) // ITER ... FTYPE FVALUE
2126 0 : return false;
2127 : }
2128 :
2129 336 : if (!tryCatch_->emitEnd())
2130 0 : return false;
2131 :
2132 336 : tryCatch_.reset();
2133 336 : numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
2134 :
2135 336 : return true;
2136 : }
2137 :
2138 413 : bool emitIteratorClose(BytecodeEmitter* bce,
2139 : CompletionKind completionKind = CompletionKind::Normal) {
2140 413 : ptrdiff_t start = bce->offset();
2141 413 : if (!bce->emitIteratorClose(iterKind_, completionKind, allowSelfHosted_))
2142 0 : return false;
2143 413 : ptrdiff_t end = bce->offset();
2144 413 : return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
2145 : }
2146 :
2147 57 : bool emitPrepareForNonLocalJump(BytecodeEmitter* bce, bool isTarget) {
2148 : // Pop unnecessary value from the stack. Effectively this means
2149 : // leaving try-catch block. However, the performing IteratorClose can
2150 : // reach the depth for try-catch, and effectively re-enter the
2151 : // try-catch block.
2152 57 : if (!bce->emit1(JSOP_POP)) // ITER
2153 0 : return false;
2154 :
2155 : // Clear ITER slot on the stack to tell catch block to avoid performing
2156 : // IteratorClose again.
2157 57 : if (!bce->emit1(JSOP_UNDEFINED)) // ITER UNDEF
2158 0 : return false;
2159 57 : if (!bce->emit1(JSOP_SWAP)) // UNDEF ITER
2160 0 : return false;
2161 :
2162 57 : if (!emitIteratorClose(bce)) // UNDEF
2163 0 : return false;
2164 :
2165 57 : if (isTarget) {
2166 : // At the level of the target block, there's bytecode after the
2167 : // loop that will pop the iterator and the value, so push
2168 : // an undefined to balance the stack.
2169 11 : if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF
2170 0 : return false;
2171 : } else {
2172 46 : if (!bce->emit1(JSOP_POP)) //
2173 0 : return false;
2174 : }
2175 :
2176 57 : return true;
2177 : }
2178 : };
2179 :
2180 5673 : BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
2181 : const EitherParser<FullParseHandler>& parser, SharedContext* sc,
2182 : HandleScript script, Handle<LazyScript*> lazyScript,
2183 5673 : uint32_t lineNum, EmitterMode emitterMode)
2184 : : sc(sc),
2185 5673 : cx(sc->context),
2186 : parent(parent),
2187 : script(cx, script),
2188 : lazyScript(cx, lazyScript),
2189 5673 : prologue(cx, lineNum),
2190 5673 : main(cx, lineNum),
2191 5673 : current(&main),
2192 : parser(parser),
2193 5673 : atomIndices(cx->frontendCollectionPool()),
2194 : firstLine(lineNum),
2195 : maxFixedSlots(0),
2196 : maxStackDepth(0),
2197 : stackDepth(0),
2198 : arrayCompDepth(0),
2199 : emitLevel(0),
2200 : bodyScopeIndex(UINT32_MAX),
2201 : varEmitterScope(nullptr),
2202 : innermostNestableControl(nullptr),
2203 : innermostEmitterScope(nullptr),
2204 : innermostTDZCheckCache(nullptr),
2205 5673 : constList(cx),
2206 5673 : scopeList(cx),
2207 5673 : tryNoteList(cx),
2208 5673 : scopeNoteList(cx),
2209 5673 : yieldAndAwaitOffsetList(cx),
2210 : typesetCount(0),
2211 : hasSingletons(false),
2212 : hasTryFinally(false),
2213 : emittingRunOnceLambda(false),
2214 : emitterMode(emitterMode),
2215 62403 : functionBodyEndPosSet(false)
2216 : {
2217 5673 : MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
2218 5673 : }
2219 :
2220 5389 : BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
2221 : const EitherParser<FullParseHandler>& parser, SharedContext* sc,
2222 : HandleScript script, Handle<LazyScript*> lazyScript,
2223 5389 : TokenPos bodyPosition, EmitterMode emitterMode)
2224 : : BytecodeEmitter(parent, parser, sc, script, lazyScript,
2225 5389 : parser.tokenStream().srcCoords.lineNum(bodyPosition.begin),
2226 10778 : emitterMode)
2227 : {
2228 5389 : setFunctionBodyEndPos(bodyPosition);
2229 5389 : }
2230 :
2231 : bool
2232 5673 : BytecodeEmitter::init()
2233 : {
2234 5673 : return atomIndices.acquire(cx);
2235 : }
2236 :
2237 : template <typename Predicate /* (NestableControl*) -> bool */>
2238 : BytecodeEmitter::NestableControl*
2239 : BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
2240 : {
2241 : return NestableControl::findNearest(innermostNestableControl, predicate);
2242 : }
2243 :
2244 : template <typename T>
2245 : T*
2246 6004 : BytecodeEmitter::findInnermostNestableControl() const
2247 : {
2248 6004 : return NestableControl::findNearest<T>(innermostNestableControl);
2249 : }
2250 :
2251 : template <typename T, typename Predicate /* (T*) -> bool */>
2252 : T*
2253 479 : BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
2254 : {
2255 479 : return NestableControl::findNearest<T>(innermostNestableControl, predicate);
2256 : }
2257 :
2258 : NameLocation
2259 89957 : BytecodeEmitter::lookupName(JSAtom* name)
2260 : {
2261 89957 : return innermostEmitterScope->lookup(this, name);
2262 : }
2263 :
2264 : Maybe<NameLocation>
2265 6694 : BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
2266 : {
2267 6694 : return innermostEmitterScope->locationBoundInScope(this, name, target);
2268 : }
2269 :
2270 : Maybe<NameLocation>
2271 479 : BytecodeEmitter::locationOfNameBoundInFunctionScope(JSAtom* name, EmitterScope* source)
2272 : {
2273 479 : EmitterScope* funScope = source;
2274 1089 : while (!funScope->scope(this)->is<FunctionScope>())
2275 305 : funScope = funScope->enclosingInFrame();
2276 479 : return source->locationBoundInScope(this, name, funScope);
2277 : }
2278 :
2279 : bool
2280 388624 : BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset)
2281 : {
2282 388624 : *offset = code().length();
2283 :
2284 : // Start it off moderately large to avoid repeated resizings early on.
2285 : // ~98% of cases fit within 1024 bytes.
2286 388624 : if (code().capacity() == 0 && !code().reserve(1024))
2287 0 : return false;
2288 :
2289 388624 : if (!code().growBy(delta)) {
2290 0 : ReportOutOfMemory(cx);
2291 0 : return false;
2292 : }
2293 388624 : return true;
2294 : }
2295 :
2296 : void
2297 388624 : BytecodeEmitter::updateDepth(ptrdiff_t target)
2298 : {
2299 388624 : jsbytecode* pc = code(target);
2300 :
2301 388624 : int nuses = StackUses(nullptr, pc);
2302 388624 : int ndefs = StackDefs(nullptr, pc);
2303 :
2304 388624 : stackDepth -= nuses;
2305 388624 : MOZ_ASSERT(stackDepth >= 0);
2306 388624 : stackDepth += ndefs;
2307 :
2308 388624 : if ((uint32_t)stackDepth > maxStackDepth)
2309 24354 : maxStackDepth = stackDepth;
2310 388624 : }
2311 :
2312 : #ifdef DEBUG
2313 : bool
2314 367346 : BytecodeEmitter::checkStrictOrSloppy(JSOp op)
2315 : {
2316 367346 : if (IsCheckStrictOp(op) && !sc->strict())
2317 0 : return false;
2318 367346 : if (IsCheckSloppyOp(op) && sc->strict())
2319 0 : return false;
2320 367346 : return true;
2321 : }
2322 : #endif
2323 :
2324 : bool
2325 178487 : BytecodeEmitter::emit1(JSOp op)
2326 : {
2327 178487 : MOZ_ASSERT(checkStrictOrSloppy(op));
2328 :
2329 : ptrdiff_t offset;
2330 178487 : if (!emitCheck(1, &offset))
2331 0 : return false;
2332 :
2333 178487 : jsbytecode* code = this->code(offset);
2334 178487 : code[0] = jsbytecode(op);
2335 178487 : updateDepth(offset);
2336 178487 : return true;
2337 : }
2338 :
2339 : bool
2340 7109 : BytecodeEmitter::emit2(JSOp op, uint8_t op1)
2341 : {
2342 7109 : MOZ_ASSERT(checkStrictOrSloppy(op));
2343 :
2344 : ptrdiff_t offset;
2345 7109 : if (!emitCheck(2, &offset))
2346 0 : return false;
2347 :
2348 7109 : jsbytecode* code = this->code(offset);
2349 7109 : code[0] = jsbytecode(op);
2350 7109 : code[1] = jsbytecode(op1);
2351 7109 : updateDepth(offset);
2352 7109 : return true;
2353 : }
2354 :
2355 : bool
2356 23937 : BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2)
2357 : {
2358 23937 : MOZ_ASSERT(checkStrictOrSloppy(op));
2359 :
2360 : /* These should filter through emitVarOp. */
2361 23937 : MOZ_ASSERT(!IsArgOp(op));
2362 23937 : MOZ_ASSERT(!IsLocalOp(op));
2363 :
2364 : ptrdiff_t offset;
2365 23937 : if (!emitCheck(3, &offset))
2366 0 : return false;
2367 :
2368 23937 : jsbytecode* code = this->code(offset);
2369 23937 : code[0] = jsbytecode(op);
2370 23937 : code[1] = op1;
2371 23937 : code[2] = op2;
2372 23937 : updateDepth(offset);
2373 23937 : return true;
2374 : }
2375 :
2376 : bool
2377 75110 : BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset)
2378 : {
2379 75110 : MOZ_ASSERT(checkStrictOrSloppy(op));
2380 75110 : ptrdiff_t length = 1 + ptrdiff_t(extra);
2381 :
2382 : ptrdiff_t off;
2383 75110 : if (!emitCheck(length, &off))
2384 0 : return false;
2385 :
2386 75110 : jsbytecode* code = this->code(off);
2387 75110 : code[0] = jsbytecode(op);
2388 : /* The remaining |extra| bytes are set by the caller */
2389 :
2390 : /*
2391 : * Don't updateDepth if op's use-count comes from the immediate
2392 : * operand yet to be stored in the extra bytes after op.
2393 : */
2394 75110 : if (CodeSpec[op].nuses >= 0)
2395 75110 : updateDepth(off);
2396 :
2397 75110 : if (offset)
2398 74900 : *offset = off;
2399 75110 : return true;
2400 : }
2401 :
2402 : bool
2403 32532 : BytecodeEmitter::emitJumpTarget(JumpTarget* target)
2404 : {
2405 32532 : ptrdiff_t off = offset();
2406 :
2407 : // Alias consecutive jump targets.
2408 32532 : if (off == current->lastTarget.offset + ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
2409 2050 : target->offset = current->lastTarget.offset;
2410 2050 : return true;
2411 : }
2412 :
2413 30482 : target->offset = off;
2414 30482 : current->lastTarget.offset = off;
2415 30482 : if (!emit1(JSOP_JUMPTARGET))
2416 0 : return false;
2417 30482 : return true;
2418 : }
2419 :
2420 : void
2421 19622 : JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset)
2422 : {
2423 19622 : SET_JUMP_OFFSET(&code[jumpOffset], offset - jumpOffset);
2424 19622 : offset = jumpOffset;
2425 19622 : }
2426 :
2427 : void
2428 19251 : JumpList::patchAll(jsbytecode* code, JumpTarget target)
2429 : {
2430 : ptrdiff_t delta;
2431 38873 : for (ptrdiff_t jumpOffset = offset; jumpOffset != -1; jumpOffset += delta) {
2432 19622 : jsbytecode* pc = &code[jumpOffset];
2433 19622 : MOZ_ASSERT(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL);
2434 19622 : delta = GET_JUMP_OFFSET(pc);
2435 19622 : MOZ_ASSERT(delta < 0);
2436 19622 : ptrdiff_t span = target.offset - jumpOffset;
2437 19622 : SET_JUMP_OFFSET(pc, span);
2438 : }
2439 19251 : }
2440 :
2441 : bool
2442 19622 : BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump)
2443 : {
2444 : ptrdiff_t offset;
2445 19622 : if (!emitCheck(5, &offset))
2446 0 : return false;
2447 :
2448 19622 : jsbytecode* code = this->code(offset);
2449 19622 : code[0] = jsbytecode(op);
2450 19622 : MOZ_ASSERT(-1 <= jump->offset && jump->offset < offset);
2451 19622 : jump->push(this->code(0), offset);
2452 19622 : updateDepth(offset);
2453 19622 : return true;
2454 : }
2455 :
2456 : bool
2457 18542 : BytecodeEmitter::emitJump(JSOp op, JumpList* jump)
2458 : {
2459 18542 : if (!emitJumpNoFallthrough(op, jump))
2460 0 : return false;
2461 18542 : if (BytecodeFallsThrough(op)) {
2462 : JumpTarget fallthrough;
2463 12403 : if (!emitJumpTarget(&fallthrough))
2464 0 : return false;
2465 : }
2466 18542 : return true;
2467 : }
2468 :
2469 : bool
2470 1080 : BytecodeEmitter::emitBackwardJump(JSOp op, JumpTarget target, JumpList* jump, JumpTarget* fallthrough)
2471 : {
2472 1080 : if (!emitJumpNoFallthrough(op, jump))
2473 0 : return false;
2474 1080 : patchJumpsToTarget(*jump, target);
2475 :
2476 : // Unconditionally create a fallthrough for closing iterators, and as a
2477 : // target for break statements.
2478 1080 : if (!emitJumpTarget(fallthrough))
2479 0 : return false;
2480 1080 : return true;
2481 : }
2482 :
2483 : void
2484 19251 : BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target)
2485 : {
2486 19251 : MOZ_ASSERT(-1 <= jump.offset && jump.offset <= offset());
2487 19251 : MOZ_ASSERT(0 <= target.offset && target.offset <= offset());
2488 19251 : MOZ_ASSERT_IF(jump.offset != -1 && target.offset + 4 <= offset(),
2489 : BytecodeIsJumpTarget(JSOp(*code(target.offset))));
2490 19251 : jump.patchAll(code(0), target);
2491 19251 : }
2492 :
2493 : bool
2494 23298 : BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump)
2495 : {
2496 23298 : if (jump.offset == -1)
2497 7390 : return true;
2498 : JumpTarget target;
2499 15908 : if (!emitJumpTarget(&target))
2500 0 : return false;
2501 15908 : patchJumpsToTarget(jump, target);
2502 15908 : return true;
2503 : }
2504 :
2505 : bool
2506 23429 : BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn)
2507 : {
2508 23429 : if (pn && !updateSourceCoordNotes(pn->pn_pos.begin))
2509 0 : return false;
2510 23429 : return emit3(op, ARGC_HI(argc), ARGC_LO(argc));
2511 : }
2512 :
2513 : bool
2514 2959 : BytecodeEmitter::emitDupAt(unsigned slotFromTop)
2515 : {
2516 2959 : MOZ_ASSERT(slotFromTop < unsigned(stackDepth));
2517 :
2518 2959 : if (slotFromTop == 0)
2519 541 : return emit1(JSOP_DUP);
2520 :
2521 2418 : if (slotFromTop >= JS_BIT(24)) {
2522 0 : reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
2523 0 : return false;
2524 : }
2525 :
2526 : ptrdiff_t off;
2527 2418 : if (!emitN(JSOP_DUPAT, 3, &off))
2528 0 : return false;
2529 :
2530 2418 : jsbytecode* pc = code(off);
2531 2418 : SET_UINT24(pc, slotFromTop);
2532 2418 : return true;
2533 : }
2534 :
2535 : bool
2536 736 : BytecodeEmitter::emitPopN(unsigned n)
2537 : {
2538 736 : MOZ_ASSERT(n != 0);
2539 :
2540 736 : if (n == 1)
2541 0 : return emit1(JSOP_POP);
2542 :
2543 : // 2 JSOP_POPs (2 bytes) are shorter than JSOP_POPN (3 bytes).
2544 736 : if (n == 2)
2545 733 : return emit1(JSOP_POP) && emit1(JSOP_POP);
2546 :
2547 3 : return emitUint16Operand(JSOP_POPN, n);
2548 : }
2549 :
2550 : bool
2551 1177 : BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind)
2552 : {
2553 1177 : return emit2(JSOP_CHECKISOBJ, uint8_t(kind));
2554 : }
2555 :
2556 : bool
2557 336 : BytecodeEmitter::emitCheckIsCallable(CheckIsCallableKind kind)
2558 : {
2559 336 : return emit2(JSOP_CHECKISCALLABLE, uint8_t(kind));
2560 : }
2561 :
2562 : static inline unsigned
2563 66838 : LengthOfSetLine(unsigned line)
2564 : {
2565 66838 : return 1 /* SN_SETLINE */ + (line > SN_4BYTE_OFFSET_MASK ? 4 : 1);
2566 : }
2567 :
2568 : /* Updates line number notes, not column notes. */
2569 : bool
2570 312313 : BytecodeEmitter::updateLineNumberNotes(uint32_t offset)
2571 : {
2572 312313 : TokenStreamAnyChars* ts = &parser.tokenStream();
2573 : bool onThisLine;
2574 312313 : if (!ts->srcCoords.isOnThisLine(offset, currentLine(), &onThisLine)) {
2575 0 : ts->reportErrorNoOffset(JSMSG_OUT_OF_MEMORY);
2576 0 : return false;
2577 : }
2578 :
2579 312313 : if (!onThisLine) {
2580 66838 : unsigned line = ts->srcCoords.lineNum(offset);
2581 66838 : unsigned delta = line - currentLine();
2582 :
2583 : /*
2584 : * Encode any change in the current source line number by using
2585 : * either several SRC_NEWLINE notes or just one SRC_SETLINE note,
2586 : * whichever consumes less space.
2587 : *
2588 : * NB: We handle backward line number deltas (possible with for
2589 : * loops where the update part is emitted after the body, but its
2590 : * line number is <= any line number in the body) here by letting
2591 : * unsigned delta_ wrap to a very large number, which triggers a
2592 : * SRC_SETLINE.
2593 : */
2594 66838 : current->currentLine = line;
2595 66838 : current->lastColumn = 0;
2596 66838 : if (delta >= LengthOfSetLine(line)) {
2597 19611 : if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(line)))
2598 0 : return false;
2599 : } else {
2600 60545 : do {
2601 60545 : if (!newSrcNote(SRC_NEWLINE))
2602 0 : return false;
2603 : } while (--delta != 0);
2604 : }
2605 : }
2606 312313 : return true;
2607 : }
2608 :
2609 : /* Updates the line number and column number information in the source notes. */
2610 : bool
2611 85525 : BytecodeEmitter::updateSourceCoordNotes(uint32_t offset)
2612 : {
2613 85525 : if (!updateLineNumberNotes(offset))
2614 0 : return false;
2615 :
2616 85525 : uint32_t columnIndex = parser.tokenStream().srcCoords.columnIndex(offset);
2617 85525 : ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(current->lastColumn);
2618 85525 : if (colspan != 0) {
2619 : // If the column span is so large that we can't store it, then just
2620 : // discard this information. This can happen with minimized or otherwise
2621 : // machine-generated code. Even gigantic column numbers are still
2622 : // valuable if you have a source map to relate them to something real;
2623 : // but it's better to fail soft here.
2624 63975 : if (!SN_REPRESENTABLE_COLSPAN(colspan))
2625 0 : return true;
2626 63975 : if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan)))
2627 0 : return false;
2628 63975 : current->lastColumn = columnIndex;
2629 : }
2630 85525 : return true;
2631 : }
2632 :
2633 : bool
2634 1074 : BytecodeEmitter::emitLoopHead(ParseNode* nextpn, JumpTarget* top)
2635 : {
2636 1074 : if (nextpn) {
2637 : /*
2638 : * Try to give the JSOP_LOOPHEAD the same line number as the next
2639 : * instruction. nextpn is often a block, in which case the next
2640 : * instruction typically comes from the first statement inside.
2641 : */
2642 644 : if (nextpn->isKind(PNK_LEXICALSCOPE))
2643 576 : nextpn = nextpn->scopeBody();
2644 644 : MOZ_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
2645 644 : if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
2646 575 : nextpn = nextpn->pn_head;
2647 644 : if (!updateSourceCoordNotes(nextpn->pn_pos.begin))
2648 0 : return false;
2649 : }
2650 :
2651 1074 : *top = { offset() };
2652 1074 : return emit1(JSOP_LOOPHEAD);
2653 : }
2654 :
2655 : bool
2656 1074 : BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump)
2657 : {
2658 1074 : if (nextpn) {
2659 : /* Update the line number, as for LOOPHEAD. */
2660 960 : if (nextpn->isKind(PNK_LEXICALSCOPE))
2661 9 : nextpn = nextpn->scopeBody();
2662 960 : MOZ_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
2663 960 : if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
2664 9 : nextpn = nextpn->pn_head;
2665 960 : if (!updateSourceCoordNotes(nextpn->pn_pos.begin))
2666 0 : return false;
2667 : }
2668 :
2669 1074 : JumpTarget entry{ offset() };
2670 1074 : patchJumpsToTarget(entryJump, entry);
2671 :
2672 1074 : LoopControl& loopInfo = innermostNestableControl->as<LoopControl>();
2673 1074 : MOZ_ASSERT(loopInfo.loopDepth() > 0);
2674 :
2675 1074 : uint8_t loopDepthAndFlags = PackLoopEntryDepthHintAndFlags(loopInfo.loopDepth(),
2676 2148 : loopInfo.canIonOsr());
2677 1074 : return emit2(JSOP_LOOPENTRY, loopDepthAndFlags);
2678 : }
2679 :
2680 : void
2681 121549 : BytecodeEmitter::checkTypeSet(JSOp op)
2682 : {
2683 121549 : if (CodeSpec[op].format & JOF_TYPESET) {
2684 82592 : if (typesetCount < UINT16_MAX)
2685 82592 : typesetCount++;
2686 : }
2687 121549 : }
2688 :
2689 : bool
2690 508 : BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t operand)
2691 : {
2692 508 : MOZ_ASSERT(operand <= UINT16_MAX);
2693 508 : if (!emit3(op, UINT16_HI(operand), UINT16_LO(operand)))
2694 0 : return false;
2695 508 : checkTypeSet(op);
2696 508 : return true;
2697 : }
2698 :
2699 : bool
2700 2124 : BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand)
2701 : {
2702 : ptrdiff_t off;
2703 2124 : if (!emitN(op, 4, &off))
2704 0 : return false;
2705 2124 : SET_UINT32(code(off), operand);
2706 2124 : checkTypeSet(op);
2707 2124 : return true;
2708 : }
2709 :
2710 : namespace {
2711 :
2712 : class NonLocalExitControl
2713 : {
2714 : public:
2715 : enum Kind
2716 : {
2717 : // IteratorClose is handled especially inside the exception unwinder.
2718 : Throw,
2719 :
2720 : // A 'continue' statement does not call IteratorClose for the loop it
2721 : // is continuing, i.e. excluding the target loop.
2722 : Continue,
2723 :
2724 : // A 'break' or 'return' statement does call IteratorClose for the
2725 : // loop it is breaking out of or returning from, i.e. including the
2726 : // target loop.
2727 : Break,
2728 : Return
2729 : };
2730 :
2731 : private:
2732 : BytecodeEmitter* bce_;
2733 : const uint32_t savedScopeNoteIndex_;
2734 : const int savedDepth_;
2735 : uint32_t openScopeNoteIndex_;
2736 : Kind kind_;
2737 :
2738 : NonLocalExitControl(const NonLocalExitControl&) = delete;
2739 :
2740 : MOZ_MUST_USE bool leaveScope(BytecodeEmitter::EmitterScope* scope);
2741 :
2742 : public:
2743 6764 : NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
2744 6764 : : bce_(bce),
2745 6764 : savedScopeNoteIndex_(bce->scopeNoteList.length()),
2746 6764 : savedDepth_(bce->stackDepth),
2747 6764 : openScopeNoteIndex_(bce->innermostEmitterScope->noteIndex()),
2748 27056 : kind_(kind)
2749 6764 : { }
2750 :
2751 13528 : ~NonLocalExitControl() {
2752 8819 : for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length(); n++)
2753 2055 : bce_->scopeNoteList.recordEnd(n, bce_->offset(), bce_->inPrologue());
2754 6764 : bce_->stackDepth = savedDepth_;
2755 6764 : }
2756 :
2757 : MOZ_MUST_USE bool prepareForNonLocalJump(BytecodeEmitter::NestableControl* target);
2758 :
2759 6164 : MOZ_MUST_USE bool prepareForNonLocalJumpToOutermost() {
2760 6164 : return prepareForNonLocalJump(nullptr);
2761 : }
2762 : };
2763 :
2764 : bool
2765 2055 : NonLocalExitControl::leaveScope(BytecodeEmitter::EmitterScope* es)
2766 : {
2767 2055 : if (!es->leave(bce_, /* nonLocal = */ true))
2768 0 : return false;
2769 :
2770 : // As we pop each scope due to the non-local jump, emit notes that
2771 : // record the extent of the enclosing scope. These notes will have
2772 : // their ends recorded in ~NonLocalExitControl().
2773 2055 : uint32_t enclosingScopeIndex = ScopeNote::NoScopeIndex;
2774 2055 : if (es->enclosingInFrame())
2775 2055 : enclosingScopeIndex = es->enclosingInFrame()->index();
2776 2055 : if (!bce_->scopeNoteList.append(enclosingScopeIndex, bce_->offset(), bce_->inPrologue(),
2777 : openScopeNoteIndex_))
2778 0 : return false;
2779 2055 : openScopeNoteIndex_ = bce_->scopeNoteList.length() - 1;
2780 :
2781 2055 : return true;
2782 : }
2783 :
2784 : /*
2785 : * Emit additional bytecode(s) for non-local jumps.
2786 : */
2787 : bool
2788 6764 : NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* target)
2789 : {
2790 : using NestableControl = BytecodeEmitter::NestableControl;
2791 : using EmitterScope = BytecodeEmitter::EmitterScope;
2792 :
2793 6764 : EmitterScope* es = bce_->innermostEmitterScope;
2794 6764 : int npops = 0;
2795 :
2796 : // For 'continue', 'break', and 'return' statements, emit IteratorClose
2797 : // bytecode inline. 'continue' statements do not call IteratorClose for
2798 : // the loop they are continuing.
2799 6764 : bool emitIteratorClose = kind_ == Continue || kind_ == Break || kind_ == Return;
2800 6764 : bool emitIteratorCloseAtTarget = emitIteratorClose && kind_ != Continue;
2801 :
2802 13652 : auto flushPops = [&npops](BytecodeEmitter* bce) {
2803 6826 : if (npops && !bce->emitPopN(npops))
2804 0 : return false;
2805 6826 : npops = 0;
2806 6826 : return true;
2807 6764 : };
2808 :
2809 : // Walk the nestable control stack and patch jumps.
2810 7849 : for (NestableControl* control = bce_->innermostNestableControl;
2811 7849 : control != target;
2812 1085 : control = control->enclosing())
2813 : {
2814 : // Walk the scope stack and leave the scopes we entered. Leaving a scope
2815 : // may emit administrative ops like JSOP_POPLEXICALENV but never anything
2816 : // that manipulates the stack.
2817 1539 : for (; es != control->emitterScope(); es = es->enclosingInFrame()) {
2818 227 : if (!leaveScope(es))
2819 0 : return false;
2820 : }
2821 :
2822 1085 : switch (control->kind()) {
2823 : case StatementKind::Finally: {
2824 16 : TryFinallyControl& finallyControl = control->as<TryFinallyControl>();
2825 16 : if (finallyControl.emittingSubroutine()) {
2826 : /*
2827 : * There's a [exception or hole, retsub pc-index] pair and the
2828 : * possible return value on the stack that we need to pop.
2829 : */
2830 0 : npops += 3;
2831 : } else {
2832 16 : if (!flushPops(bce_))
2833 0 : return false;
2834 16 : if (!bce_->emitJump(JSOP_GOSUB, &finallyControl.gosubs)) // ...
2835 0 : return false;
2836 : }
2837 16 : break;
2838 : }
2839 :
2840 : case StatementKind::ForOfLoop:
2841 46 : if (emitIteratorClose) {
2842 46 : if (!flushPops(bce_))
2843 0 : return false;
2844 :
2845 46 : ForOfLoopControl& loopinfo = control->as<ForOfLoopControl>();
2846 46 : if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ false)) // ...
2847 0 : return false;
2848 : } else {
2849 0 : npops += 2;
2850 : }
2851 46 : break;
2852 :
2853 : case StatementKind::ForInLoop:
2854 0 : if (!flushPops(bce_))
2855 0 : return false;
2856 :
2857 : // The iterator and the current value are on the stack.
2858 0 : if (!bce_->emit1(JSOP_POP)) // ... ITER
2859 0 : return false;
2860 0 : if (!bce_->emit1(JSOP_ENDITER)) // ...
2861 0 : return false;
2862 0 : break;
2863 :
2864 : default:
2865 1023 : break;
2866 : }
2867 : }
2868 :
2869 6764 : if (!flushPops(bce_))
2870 0 : return false;
2871 :
2872 6764 : if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
2873 11 : ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
2874 11 : if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ true)) // ... UNDEF UNDEF
2875 0 : return false;
2876 : }
2877 :
2878 6764 : EmitterScope* targetEmitterScope = target ? target->emitterScope() : bce_->varEmitterScope;
2879 10420 : for (; es != targetEmitterScope; es = es->enclosingInFrame()) {
2880 1828 : if (!leaveScope(es))
2881 0 : return false;
2882 : }
2883 :
2884 6764 : return true;
2885 : }
2886 :
2887 : } // anonymous namespace
2888 :
2889 : bool
2890 600 : BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist, SrcNoteType noteType)
2891 : {
2892 : NonLocalExitControl nle(this, noteType == SRC_CONTINUE
2893 : ? NonLocalExitControl::Continue
2894 1200 : : NonLocalExitControl::Break);
2895 :
2896 600 : if (!nle.prepareForNonLocalJump(target))
2897 0 : return false;
2898 :
2899 600 : if (noteType != SRC_NULL) {
2900 600 : if (!newSrcNote(noteType))
2901 0 : return false;
2902 : }
2903 :
2904 600 : return emitJump(JSOP_GOTO, jumplist);
2905 : }
2906 :
2907 : Scope*
2908 2981 : BytecodeEmitter::innermostScope() const
2909 : {
2910 2981 : return innermostEmitterScope->scope(this);
2911 : }
2912 :
2913 : bool
2914 13156 : BytecodeEmitter::emitIndex32(JSOp op, uint32_t index)
2915 : {
2916 13156 : MOZ_ASSERT(checkStrictOrSloppy(op));
2917 :
2918 13156 : const size_t len = 1 + UINT32_INDEX_LEN;
2919 13156 : MOZ_ASSERT(len == size_t(CodeSpec[op].length));
2920 :
2921 : ptrdiff_t offset;
2922 13156 : if (!emitCheck(len, &offset))
2923 0 : return false;
2924 :
2925 13156 : jsbytecode* code = this->code(offset);
2926 13156 : code[0] = jsbytecode(op);
2927 13156 : SET_UINT32_INDEX(code, index);
2928 13156 : checkTypeSet(op);
2929 13156 : updateDepth(offset);
2930 13156 : return true;
2931 : }
2932 :
2933 : bool
2934 69547 : BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index)
2935 : {
2936 69547 : MOZ_ASSERT(checkStrictOrSloppy(op));
2937 :
2938 69547 : const size_t len = CodeSpec[op].length;
2939 69547 : MOZ_ASSERT(len >= 1 + UINT32_INDEX_LEN);
2940 :
2941 : ptrdiff_t offset;
2942 69547 : if (!emitCheck(len, &offset))
2943 0 : return false;
2944 :
2945 69547 : jsbytecode* code = this->code(offset);
2946 69547 : code[0] = jsbytecode(op);
2947 69547 : SET_UINT32_INDEX(code, index);
2948 69547 : checkTypeSet(op);
2949 69547 : updateDepth(offset);
2950 69547 : return true;
2951 : }
2952 :
2953 : bool
2954 64667 : BytecodeEmitter::emitAtomOp(JSAtom* atom, JSOp op)
2955 : {
2956 64667 : MOZ_ASSERT(atom);
2957 64667 : MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
2958 :
2959 : // .generator lookups should be emitted as JSOP_GETALIASEDVAR instead of
2960 : // JSOP_GETNAME etc, to bypass |with| objects on the scope chain.
2961 : // It's safe to emit .this lookups though because |with| objects skip
2962 : // those.
2963 64667 : MOZ_ASSERT_IF(op == JSOP_GETNAME || op == JSOP_GETGNAME,
2964 : atom != cx->names().dotGenerator);
2965 :
2966 64667 : if (op == JSOP_GETPROP && atom == cx->names().length) {
2967 : /* Specialize length accesses for the interpreter. */
2968 1232 : op = JSOP_LENGTH;
2969 : }
2970 :
2971 : uint32_t index;
2972 64667 : if (!makeAtomIndex(atom, &index))
2973 0 : return false;
2974 :
2975 64667 : return emitIndexOp(op, index);
2976 : }
2977 :
2978 : bool
2979 37557 : BytecodeEmitter::emitAtomOp(ParseNode* pn, JSOp op)
2980 : {
2981 37557 : MOZ_ASSERT(pn->pn_atom != nullptr);
2982 37557 : return emitAtomOp(pn->pn_atom, op);
2983 : }
2984 :
2985 : bool
2986 465 : BytecodeEmitter::emitInternedScopeOp(uint32_t index, JSOp op)
2987 : {
2988 465 : MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE);
2989 465 : MOZ_ASSERT(index < scopeList.length());
2990 465 : return emitIndex32(op, index);
2991 : }
2992 :
2993 : bool
2994 488 : BytecodeEmitter::emitInternedObjectOp(uint32_t index, JSOp op)
2995 : {
2996 488 : MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
2997 488 : MOZ_ASSERT(index < objectList.length);
2998 488 : return emitIndex32(op, index);
2999 : }
3000 :
3001 : bool
3002 487 : BytecodeEmitter::emitObjectOp(ObjectBox* objbox, JSOp op)
3003 : {
3004 487 : return emitInternedObjectOp(objectList.add(objbox), op);
3005 : }
3006 :
3007 : bool
3008 1 : BytecodeEmitter::emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op)
3009 : {
3010 1 : uint32_t index = objectList.add(objbox1);
3011 1 : objectList.add(objbox2);
3012 1 : return emitInternedObjectOp(index, op);
3013 : }
3014 :
3015 : bool
3016 172 : BytecodeEmitter::emitRegExp(uint32_t index)
3017 : {
3018 172 : return emitIndex32(JSOP_REGEXP, index);
3019 : }
3020 :
3021 : bool
3022 47040 : BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot)
3023 : {
3024 47040 : MOZ_ASSERT(JOF_OPTYPE(op) != JOF_ENVCOORD);
3025 47040 : MOZ_ASSERT(IsLocalOp(op));
3026 :
3027 : ptrdiff_t off;
3028 47040 : if (!emitN(op, LOCALNO_LEN, &off))
3029 0 : return false;
3030 :
3031 47040 : SET_LOCALNO(code(off), slot);
3032 47040 : return true;
3033 : }
3034 :
3035 : bool
3036 14802 : BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot)
3037 : {
3038 14802 : MOZ_ASSERT(IsArgOp(op));
3039 : ptrdiff_t off;
3040 14802 : if (!emitN(op, ARGNO_LEN, &off))
3041 0 : return false;
3042 :
3043 14802 : SET_ARGNO(code(off), slot);
3044 14802 : return true;
3045 : }
3046 :
3047 : bool
3048 8054 : BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec)
3049 : {
3050 8054 : MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ENVCOORD);
3051 :
3052 8054 : unsigned n = ENVCOORD_HOPS_LEN + ENVCOORD_SLOT_LEN;
3053 8054 : MOZ_ASSERT(int(n) + 1 /* op */ == CodeSpec[op].length);
3054 :
3055 : ptrdiff_t off;
3056 8054 : if (!emitN(op, n, &off))
3057 0 : return false;
3058 :
3059 8054 : jsbytecode* pc = code(off);
3060 8054 : SET_ENVCOORD_HOPS(pc, ec.hops());
3061 8054 : pc += ENVCOORD_HOPS_LEN;
3062 8054 : SET_ENVCOORD_SLOT(pc, ec.slot());
3063 8054 : pc += ENVCOORD_SLOT_LEN;
3064 8054 : checkTypeSet(op);
3065 8054 : return true;
3066 : }
3067 :
3068 : static JSOp
3069 705 : GetIncDecInfo(ParseNodeKind kind, bool* post)
3070 : {
3071 705 : MOZ_ASSERT(kind == PNK_POSTINCREMENT || kind == PNK_PREINCREMENT ||
3072 : kind == PNK_POSTDECREMENT || kind == PNK_PREDECREMENT);
3073 705 : *post = kind == PNK_POSTINCREMENT || kind == PNK_POSTDECREMENT;
3074 705 : return (kind == PNK_POSTINCREMENT || kind == PNK_PREINCREMENT) ? JSOP_ADD : JSOP_SUB;
3075 : }
3076 :
3077 : JSOp
3078 452 : BytecodeEmitter::strictifySetNameOp(JSOp op)
3079 : {
3080 452 : switch (op) {
3081 : case JSOP_SETNAME:
3082 35 : if (sc->strict())
3083 35 : op = JSOP_STRICTSETNAME;
3084 35 : break;
3085 : case JSOP_SETGNAME:
3086 417 : if (sc->strict())
3087 333 : op = JSOP_STRICTSETGNAME;
3088 417 : break;
3089 : default:;
3090 : }
3091 452 : return op;
3092 : }
3093 :
3094 : bool
3095 14039 : BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
3096 : {
3097 14039 : if (!CheckRecursionLimit(cx))
3098 0 : return false;
3099 :
3100 : restart:
3101 :
3102 14039 : switch (pn->getKind()) {
3103 : // Trivial cases with no side effects.
3104 : case PNK_NOP:
3105 : case PNK_STRING:
3106 : case PNK_TEMPLATE_STRING:
3107 : case PNK_REGEXP:
3108 : case PNK_TRUE:
3109 : case PNK_FALSE:
3110 : case PNK_NULL:
3111 : case PNK_RAW_UNDEFINED:
3112 : case PNK_ELISION:
3113 : case PNK_GENERATOR:
3114 : case PNK_NUMBER:
3115 : case PNK_OBJECT_PROPERTY_NAME:
3116 107 : MOZ_ASSERT(pn->isArity(PN_NULLARY));
3117 107 : *answer = false;
3118 107 : return true;
3119 :
3120 : // |this| can throw in derived class constructors, including nested arrow
3121 : // functions or eval.
3122 : case PNK_THIS:
3123 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3124 0 : *answer = sc->needsThisTDZChecks();
3125 0 : return true;
3126 :
3127 : // Trivial binary nodes with more token pos holders.
3128 : case PNK_NEWTARGET:
3129 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3130 0 : MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER));
3131 0 : MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER));
3132 0 : *answer = false;
3133 0 : return true;
3134 :
3135 : case PNK_BREAK:
3136 : case PNK_CONTINUE:
3137 : case PNK_DEBUGGER:
3138 0 : MOZ_ASSERT(pn->isArity(PN_NULLARY));
3139 0 : *answer = true;
3140 0 : return true;
3141 :
3142 : // Watch out for getters!
3143 : case PNK_DOT:
3144 3 : MOZ_ASSERT(pn->isArity(PN_NAME));
3145 3 : *answer = true;
3146 3 : return true;
3147 :
3148 : // Unary cases with side effects only if the child has them.
3149 : case PNK_TYPEOFEXPR:
3150 : case PNK_VOID:
3151 : case PNK_NOT:
3152 6 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3153 6 : return checkSideEffects(pn->pn_kid, answer);
3154 :
3155 : // Even if the name expression is effect-free, performing ToPropertyKey on
3156 : // it might not be effect-free:
3157 : //
3158 : // RegExp.prototype.toString = () => { throw 42; };
3159 : // ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
3160 : //
3161 : // function Q() {
3162 : // ({ [new.target]: 0 });
3163 : // }
3164 : // Q.toString = () => { throw 17; };
3165 : // new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
3166 : case PNK_COMPUTED_NAME:
3167 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3168 0 : *answer = true;
3169 0 : return true;
3170 :
3171 : // Looking up or evaluating the associated name could throw.
3172 : case PNK_TYPEOFNAME:
3173 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3174 0 : *answer = true;
3175 0 : return true;
3176 :
3177 : // These unary cases have side effects on the enclosing object/array,
3178 : // sure. But that's not the question this function answers: it's
3179 : // whether the operation may have a side effect on something *other* than
3180 : // the result of the overall operation in which it's embedded. The
3181 : // answer to that is no, for an object literal having a mutated prototype
3182 : // and an array comprehension containing no other effectful operations
3183 : // only produce a value, without affecting anything else.
3184 : case PNK_MUTATEPROTO:
3185 : case PNK_ARRAYPUSH:
3186 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3187 0 : return checkSideEffects(pn->pn_kid, answer);
3188 :
3189 : // Unary cases with obvious side effects.
3190 : case PNK_PREINCREMENT:
3191 : case PNK_POSTINCREMENT:
3192 : case PNK_PREDECREMENT:
3193 : case PNK_POSTDECREMENT:
3194 : case PNK_THROW:
3195 182 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3196 182 : *answer = true;
3197 182 : return true;
3198 :
3199 : // These might invoke valueOf/toString, even with a subexpression without
3200 : // side effects! Consider |+{ valueOf: null, toString: null }|.
3201 : case PNK_BITNOT:
3202 : case PNK_POS:
3203 : case PNK_NEG:
3204 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3205 0 : *answer = true;
3206 0 : return true;
3207 :
3208 : // This invokes the (user-controllable) iterator protocol.
3209 : case PNK_SPREAD:
3210 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3211 0 : *answer = true;
3212 0 : return true;
3213 :
3214 : case PNK_INITIALYIELD:
3215 : case PNK_YIELD_STAR:
3216 : case PNK_YIELD:
3217 : case PNK_AWAIT:
3218 157 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3219 157 : *answer = true;
3220 157 : return true;
3221 :
3222 : // Deletion generally has side effects, even if isolated cases have none.
3223 : case PNK_DELETENAME:
3224 : case PNK_DELETEPROP:
3225 : case PNK_DELETEELEM:
3226 82 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3227 82 : *answer = true;
3228 82 : return true;
3229 :
3230 : // Deletion of a non-Reference expression has side effects only through
3231 : // evaluating the expression.
3232 : case PNK_DELETEEXPR: {
3233 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3234 0 : ParseNode* expr = pn->pn_kid;
3235 0 : return checkSideEffects(expr, answer);
3236 : }
3237 :
3238 : case PNK_SEMI:
3239 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3240 0 : if (ParseNode* expr = pn->pn_kid)
3241 0 : return checkSideEffects(expr, answer);
3242 0 : *answer = false;
3243 0 : return true;
3244 :
3245 : // Binary cases with obvious side effects.
3246 : case PNK_ASSIGN:
3247 : case PNK_ADDASSIGN:
3248 : case PNK_SUBASSIGN:
3249 : case PNK_BITORASSIGN:
3250 : case PNK_BITXORASSIGN:
3251 : case PNK_BITANDASSIGN:
3252 : case PNK_LSHASSIGN:
3253 : case PNK_RSHASSIGN:
3254 : case PNK_URSHASSIGN:
3255 : case PNK_MULASSIGN:
3256 : case PNK_DIVASSIGN:
3257 : case PNK_MODASSIGN:
3258 : case PNK_POWASSIGN:
3259 : case PNK_SETTHIS:
3260 5394 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3261 5394 : *answer = true;
3262 5394 : return true;
3263 :
3264 : case PNK_STATEMENTLIST:
3265 : case PNK_CATCHLIST:
3266 : // Strict equality operations and logical operators are well-behaved and
3267 : // perform no conversions.
3268 : case PNK_OR:
3269 : case PNK_AND:
3270 : case PNK_STRICTEQ:
3271 : case PNK_STRICTNE:
3272 : // Any subexpression of a comma expression could be effectful.
3273 : case PNK_COMMA:
3274 9 : MOZ_ASSERT(pn->pn_count > 0);
3275 : MOZ_FALLTHROUGH;
3276 : // Subcomponents of a literal may be effectful.
3277 : case PNK_ARRAY:
3278 : case PNK_OBJECT:
3279 9 : MOZ_ASSERT(pn->isArity(PN_LIST));
3280 9 : for (ParseNode* item = pn->pn_head; item; item = item->pn_next) {
3281 9 : if (!checkSideEffects(item, answer))
3282 0 : return false;
3283 9 : if (*answer)
3284 9 : return true;
3285 : }
3286 0 : return true;
3287 :
3288 : // Most other binary operations (parsed as lists in SpiderMonkey) may
3289 : // perform conversions triggering side effects. Math operations perform
3290 : // ToNumber and may fail invoking invalid user-defined toString/valueOf:
3291 : // |5 < { toString: null }|. |instanceof| throws if provided a
3292 : // non-object constructor: |null instanceof null|. |in| throws if given
3293 : // a non-object RHS: |5 in null|.
3294 : case PNK_BITOR:
3295 : case PNK_BITXOR:
3296 : case PNK_BITAND:
3297 : case PNK_EQ:
3298 : case PNK_NE:
3299 : case PNK_LT:
3300 : case PNK_LE:
3301 : case PNK_GT:
3302 : case PNK_GE:
3303 : case PNK_INSTANCEOF:
3304 : case PNK_IN:
3305 : case PNK_LSH:
3306 : case PNK_RSH:
3307 : case PNK_URSH:
3308 : case PNK_ADD:
3309 : case PNK_SUB:
3310 : case PNK_STAR:
3311 : case PNK_DIV:
3312 : case PNK_MOD:
3313 : case PNK_POW:
3314 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3315 0 : MOZ_ASSERT(pn->pn_count >= 2);
3316 0 : *answer = true;
3317 0 : return true;
3318 :
3319 : case PNK_COLON:
3320 : case PNK_CASE:
3321 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3322 0 : if (!checkSideEffects(pn->pn_left, answer))
3323 0 : return false;
3324 0 : if (*answer)
3325 0 : return true;
3326 0 : return checkSideEffects(pn->pn_right, answer);
3327 :
3328 : // More getters.
3329 : case PNK_ELEM:
3330 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3331 0 : *answer = true;
3332 0 : return true;
3333 :
3334 : // These affect visible names in this code, or in other code.
3335 : case PNK_IMPORT:
3336 : case PNK_EXPORT_FROM:
3337 : case PNK_EXPORT_DEFAULT:
3338 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3339 0 : *answer = true;
3340 0 : return true;
3341 :
3342 : // Likewise.
3343 : case PNK_EXPORT:
3344 0 : MOZ_ASSERT(pn->isArity(PN_UNARY));
3345 0 : *answer = true;
3346 0 : return true;
3347 :
3348 : // Every part of a loop might be effect-free, but looping infinitely *is*
3349 : // an effect. (Language lawyer trivia: C++ says threads can be assumed
3350 : // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
3351 : // implementation's equivalent of the below could set |*answer = false;|
3352 : // if all loop sub-nodes set |*answer = false|!)
3353 : case PNK_DOWHILE:
3354 : case PNK_WHILE:
3355 : case PNK_FOR:
3356 : case PNK_COMPREHENSIONFOR:
3357 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3358 0 : *answer = true;
3359 0 : return true;
3360 :
3361 : // Declarations affect the name set of the relevant scope.
3362 : case PNK_VAR:
3363 : case PNK_CONST:
3364 : case PNK_LET:
3365 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3366 0 : *answer = true;
3367 0 : return true;
3368 :
3369 : case PNK_IF:
3370 : case PNK_CONDITIONAL:
3371 0 : MOZ_ASSERT(pn->isArity(PN_TERNARY));
3372 0 : if (!checkSideEffects(pn->pn_kid1, answer))
3373 0 : return false;
3374 0 : if (*answer)
3375 0 : return true;
3376 0 : if (!checkSideEffects(pn->pn_kid2, answer))
3377 0 : return false;
3378 0 : if (*answer)
3379 0 : return true;
3380 0 : if ((pn = pn->pn_kid3))
3381 0 : goto restart;
3382 0 : return true;
3383 :
3384 : // Function calls can invoke non-local code.
3385 : case PNK_NEW:
3386 : case PNK_CALL:
3387 : case PNK_TAGGED_TEMPLATE:
3388 : case PNK_SUPERCALL:
3389 8092 : MOZ_ASSERT(pn->isArity(PN_LIST));
3390 8092 : *answer = true;
3391 8092 : return true;
3392 :
3393 : // Classes typically introduce names. Even if no name is introduced,
3394 : // the heritage and/or class body (through computed property names)
3395 : // usually have effects.
3396 : case PNK_CLASS:
3397 0 : MOZ_ASSERT(pn->isArity(PN_TERNARY));
3398 0 : *answer = true;
3399 0 : return true;
3400 :
3401 : // |with| calls |ToObject| on its expression and so throws if that value
3402 : // is null/undefined.
3403 : case PNK_WITH:
3404 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3405 0 : *answer = true;
3406 0 : return true;
3407 :
3408 : case PNK_RETURN:
3409 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3410 0 : *answer = true;
3411 0 : return true;
3412 :
3413 : case PNK_NAME:
3414 7 : MOZ_ASSERT(pn->isArity(PN_NAME));
3415 7 : *answer = true;
3416 7 : return true;
3417 :
3418 : // Shorthands could trigger getters: the |x| in the object literal in
3419 : // |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
3420 : // one. (Of course, it isn't necessary to use |with| for a shorthand to
3421 : // trigger a getter.)
3422 : case PNK_SHORTHAND:
3423 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3424 0 : *answer = true;
3425 0 : return true;
3426 :
3427 : case PNK_FUNCTION:
3428 0 : MOZ_ASSERT(pn->isArity(PN_CODE));
3429 : /*
3430 : * A named function, contrary to ES3, is no longer effectful, because
3431 : * we bind its name lexically (using JSOP_CALLEE) instead of creating
3432 : * an Object instance and binding a readonly, permanent property in it
3433 : * (the object and binding can be detected and hijacked or captured).
3434 : * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
3435 : */
3436 0 : *answer = false;
3437 0 : return true;
3438 :
3439 : case PNK_MODULE:
3440 0 : *answer = false;
3441 0 : return true;
3442 :
3443 : // Generator expressions have no side effects on their own.
3444 : case PNK_GENEXP:
3445 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3446 0 : *answer = false;
3447 0 : return true;
3448 :
3449 : case PNK_TRY:
3450 0 : MOZ_ASSERT(pn->isArity(PN_TERNARY));
3451 0 : if (!checkSideEffects(pn->pn_kid1, answer))
3452 0 : return false;
3453 0 : if (*answer)
3454 0 : return true;
3455 0 : if (ParseNode* catchList = pn->pn_kid2) {
3456 0 : MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
3457 0 : if (!checkSideEffects(catchList, answer))
3458 0 : return false;
3459 0 : if (*answer)
3460 0 : return true;
3461 : }
3462 0 : if (ParseNode* finallyBlock = pn->pn_kid3) {
3463 0 : if (!checkSideEffects(finallyBlock, answer))
3464 0 : return false;
3465 : }
3466 0 : return true;
3467 :
3468 : case PNK_CATCH:
3469 0 : MOZ_ASSERT(pn->isArity(PN_TERNARY));
3470 0 : if (!checkSideEffects(pn->pn_kid1, answer))
3471 0 : return false;
3472 0 : if (*answer)
3473 0 : return true;
3474 0 : if (ParseNode* cond = pn->pn_kid2) {
3475 0 : if (!checkSideEffects(cond, answer))
3476 0 : return false;
3477 0 : if (*answer)
3478 0 : return true;
3479 : }
3480 0 : return checkSideEffects(pn->pn_kid3, answer);
3481 :
3482 : case PNK_SWITCH:
3483 0 : MOZ_ASSERT(pn->isArity(PN_BINARY));
3484 0 : if (!checkSideEffects(pn->pn_left, answer))
3485 0 : return false;
3486 0 : return *answer || checkSideEffects(pn->pn_right, answer);
3487 :
3488 : case PNK_LABEL:
3489 0 : MOZ_ASSERT(pn->isArity(PN_NAME));
3490 0 : return checkSideEffects(pn->expr(), answer);
3491 :
3492 : case PNK_LEXICALSCOPE:
3493 0 : MOZ_ASSERT(pn->isArity(PN_SCOPE));
3494 0 : return checkSideEffects(pn->scopeBody(), answer);
3495 :
3496 : // We could methodically check every interpolated expression, but it's
3497 : // probably not worth the trouble. Treat template strings as effect-free
3498 : // only if they don't contain any substitutions.
3499 : case PNK_TEMPLATE_STRING_LIST:
3500 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3501 0 : MOZ_ASSERT(pn->pn_count > 0);
3502 0 : MOZ_ASSERT((pn->pn_count % 2) == 1,
3503 : "template strings must alternate template and substitution "
3504 : "parts");
3505 0 : *answer = pn->pn_count > 1;
3506 0 : return true;
3507 :
3508 : case PNK_ARRAYCOMP:
3509 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
3510 0 : MOZ_ASSERT(pn->pn_count == 1);
3511 0 : return checkSideEffects(pn->pn_head, answer);
3512 :
3513 : // This should be unreachable but is left as-is for now.
3514 : case PNK_PARAMSBODY:
3515 0 : *answer = true;
3516 0 : return true;
3517 :
3518 : case PNK_FORIN: // by PNK_FOR/PNK_COMPREHENSIONFOR
3519 : case PNK_FOROF: // by PNK_FOR/PNK_COMPREHENSIONFOR
3520 : case PNK_FORHEAD: // by PNK_FOR/PNK_COMPREHENSIONFOR
3521 : case PNK_CLASSMETHOD: // by PNK_CLASS
3522 : case PNK_CLASSNAMES: // by PNK_CLASS
3523 : case PNK_CLASSMETHODLIST: // by PNK_CLASS
3524 : case PNK_IMPORT_SPEC_LIST: // by PNK_IMPORT
3525 : case PNK_IMPORT_SPEC: // by PNK_IMPORT
3526 : case PNK_EXPORT_BATCH_SPEC:// by PNK_EXPORT
3527 : case PNK_EXPORT_SPEC_LIST: // by PNK_EXPORT
3528 : case PNK_EXPORT_SPEC: // by PNK_EXPORT
3529 : case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
3530 : case PNK_POSHOLDER: // by PNK_NEWTARGET
3531 : case PNK_SUPERBASE: // by PNK_ELEM and others
3532 0 : MOZ_CRASH("handled by parent nodes");
3533 :
3534 : case PNK_LIMIT: // invalid sentinel value
3535 0 : MOZ_CRASH("invalid node kind");
3536 : }
3537 :
3538 0 : MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in "
3539 : "BytecodeEmitter::checkSideEffects");
3540 : }
3541 :
3542 : bool
3543 5883 : BytecodeEmitter::isInLoop()
3544 : {
3545 5883 : return findInnermostNestableControl<LoopControl>();
3546 : }
3547 :
3548 : bool
3549 6575 : BytecodeEmitter::checkSingletonContext()
3550 : {
3551 6575 : if (!script->treatAsRunOnce() || sc->isFunctionBox() || isInLoop())
3552 5135 : return false;
3553 1440 : hasSingletons = true;
3554 1440 : return true;
3555 : }
3556 :
3557 : bool
3558 5842 : BytecodeEmitter::checkRunOnceContext()
3559 : {
3560 5842 : return checkSingletonContext() || (!isInLoop() && isRunOnceLambda());
3561 : }
3562 :
3563 : bool
3564 264 : BytecodeEmitter::needsImplicitThis()
3565 : {
3566 : // Short-circuit if there is an enclosing 'with' scope.
3567 264 : if (sc->inWith())
3568 0 : return true;
3569 :
3570 : // Otherwise see if the current point is under a 'with'.
3571 638 : for (EmitterScope* es = innermostEmitterScope; es; es = es->enclosingInFrame()) {
3572 374 : if (es->scope(this)->kind() == ScopeKind::With)
3573 0 : return true;
3574 : }
3575 :
3576 264 : return false;
3577 : }
3578 :
3579 : bool
3580 284 : BytecodeEmitter::maybeSetDisplayURL()
3581 : {
3582 284 : if (tokenStream().hasDisplayURL()) {
3583 2 : if (!parser.ss()->setDisplayURL(cx, tokenStream().displayURL()))
3584 0 : return false;
3585 : }
3586 284 : return true;
3587 : }
3588 :
3589 : bool
3590 284 : BytecodeEmitter::maybeSetSourceMap()
3591 : {
3592 284 : if (tokenStream().hasSourceMapURL()) {
3593 0 : MOZ_ASSERT(!parser.ss()->hasSourceMapURL());
3594 0 : if (!parser.ss()->setSourceMapURL(cx, tokenStream().sourceMapURL()))
3595 0 : return false;
3596 : }
3597 :
3598 : /*
3599 : * Source map URLs passed as a compile option (usually via a HTTP source map
3600 : * header) override any source map urls passed as comment pragmas.
3601 : */
3602 284 : if (parser.options().sourceMapURL()) {
3603 : // Warn about the replacement, but use the new one.
3604 0 : if (parser.ss()->hasSourceMapURL()) {
3605 0 : if (!parser.reportNoOffset(ParseWarning, false, JSMSG_ALREADY_HAS_PRAGMA,
3606 0 : parser.ss()->filename(), "//# sourceMappingURL"))
3607 : {
3608 0 : return false;
3609 : }
3610 : }
3611 :
3612 0 : if (!parser.ss()->setSourceMapURL(cx, parser.options().sourceMapURL()))
3613 0 : return false;
3614 : }
3615 :
3616 284 : return true;
3617 : }
3618 :
3619 : void
3620 284 : BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext* cx)
3621 : {
3622 : // Note: when parsing off thread the resulting scripts need to be handed to
3623 : // the debugger after rejoining to the active thread.
3624 284 : if (cx->helperThread())
3625 0 : return;
3626 :
3627 : // Lazy scripts are never top level (despite always being invoked with a
3628 : // nullptr parent), and so the hook should never be fired.
3629 284 : if (emitterMode != LazyFunction && !parent)
3630 284 : Debugger::onNewScript(cx, script);
3631 : }
3632 :
3633 : inline TokenStreamAnyChars&
3634 6244 : BytecodeEmitter::tokenStream()
3635 : {
3636 6244 : return parser.tokenStream();
3637 : }
3638 :
3639 : void
3640 0 : BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
3641 : {
3642 0 : TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
3643 :
3644 : va_list args;
3645 0 : va_start(args, errorNumber);
3646 :
3647 0 : ErrorMetadata metadata;
3648 0 : if (parser.computeErrorMetadata(&metadata, pos.begin))
3649 0 : ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
3650 :
3651 0 : va_end(args);
3652 0 : }
3653 :
3654 : bool
3655 0 : BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
3656 : {
3657 0 : TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
3658 :
3659 : va_list args;
3660 0 : va_start(args, errorNumber);
3661 :
3662 0 : bool result = parser.reportExtraWarningErrorNumberVA(nullptr, pos.begin, errorNumber, args);
3663 :
3664 0 : va_end(args);
3665 0 : return result;
3666 : }
3667 :
3668 : bool
3669 0 : BytecodeEmitter::reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...)
3670 : {
3671 0 : TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
3672 :
3673 : va_list args;
3674 0 : va_start(args, errorNumber);
3675 0 : bool result = parser.reportStrictModeErrorNumberVA(nullptr, pos.begin, sc->strict(),
3676 0 : errorNumber, args);
3677 0 : va_end(args);
3678 0 : return result;
3679 : }
3680 :
3681 : bool
3682 1656 : BytecodeEmitter::emitNewInit(JSProtoKey key)
3683 : {
3684 1656 : const size_t len = 1 + UINT32_INDEX_LEN;
3685 : ptrdiff_t offset;
3686 1656 : if (!emitCheck(len, &offset))
3687 0 : return false;
3688 :
3689 1656 : jsbytecode* code = this->code(offset);
3690 1656 : code[0] = JSOP_NEWINIT;
3691 1656 : code[1] = jsbytecode(key);
3692 1656 : code[2] = 0;
3693 1656 : code[3] = 0;
3694 1656 : code[4] = 0;
3695 1656 : checkTypeSet(JSOP_NEWINIT);
3696 1656 : updateDepth(offset);
3697 1656 : return true;
3698 : }
3699 :
3700 : bool
3701 33 : BytecodeEmitter::iteratorResultShape(unsigned* shape)
3702 : {
3703 : // No need to do any guessing for the object kind, since we know exactly how
3704 : // many properties we plan to have.
3705 33 : gc::AllocKind kind = gc::GetGCObjectKind(2);
3706 66 : RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
3707 33 : if (!obj)
3708 0 : return false;
3709 :
3710 66 : Rooted<jsid> value_id(cx, AtomToId(cx->names().value));
3711 66 : Rooted<jsid> done_id(cx, AtomToId(cx->names().done));
3712 33 : if (!NativeDefineProperty(cx, obj, value_id, UndefinedHandleValue, nullptr, nullptr,
3713 : JSPROP_ENUMERATE))
3714 : {
3715 0 : return false;
3716 : }
3717 33 : if (!NativeDefineProperty(cx, obj, done_id, UndefinedHandleValue, nullptr, nullptr,
3718 : JSPROP_ENUMERATE))
3719 : {
3720 0 : return false;
3721 : }
3722 :
3723 33 : ObjectBox* objbox = parser.newObjectBox(obj);
3724 33 : if (!objbox)
3725 0 : return false;
3726 :
3727 33 : *shape = objectList.add(objbox);
3728 :
3729 33 : return true;
3730 : }
3731 :
3732 : bool
3733 33 : BytecodeEmitter::emitPrepareIteratorResult()
3734 : {
3735 : unsigned shape;
3736 33 : if (!iteratorResultShape(&shape))
3737 0 : return false;
3738 33 : return emitIndex32(JSOP_NEWOBJECT, shape);
3739 : }
3740 :
3741 : bool
3742 33 : BytecodeEmitter::emitFinishIteratorResult(bool done)
3743 : {
3744 : uint32_t value_id;
3745 33 : if (!makeAtomIndex(cx->names().value, &value_id))
3746 0 : return false;
3747 : uint32_t done_id;
3748 33 : if (!makeAtomIndex(cx->names().done, &done_id))
3749 0 : return false;
3750 :
3751 33 : if (!emitIndex32(JSOP_INITPROP, value_id))
3752 0 : return false;
3753 33 : if (!emit1(done ? JSOP_TRUE : JSOP_FALSE))
3754 0 : return false;
3755 33 : if (!emitIndex32(JSOP_INITPROP, done_id))
3756 0 : return false;
3757 33 : return true;
3758 : }
3759 :
3760 : bool
3761 0 : BytecodeEmitter::emitToIteratorResult(bool done)
3762 : {
3763 0 : if (!emitPrepareIteratorResult()) // VALUE OBJ
3764 0 : return false;
3765 0 : if (!emit1(JSOP_SWAP)) // OBJ VALUE
3766 0 : return false;
3767 0 : if (!emitFinishIteratorResult(done)) // RESULT
3768 0 : return false;
3769 0 : return true;
3770 : }
3771 :
3772 : bool
3773 70685 : BytecodeEmitter::emitGetNameAtLocation(JSAtom* name, const NameLocation& loc, bool callContext)
3774 : {
3775 70685 : switch (loc.kind()) {
3776 : case NameLocation::Kind::Dynamic:
3777 1395 : if (!emitAtomOp(name, JSOP_GETNAME))
3778 0 : return false;
3779 1395 : break;
3780 :
3781 : case NameLocation::Kind::Global:
3782 11113 : if (!emitAtomOp(name, JSOP_GETGNAME))
3783 0 : return false;
3784 11113 : break;
3785 :
3786 : case NameLocation::Kind::Intrinsic:
3787 9273 : if (!emitAtomOp(name, JSOP_GETINTRINSIC))
3788 0 : return false;
3789 9273 : break;
3790 :
3791 : case NameLocation::Kind::NamedLambdaCallee:
3792 25 : if (!emit1(JSOP_CALLEE))
3793 0 : return false;
3794 25 : break;
3795 :
3796 : case NameLocation::Kind::Import:
3797 0 : if (!emitAtomOp(name, JSOP_GETIMPORT))
3798 0 : return false;
3799 0 : break;
3800 :
3801 : case NameLocation::Kind::ArgumentSlot:
3802 14065 : if (!emitArgOp(JSOP_GETARG, loc.argumentSlot()))
3803 0 : return false;
3804 14065 : break;
3805 :
3806 : case NameLocation::Kind::FrameSlot:
3807 28813 : if (loc.isLexical()) {
3808 9809 : if (!emitTDZCheckIfNeeded(name, loc))
3809 0 : return false;
3810 : }
3811 28813 : if (!emitLocalOp(JSOP_GETLOCAL, loc.frameSlot()))
3812 0 : return false;
3813 28813 : break;
3814 :
3815 : case NameLocation::Kind::EnvironmentCoordinate:
3816 6001 : if (loc.isLexical()) {
3817 1945 : if (!emitTDZCheckIfNeeded(name, loc))
3818 0 : return false;
3819 : }
3820 6001 : if (!emitEnvCoordOp(JSOP_GETALIASEDVAR, loc.environmentCoordinate()))
3821 0 : return false;
3822 6001 : break;
3823 :
3824 : case NameLocation::Kind::DynamicAnnexBVar:
3825 0 : MOZ_CRASH("Synthesized vars for Annex B.3.3 should only be used in initialization");
3826 : }
3827 :
3828 : // Need to provide |this| value for call.
3829 70685 : if (callContext) {
3830 8545 : switch (loc.kind()) {
3831 : case NameLocation::Kind::Dynamic: {
3832 264 : JSOp thisOp = needsImplicitThis() ? JSOP_IMPLICITTHIS : JSOP_GIMPLICITTHIS;
3833 264 : if (!emitAtomOp(name, thisOp))
3834 0 : return false;
3835 264 : break;
3836 : }
3837 :
3838 : case NameLocation::Kind::Global:
3839 887 : if (!emitAtomOp(name, JSOP_GIMPLICITTHIS))
3840 0 : return false;
3841 887 : break;
3842 :
3843 : case NameLocation::Kind::Intrinsic:
3844 : case NameLocation::Kind::NamedLambdaCallee:
3845 : case NameLocation::Kind::Import:
3846 : case NameLocation::Kind::ArgumentSlot:
3847 : case NameLocation::Kind::FrameSlot:
3848 : case NameLocation::Kind::EnvironmentCoordinate:
3849 7394 : if (!emit1(JSOP_UNDEFINED))
3850 0 : return false;
3851 7394 : break;
3852 :
3853 : case NameLocation::Kind::DynamicAnnexBVar:
3854 0 : MOZ_CRASH("Synthesized vars for Annex B.3.3 should only be used in initialization");
3855 : }
3856 : }
3857 :
3858 70685 : return true;
3859 : }
3860 :
3861 : bool
3862 69149 : BytecodeEmitter::emitGetName(ParseNode* pn, bool callContext)
3863 : {
3864 69149 : return emitGetName(pn->name(), callContext);
3865 : }
3866 :
3867 : template <typename RHSEmitter>
3868 : bool
3869 16995 : BytecodeEmitter::emitSetOrInitializeNameAtLocation(HandleAtom name, const NameLocation& loc,
3870 : RHSEmitter emitRhs, bool initialize)
3871 : {
3872 16995 : bool emittedBindOp = false;
3873 :
3874 16995 : switch (loc.kind()) {
3875 : case NameLocation::Kind::Dynamic:
3876 : case NameLocation::Kind::Import:
3877 : case NameLocation::Kind::DynamicAnnexBVar: {
3878 : uint32_t atomIndex;
3879 35 : if (!makeAtomIndex(name, &atomIndex))
3880 0 : return false;
3881 35 : if (loc.kind() == NameLocation::Kind::DynamicAnnexBVar) {
3882 : // Annex B vars always go on the nearest variable environment,
3883 : // even if lexical environments in between contain same-named
3884 : // bindings.
3885 0 : if (!emit1(JSOP_BINDVAR))
3886 0 : return false;
3887 : } else {
3888 35 : if (!emitIndexOp(JSOP_BINDNAME, atomIndex))
3889 0 : return false;
3890 : }
3891 35 : emittedBindOp = true;
3892 35 : if (!emitRhs(this, loc, emittedBindOp))
3893 0 : return false;
3894 35 : if (!emitIndexOp(strictifySetNameOp(JSOP_SETNAME), atomIndex))
3895 0 : return false;
3896 35 : break;
3897 : }
3898 :
3899 : case NameLocation::Kind::Global: {
3900 : JSOp op;
3901 : uint32_t atomIndex;
3902 1587 : if (!makeAtomIndex(name, &atomIndex))
3903 0 : return false;
3904 1587 : if (loc.isLexical() && initialize) {
3905 : // INITGLEXICAL always gets the global lexical scope. It doesn't
3906 : // need a BINDGNAME.
3907 1170 : MOZ_ASSERT(innermostScope()->is<GlobalScope>());
3908 1170 : op = JSOP_INITGLEXICAL;
3909 : } else {
3910 417 : if (!emitIndexOp(JSOP_BINDGNAME, atomIndex))
3911 0 : return false;
3912 417 : emittedBindOp = true;
3913 417 : op = strictifySetNameOp(JSOP_SETGNAME);
3914 : }
3915 1587 : if (!emitRhs(this, loc, emittedBindOp))
3916 0 : return false;
3917 1588 : if (!emitIndexOp(op, atomIndex))
3918 0 : return false;
3919 1588 : break;
3920 : }
3921 :
3922 : case NameLocation::Kind::Intrinsic:
3923 87 : if (!emitRhs(this, loc, emittedBindOp))
3924 0 : return false;
3925 87 : if (!emitAtomOp(name, JSOP_SETINTRINSIC))
3926 0 : return false;
3927 87 : break;
3928 :
3929 : case NameLocation::Kind::NamedLambdaCallee:
3930 0 : if (!emitRhs(this, loc, emittedBindOp))
3931 0 : return false;
3932 : // Assigning to the named lambda is a no-op in sloppy mode but
3933 : // throws in strict mode.
3934 0 : if (sc->strict() && !emit1(JSOP_THROWSETCALLEE))
3935 0 : return false;
3936 0 : break;
3937 :
3938 : case NameLocation::Kind::ArgumentSlot: {
3939 : // If we assign to a positional formal parameter and the arguments
3940 : // object is unmapped (strict mode or function with
3941 : // default/rest/destructing args), parameters do not alias
3942 : // arguments[i], and to make the arguments object reflect initial
3943 : // parameter values prior to any mutation we create it eagerly
3944 : // whenever parameters are (or might, in the case of calls to eval)
3945 : // assigned.
3946 265 : FunctionBox* funbox = sc->asFunctionBox();
3947 265 : if (funbox->argumentsHasLocalBinding() && !funbox->hasMappedArgsObj())
3948 1 : funbox->setDefinitelyNeedsArgsObj();
3949 :
3950 265 : if (!emitRhs(this, loc, emittedBindOp))
3951 0 : return false;
3952 265 : if (!emitArgOp(JSOP_SETARG, loc.argumentSlot()))
3953 0 : return false;
3954 265 : break;
3955 : }
3956 :
3957 : case NameLocation::Kind::FrameSlot: {
3958 13519 : JSOp op = JSOP_SETLOCAL;
3959 13519 : if (!emitRhs(this, loc, emittedBindOp))
3960 0 : return false;
3961 13519 : if (loc.isLexical()) {
3962 5182 : if (initialize) {
3963 4378 : op = JSOP_INITLEXICAL;
3964 : } else {
3965 804 : if (loc.isConst())
3966 0 : op = JSOP_THROWSETCONST;
3967 :
3968 804 : if (!emitTDZCheckIfNeeded(name, loc))
3969 0 : return false;
3970 : }
3971 : }
3972 13519 : if (!emitLocalOp(op, loc.frameSlot()))
3973 0 : return false;
3974 13519 : if (op == JSOP_INITLEXICAL) {
3975 4378 : if (!innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ))
3976 0 : return false;
3977 : }
3978 13519 : break;
3979 : }
3980 :
3981 : case NameLocation::Kind::EnvironmentCoordinate: {
3982 1502 : JSOp op = JSOP_SETALIASEDVAR;
3983 1502 : if (!emitRhs(this, loc, emittedBindOp))
3984 0 : return false;
3985 1502 : if (loc.isLexical()) {
3986 904 : if (initialize) {
3987 724 : op = JSOP_INITALIASEDLEXICAL;
3988 : } else {
3989 180 : if (loc.isConst())
3990 0 : op = JSOP_THROWSETALIASEDCONST;
3991 :
3992 180 : if (!emitTDZCheckIfNeeded(name, loc))
3993 0 : return false;
3994 : }
3995 : }
3996 1502 : if (loc.bindingKind() == BindingKind::NamedLambdaCallee) {
3997 : // Assigning to the named lambda is a no-op in sloppy mode and throws
3998 : // in strict mode.
3999 0 : op = JSOP_THROWSETALIASEDCONST;
4000 0 : if (sc->strict() && !emitEnvCoordOp(op, loc.environmentCoordinate()))
4001 0 : return false;
4002 : } else {
4003 1502 : if (!emitEnvCoordOp(op, loc.environmentCoordinate()))
4004 0 : return false;
4005 : }
4006 1502 : if (op == JSOP_INITALIASEDLEXICAL) {
4007 724 : if (!innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ))
4008 0 : return false;
4009 : }
4010 1502 : break;
4011 : }
4012 : }
4013 :
4014 16996 : return true;
4015 : }
4016 :
4017 : bool
4018 12738 : BytecodeEmitter::emitTDZCheckIfNeeded(JSAtom* name, const NameLocation& loc)
4019 : {
4020 : // Dynamic accesses have TDZ checks built into their VM code and should
4021 : // never emit explicit TDZ checks.
4022 12738 : MOZ_ASSERT(loc.hasKnownSlot());
4023 12738 : MOZ_ASSERT(loc.isLexical());
4024 :
4025 25476 : Maybe<MaybeCheckTDZ> check = innermostTDZCheckCache->needsTDZCheck(this, name);
4026 12738 : if (!check)
4027 0 : return false;
4028 :
4029 : // We've already emitted a check in this basic block.
4030 12738 : if (*check == DontCheckTDZ)
4031 12186 : return true;
4032 :
4033 552 : if (loc.kind() == NameLocation::Kind::FrameSlot) {
4034 1 : if (!emitLocalOp(JSOP_CHECKLEXICAL, loc.frameSlot()))
4035 0 : return false;
4036 : } else {
4037 551 : if (!emitEnvCoordOp(JSOP_CHECKALIASEDLEXICAL, loc.environmentCoordinate()))
4038 0 : return false;
4039 : }
4040 :
4041 552 : return innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ);
4042 : }
4043 :
4044 : bool
4045 21731 : BytecodeEmitter::emitPropLHS(ParseNode* pn)
4046 : {
4047 21731 : MOZ_ASSERT(pn->isKind(PNK_DOT));
4048 21731 : MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper());
4049 :
4050 21731 : ParseNode* pn2 = pn->pn_expr;
4051 :
4052 : /*
4053 : * If the object operand is also a dotted property reference, reverse the
4054 : * list linked via pn_expr temporarily so we can iterate over it from the
4055 : * bottom up (reversing again as we go), to avoid excessive recursion.
4056 : */
4057 21731 : if (pn2->isKind(PNK_DOT) && !pn2->as<PropertyAccess>().isSuper()) {
4058 3863 : ParseNode* pndot = pn2;
4059 3863 : ParseNode* pnup = nullptr;
4060 : ParseNode* pndown;
4061 : for (;;) {
4062 : /* Reverse pndot->pn_expr to point up, not down. */
4063 4279 : pndown = pndot->pn_expr;
4064 4071 : pndot->pn_expr = pnup;
4065 4071 : if (!pndown->isKind(PNK_DOT) || pndown->as<PropertyAccess>().isSuper())
4066 3863 : break;
4067 208 : pnup = pndot;
4068 208 : pndot = pndown;
4069 : }
4070 :
4071 : /* pndown is a primary expression, not a dotted property reference. */
4072 3863 : if (!emitTree(pndown))
4073 0 : return false;
4074 :
4075 4071 : do {
4076 : /* Walk back up the list, emitting annotated name ops. */
4077 4071 : if (!emitAtomOp(pndot, JSOP_GETPROP))
4078 0 : return false;
4079 :
4080 : /* Reverse the pn_expr link again. */
4081 4071 : pnup = pndot->pn_expr;
4082 4071 : pndot->pn_expr = pndown;
4083 4071 : pndown = pndot;
4084 4071 : } while ((pndot = pnup) != nullptr);
4085 3863 : return true;
4086 : }
4087 :
4088 : // The non-optimized case.
4089 17868 : return emitTree(pn2);
4090 : }
4091 :
4092 : bool
4093 13 : BytecodeEmitter::emitSuperPropLHS(ParseNode* superBase, bool isCall)
4094 : {
4095 13 : if (!emitGetThisForSuperBase(superBase))
4096 0 : return false;
4097 13 : if (isCall && !emit1(JSOP_DUP))
4098 0 : return false;
4099 13 : if (!emit1(JSOP_SUPERBASE))
4100 0 : return false;
4101 13 : return true;
4102 : }
4103 :
4104 : bool
4105 21712 : BytecodeEmitter::emitPropOp(ParseNode* pn, JSOp op)
4106 : {
4107 21712 : MOZ_ASSERT(pn->isArity(PN_NAME));
4108 :
4109 21712 : if (!emitPropLHS(pn))
4110 0 : return false;
4111 :
4112 21713 : if (op == JSOP_CALLPROP && !emit1(JSOP_DUP))
4113 0 : return false;
4114 :
4115 21713 : if (!emitAtomOp(pn, op))
4116 0 : return false;
4117 :
4118 21713 : if (op == JSOP_CALLPROP && !emit1(JSOP_SWAP))
4119 0 : return false;
4120 :
4121 21713 : return true;
4122 : }
4123 :
4124 : bool
4125 13 : BytecodeEmitter::emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall)
4126 : {
4127 13 : ParseNode* base = &pn->as<PropertyAccess>().expression();
4128 13 : if (!emitSuperPropLHS(base, isCall))
4129 0 : return false;
4130 :
4131 13 : if (!emitAtomOp(pn, op))
4132 0 : return false;
4133 :
4134 13 : if (isCall && !emit1(JSOP_SWAP))
4135 0 : return false;
4136 :
4137 13 : return true;
4138 : }
4139 :
4140 : bool
4141 19 : BytecodeEmitter::emitPropIncDec(ParseNode* pn)
4142 : {
4143 19 : MOZ_ASSERT(pn->pn_kid->isKind(PNK_DOT));
4144 :
4145 : bool post;
4146 19 : bool isSuper = pn->pn_kid->as<PropertyAccess>().isSuper();
4147 19 : JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4148 :
4149 19 : if (isSuper) {
4150 0 : ParseNode* base = &pn->pn_kid->as<PropertyAccess>().expression();
4151 0 : if (!emitSuperPropLHS(base)) // THIS OBJ
4152 0 : return false;
4153 0 : if (!emit1(JSOP_DUP2)) // THIS OBJ THIS OBJ
4154 0 : return false;
4155 : } else {
4156 19 : if (!emitPropLHS(pn->pn_kid)) // OBJ
4157 0 : return false;
4158 19 : if (!emit1(JSOP_DUP)) // OBJ OBJ
4159 0 : return false;
4160 : }
4161 19 : if (!emitAtomOp(pn->pn_kid, isSuper? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
4162 0 : return false;
4163 19 : if (!emit1(JSOP_POS)) // OBJ N
4164 0 : return false;
4165 19 : if (post && !emit1(JSOP_DUP)) // OBJ N? N
4166 0 : return false;
4167 19 : if (!emit1(JSOP_ONE)) // OBJ N? N 1
4168 0 : return false;
4169 19 : if (!emit1(binop)) // OBJ N? N+1
4170 0 : return false;
4171 :
4172 19 : if (post) {
4173 14 : if (!emit2(JSOP_PICK, 2 + isSuper)) // N? N+1 OBJ
4174 0 : return false;
4175 14 : if (!emit1(JSOP_SWAP)) // N? OBJ N+1
4176 0 : return false;
4177 14 : if (isSuper) {
4178 0 : if (!emit2(JSOP_PICK, 3)) // N THIS N+1 OBJ
4179 0 : return false;
4180 0 : if (!emit1(JSOP_SWAP)) // N THIS OBJ N+1
4181 0 : return false;
4182 : }
4183 : }
4184 :
4185 38 : JSOp setOp = isSuper ? sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
4186 38 : : sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
4187 19 : if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1
4188 0 : return false;
4189 19 : if (post && !emit1(JSOP_POP)) // RESULT
4190 0 : return false;
4191 :
4192 19 : return true;
4193 : }
4194 :
4195 : bool
4196 1045 : BytecodeEmitter::emitGetNameAtLocationForCompoundAssignment(JSAtom* name, const NameLocation& loc)
4197 : {
4198 1045 : if (loc.kind() == NameLocation::Kind::Dynamic) {
4199 : // For dynamic accesses we need to emit GETBOUNDNAME instead of
4200 : // GETNAME for correctness: looking up @@unscopables on the
4201 : // environment chain (due to 'with' environments) must only happen
4202 : // once.
4203 : //
4204 : // GETBOUNDNAME uses the environment already pushed on the stack from
4205 : // the earlier BINDNAME.
4206 0 : if (!emit1(JSOP_DUP)) // ENV ENV
4207 0 : return false;
4208 0 : if (!emitAtomOp(name, JSOP_GETBOUNDNAME)) // ENV V
4209 0 : return false;
4210 : } else {
4211 1045 : if (!emitGetNameAtLocation(name, loc)) // ENV? V
4212 0 : return false;
4213 : }
4214 :
4215 1045 : return true;
4216 : }
4217 :
4218 : bool
4219 674 : BytecodeEmitter::emitNameIncDec(ParseNode* pn)
4220 : {
4221 674 : MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
4222 :
4223 : bool post;
4224 674 : JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4225 :
4226 : auto emitRhs = [pn, post, binop](BytecodeEmitter* bce, const NameLocation& loc,
4227 674 : bool emittedBindOp)
4228 2696 : {
4229 674 : JSAtom* name = pn->pn_kid->name();
4230 674 : if (!bce->emitGetNameAtLocationForCompoundAssignment(name, loc)) // ENV? V
4231 0 : return false;
4232 674 : if (!bce->emit1(JSOP_POS)) // ENV? N
4233 0 : return false;
4234 674 : if (post && !bce->emit1(JSOP_DUP)) // ENV? N? N
4235 0 : return false;
4236 674 : if (!bce->emit1(JSOP_ONE)) // ENV? N? N 1
4237 0 : return false;
4238 674 : if (!bce->emit1(binop)) // ENV? N? N+1
4239 0 : return false;
4240 :
4241 674 : if (post && emittedBindOp) {
4242 6 : if (!bce->emit2(JSOP_PICK, 2)) // N? N+1 ENV?
4243 0 : return false;
4244 6 : if (!bce->emit1(JSOP_SWAP)) // N? ENV? N+1
4245 0 : return false;
4246 : }
4247 :
4248 674 : return true;
4249 674 : };
4250 :
4251 674 : if (!emitSetName(pn->pn_kid, emitRhs))
4252 0 : return false;
4253 :
4254 674 : if (post && !emit1(JSOP_POP))
4255 0 : return false;
4256 :
4257 674 : return true;
4258 : }
4259 :
4260 : bool
4261 2821 : BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts)
4262 : {
4263 2821 : MOZ_ASSERT(pn->isArity(PN_BINARY));
4264 :
4265 2821 : if (!emitTree(pn->pn_left))
4266 0 : return false;
4267 :
4268 2821 : if (opts == EmitElemOption::IncDec) {
4269 12 : if (!emit1(JSOP_CHECKOBJCOERCIBLE))
4270 0 : return false;
4271 2809 : } else if (opts == EmitElemOption::Call) {
4272 8 : if (!emit1(JSOP_DUP))
4273 0 : return false;
4274 : }
4275 :
4276 2821 : if (!emitTree(pn->pn_right))
4277 0 : return false;
4278 :
4279 2821 : if (opts == EmitElemOption::Set) {
4280 0 : if (!emit2(JSOP_PICK, 2))
4281 0 : return false;
4282 2821 : } else if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
4283 40 : if (!emit1(JSOP_TOID))
4284 0 : return false;
4285 : }
4286 2821 : return true;
4287 : }
4288 :
4289 : bool
4290 0 : BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
4291 : {
4292 0 : MOZ_ASSERT(pn->isKind(PNK_ELEM) && pn->as<PropertyByValue>().isSuper());
4293 :
4294 : // The ordering here is somewhat screwy. We need to evaluate the propval
4295 : // first, by spec. Do a little dance to not emit more than one JSOP_THIS.
4296 : // Since JSOP_THIS might throw in derived class constructors, we cannot
4297 : // just push it earlier as the receiver. We have to swap it down instead.
4298 :
4299 0 : if (!emitTree(pn->pn_right))
4300 0 : return false;
4301 :
4302 : // We need to convert the key to an object id first, so that we do not do
4303 : // it inside both the GETELEM and the SETELEM.
4304 0 : if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
4305 0 : if (!emit1(JSOP_TOID))
4306 0 : return false;
4307 : }
4308 :
4309 0 : if (!emitGetThisForSuperBase(pn->pn_left))
4310 0 : return false;
4311 :
4312 0 : if (opts == EmitElemOption::Call) {
4313 0 : if (!emit1(JSOP_SWAP))
4314 0 : return false;
4315 :
4316 : // We need another |this| on top, also
4317 0 : if (!emitDupAt(1))
4318 0 : return false;
4319 : }
4320 :
4321 0 : if (!emit1(JSOP_SUPERBASE))
4322 0 : return false;
4323 :
4324 0 : if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3))
4325 0 : return false;
4326 :
4327 0 : return true;
4328 : }
4329 :
4330 : bool
4331 2993 : BytecodeEmitter::emitElemOpBase(JSOp op)
4332 : {
4333 2993 : if (!emit1(op))
4334 0 : return false;
4335 :
4336 2993 : checkTypeSet(op);
4337 2993 : return true;
4338 : }
4339 :
4340 : bool
4341 2469 : BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op)
4342 : {
4343 2469 : EmitElemOption opts = EmitElemOption::Get;
4344 2469 : if (op == JSOP_CALLELEM)
4345 8 : opts = EmitElemOption::Call;
4346 2461 : else if (op == JSOP_SETELEM || op == JSOP_STRICTSETELEM)
4347 0 : opts = EmitElemOption::Set;
4348 :
4349 2469 : return emitElemOperands(pn, opts) && emitElemOpBase(op);
4350 : }
4351 :
4352 : bool
4353 0 : BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall)
4354 : {
4355 0 : EmitElemOption opts = EmitElemOption::Get;
4356 0 : if (isCall)
4357 0 : opts = EmitElemOption::Call;
4358 0 : else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER)
4359 0 : opts = EmitElemOption::Set;
4360 :
4361 0 : if (!emitSuperElemOperands(pn, opts))
4362 0 : return false;
4363 0 : if (!emitElemOpBase(op))
4364 0 : return false;
4365 :
4366 0 : if (isCall && !emit1(JSOP_SWAP))
4367 0 : return false;
4368 :
4369 0 : return true;
4370 : }
4371 :
4372 : bool
4373 12 : BytecodeEmitter::emitElemIncDec(ParseNode* pn)
4374 : {
4375 12 : MOZ_ASSERT(pn->pn_kid->isKind(PNK_ELEM));
4376 :
4377 12 : bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
4378 :
4379 : // We need to convert the key to an object id first, so that we do not do
4380 : // it inside both the GETELEM and the SETELEM. This is done by
4381 : // emit(Super)ElemOperands.
4382 12 : if (isSuper) {
4383 0 : if (!emitSuperElemOperands(pn->pn_kid, EmitElemOption::IncDec))
4384 0 : return false;
4385 : } else {
4386 12 : if (!emitElemOperands(pn->pn_kid, EmitElemOption::IncDec))
4387 0 : return false;
4388 : }
4389 :
4390 : bool post;
4391 12 : JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4392 :
4393 : JSOp getOp;
4394 12 : if (isSuper) {
4395 : // There's no such thing as JSOP_DUP3, so we have to be creative.
4396 : // Note that pushing things again is no fewer JSOps.
4397 0 : if (!emitDupAt(2)) // KEY THIS OBJ KEY
4398 0 : return false;
4399 0 : if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS
4400 0 : return false;
4401 0 : if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS OBJ
4402 0 : return false;
4403 0 : getOp = JSOP_GETELEM_SUPER;
4404 : } else {
4405 : // OBJ KEY
4406 12 : if (!emit1(JSOP_DUP2)) // OBJ KEY OBJ KEY
4407 0 : return false;
4408 12 : getOp = JSOP_GETELEM;
4409 : }
4410 12 : if (!emitElemOpBase(getOp)) // OBJ KEY V
4411 0 : return false;
4412 12 : if (!emit1(JSOP_POS)) // OBJ KEY N
4413 0 : return false;
4414 12 : if (post && !emit1(JSOP_DUP)) // OBJ KEY N? N
4415 0 : return false;
4416 12 : if (!emit1(JSOP_ONE)) // OBJ KEY N? N 1
4417 0 : return false;
4418 12 : if (!emit1(binop)) // OBJ KEY N? N+1
4419 0 : return false;
4420 :
4421 12 : if (post) {
4422 12 : if (isSuper) {
4423 : // We have one more value to rotate around, because of |this|
4424 : // on the stack
4425 0 : if (!emit2(JSOP_PICK, 4))
4426 0 : return false;
4427 : }
4428 12 : if (!emit2(JSOP_PICK, 3 + isSuper)) // KEY N N+1 OBJ
4429 0 : return false;
4430 12 : if (!emit2(JSOP_PICK, 3 + isSuper)) // N N+1 OBJ KEY
4431 0 : return false;
4432 12 : if (!emit2(JSOP_PICK, 2 + isSuper)) // N OBJ KEY N+1
4433 0 : return false;
4434 : }
4435 :
4436 24 : JSOp setOp = isSuper ? (sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
4437 24 : : (sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM);
4438 12 : if (!emitElemOpBase(setOp)) // N? N+1
4439 0 : return false;
4440 12 : if (post && !emit1(JSOP_POP)) // RESULT
4441 0 : return false;
4442 :
4443 12 : return true;
4444 : }
4445 :
4446 : bool
4447 0 : BytecodeEmitter::emitCallIncDec(ParseNode* incDec)
4448 : {
4449 0 : MOZ_ASSERT(incDec->isKind(PNK_PREINCREMENT) ||
4450 : incDec->isKind(PNK_POSTINCREMENT) ||
4451 : incDec->isKind(PNK_PREDECREMENT) ||
4452 : incDec->isKind(PNK_POSTDECREMENT));
4453 :
4454 0 : MOZ_ASSERT(incDec->pn_kid->isKind(PNK_CALL));
4455 :
4456 0 : ParseNode* call = incDec->pn_kid;
4457 0 : if (!emitTree(call)) // CALLRESULT
4458 0 : return false;
4459 0 : if (!emit1(JSOP_POS)) // N
4460 0 : return false;
4461 :
4462 : // The increment/decrement has no side effects, so proceed to throw for
4463 : // invalid assignment target.
4464 0 : return emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS);
4465 : }
4466 :
4467 : bool
4468 8079 : BytecodeEmitter::emitNumberOp(double dval)
4469 : {
4470 : int32_t ival;
4471 8079 : if (NumberIsInt32(dval, &ival)) {
4472 8028 : if (ival == 0)
4473 2882 : return emit1(JSOP_ZERO);
4474 5146 : if (ival == 1)
4475 1375 : return emit1(JSOP_ONE);
4476 3771 : if ((int)(int8_t)ival == ival)
4477 3187 : return emit2(JSOP_INT8, uint8_t(int8_t(ival)));
4478 :
4479 584 : uint32_t u = uint32_t(ival);
4480 584 : if (u < JS_BIT(16)) {
4481 502 : if (!emitUint16Operand(JSOP_UINT16, u))
4482 0 : return false;
4483 82 : } else if (u < JS_BIT(24)) {
4484 : ptrdiff_t off;
4485 38 : if (!emitN(JSOP_UINT24, 3, &off))
4486 0 : return false;
4487 38 : SET_UINT24(code(off), u);
4488 : } else {
4489 : ptrdiff_t off;
4490 44 : if (!emitN(JSOP_INT32, 4, &off))
4491 0 : return false;
4492 44 : SET_INT32(code(off), ival);
4493 : }
4494 584 : return true;
4495 : }
4496 :
4497 51 : if (!constList.append(DoubleValue(dval)))
4498 0 : return false;
4499 :
4500 51 : return emitIndex32(JSOP_DOUBLE, constList.length() - 1);
4501 : }
4502 :
4503 : /*
4504 : * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
4505 : * LLVM is deciding to inline this function which uses a lot of stack space
4506 : * into emitTree which is recursive and uses relatively little stack space.
4507 : */
4508 : MOZ_NEVER_INLINE bool
4509 210 : BytecodeEmitter::emitSwitch(ParseNode* pn)
4510 : {
4511 210 : ParseNode* cases = pn->pn_right;
4512 210 : MOZ_ASSERT(cases->isKind(PNK_LEXICALSCOPE) || cases->isKind(PNK_STATEMENTLIST));
4513 :
4514 : // Emit code for the discriminant.
4515 210 : if (!emitTree(pn->pn_left))
4516 0 : return false;
4517 :
4518 : // Enter the scope before pushing the switch BreakableControl since all
4519 : // breaks are under this scope.
4520 420 : Maybe<TDZCheckCache> tdzCache;
4521 420 : Maybe<EmitterScope> emitterScope;
4522 210 : if (cases->isKind(PNK_LEXICALSCOPE)) {
4523 210 : if (!cases->isEmptyScope()) {
4524 10 : tdzCache.emplace(this);
4525 10 : emitterScope.emplace(this);
4526 10 : if (!emitterScope->enterLexical(this, ScopeKind::Lexical, cases->scopeBindings()))
4527 0 : return false;
4528 : }
4529 :
4530 : // Advance |cases| to refer to the switch case list.
4531 210 : cases = cases->scopeBody();
4532 :
4533 : // A switch statement may contain hoisted functions inside its
4534 : // cases. The PNX_FUNCDEFS flag is propagated from the STATEMENTLIST
4535 : // bodies of the cases to the case list.
4536 210 : if (cases->pn_xflags & PNX_FUNCDEFS) {
4537 0 : MOZ_ASSERT(emitterScope);
4538 0 : for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) {
4539 0 : if (caseNode->pn_right->pn_xflags & PNX_FUNCDEFS) {
4540 0 : if (!emitHoistedFunctionsInList(caseNode->pn_right))
4541 0 : return false;
4542 : }
4543 : }
4544 : }
4545 : }
4546 :
4547 : // After entering the scope, push the switch control.
4548 420 : BreakableControl controlInfo(this, StatementKind::Switch);
4549 :
4550 210 : ptrdiff_t top = offset();
4551 :
4552 : // Switch bytecodes run from here till end of final case.
4553 210 : uint32_t caseCount = cases->pn_count;
4554 210 : if (caseCount > JS_BIT(16)) {
4555 0 : parser.reportError(JSMSG_TOO_MANY_CASES);
4556 0 : return false;
4557 : }
4558 :
4559 : // Try for most optimal, fall back if not dense ints.
4560 210 : JSOp switchOp = JSOP_TABLESWITCH;
4561 210 : uint32_t tableLength = 0;
4562 : int32_t low, high;
4563 210 : bool hasDefault = false;
4564 210 : CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as<CaseClause>() : nullptr;
4565 210 : if (caseCount == 0 ||
4566 11 : (caseCount == 1 && (hasDefault = firstCase->isDefault())))
4567 : {
4568 0 : caseCount = 0;
4569 0 : low = 0;
4570 0 : high = -1;
4571 : } else {
4572 420 : Vector<jsbitmap, 128, SystemAllocPolicy> intmap;
4573 210 : int32_t intmapBitLength = 0;
4574 :
4575 210 : low = JSVAL_INT_MAX;
4576 210 : high = JSVAL_INT_MIN;
4577 :
4578 1324 : for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4579 1114 : if (caseNode->isDefault()) {
4580 55 : hasDefault = true;
4581 55 : caseCount--; // one of the "cases" was the default
4582 615 : continue;
4583 : }
4584 :
4585 1059 : if (switchOp == JSOP_CONDSWITCH)
4586 374 : continue;
4587 :
4588 685 : MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4589 :
4590 685 : ParseNode* caseValue = caseNode->caseExpression();
4591 :
4592 685 : if (caseValue->getKind() != PNK_NUMBER) {
4593 131 : switchOp = JSOP_CONDSWITCH;
4594 131 : continue;
4595 : }
4596 :
4597 : int32_t i;
4598 554 : if (!NumberIsInt32(caseValue->pn_dval, &i)) {
4599 0 : switchOp = JSOP_CONDSWITCH;
4600 0 : continue;
4601 : }
4602 :
4603 554 : if (unsigned(i + int(JS_BIT(15))) >= unsigned(JS_BIT(16))) {
4604 0 : switchOp = JSOP_CONDSWITCH;
4605 0 : continue;
4606 : }
4607 554 : if (i < low)
4608 89 : low = i;
4609 554 : if (i > high)
4610 454 : high = i;
4611 :
4612 : // Check for duplicates, which require a JSOP_CONDSWITCH.
4613 : // We bias i by 65536 if it's negative, and hope that's a rare
4614 : // case (because it requires a malloc'd bitmap).
4615 554 : if (i < 0)
4616 0 : i += JS_BIT(16);
4617 554 : if (i >= intmapBitLength) {
4618 79 : size_t newLength = (i / JS_BITMAP_NBITS) + 1;
4619 79 : if (!intmap.resize(newLength))
4620 0 : return false;
4621 79 : intmapBitLength = newLength * JS_BITMAP_NBITS;
4622 : }
4623 554 : if (JS_TEST_BIT(intmap, i)) {
4624 0 : switchOp = JSOP_CONDSWITCH;
4625 0 : continue;
4626 : }
4627 554 : JS_SET_BIT(intmap, i);
4628 : }
4629 :
4630 : // Compute table length and select condswitch instead if overlarge or
4631 : // more than half-sparse.
4632 210 : if (switchOp == JSOP_TABLESWITCH) {
4633 79 : tableLength = uint32_t(high - low + 1);
4634 79 : if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount)
4635 1 : switchOp = JSOP_CONDSWITCH;
4636 : }
4637 : }
4638 :
4639 : // The note has one or two offsets: first tells total switch code length;
4640 : // second (if condswitch) tells offset to first JSOP_CASE.
4641 : unsigned noteIndex;
4642 : size_t switchSize;
4643 210 : if (switchOp == JSOP_CONDSWITCH) {
4644 : // 0 bytes of immediate for unoptimized switch.
4645 132 : switchSize = 0;
4646 132 : if (!newSrcNote3(SRC_CONDSWITCH, 0, 0, ¬eIndex))
4647 0 : return false;
4648 : } else {
4649 78 : MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4650 :
4651 : // 3 offsets (len, low, high) before the table, 1 per entry.
4652 78 : switchSize = size_t(JUMP_OFFSET_LEN * (3 + tableLength));
4653 78 : if (!newSrcNote2(SRC_TABLESWITCH, 0, ¬eIndex))
4654 0 : return false;
4655 : }
4656 :
4657 : // Emit switchOp followed by switchSize bytes of jump or lookup table.
4658 210 : MOZ_ASSERT(top == offset());
4659 210 : if (!emitN(switchOp, switchSize))
4660 0 : return false;
4661 :
4662 420 : Vector<CaseClause*, 32, SystemAllocPolicy> table;
4663 :
4664 210 : JumpList condSwitchDefaultOff;
4665 210 : if (switchOp == JSOP_CONDSWITCH) {
4666 : unsigned caseNoteIndex;
4667 132 : bool beforeCases = true;
4668 132 : ptrdiff_t lastCaseOffset = -1;
4669 :
4670 : // The case conditions need their own TDZ cache since they might not
4671 : // all execute.
4672 264 : TDZCheckCache tdzCache(this);
4673 :
4674 : // Emit code for evaluating cases and jumping to case statements.
4675 663 : for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4676 531 : ParseNode* caseValue = caseNode->caseExpression();
4677 :
4678 : // If the expression is a literal, suppress line number emission so
4679 : // that debugging works more naturally.
4680 531 : if (caseValue) {
4681 508 : if (!emitTree(caseValue, ValueUsage::WantValue,
4682 508 : caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
4683 : {
4684 0 : return false;
4685 : }
4686 : }
4687 :
4688 531 : if (!beforeCases) {
4689 : // prevCase is the previous JSOP_CASE's bytecode offset.
4690 399 : if (!setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
4691 0 : return false;
4692 : }
4693 531 : if (!caseValue) {
4694 : // This is the default clause.
4695 23 : continue;
4696 : }
4697 :
4698 508 : if (!newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex))
4699 0 : return false;
4700 :
4701 : // The case clauses are produced before any of the case body. The
4702 : // JumpList is saved on the parsed tree, then later restored and
4703 : // patched when generating the cases body.
4704 508 : JumpList caseJump;
4705 508 : if (!emitJump(JSOP_CASE, &caseJump))
4706 0 : return false;
4707 508 : caseNode->setOffset(caseJump.offset);
4708 508 : lastCaseOffset = caseJump.offset;
4709 :
4710 508 : if (beforeCases) {
4711 : // Switch note's second offset is to first JSOP_CASE.
4712 132 : unsigned noteCount = notes().length();
4713 132 : if (!setSrcNoteOffset(noteIndex, 1, lastCaseOffset - top))
4714 0 : return false;
4715 132 : unsigned noteCountDelta = notes().length() - noteCount;
4716 132 : if (noteCountDelta != 0)
4717 0 : caseNoteIndex += noteCountDelta;
4718 132 : beforeCases = false;
4719 : }
4720 : }
4721 :
4722 : // If we didn't have an explicit default (which could fall in between
4723 : // cases, preventing us from fusing this setSrcNoteOffset with the call
4724 : // in the loop above), link the last case to the implicit default for
4725 : // the benefit of IonBuilder.
4726 373 : if (!hasDefault &&
4727 241 : !beforeCases &&
4728 109 : !setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
4729 : {
4730 0 : return false;
4731 : }
4732 :
4733 : // Emit default even if no explicit default statement.
4734 132 : if (!emitJump(JSOP_DEFAULT, &condSwitchDefaultOff))
4735 0 : return false;
4736 : } else {
4737 78 : MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4738 :
4739 : // skip default offset.
4740 78 : jsbytecode* pc = code(top + JUMP_OFFSET_LEN);
4741 :
4742 : // Fill in switch bounds, which we know fit in 16-bit offsets.
4743 78 : SET_JUMP_OFFSET(pc, low);
4744 78 : pc += JUMP_OFFSET_LEN;
4745 78 : SET_JUMP_OFFSET(pc, high);
4746 78 : pc += JUMP_OFFSET_LEN;
4747 :
4748 78 : if (tableLength != 0) {
4749 78 : if (!table.growBy(tableLength))
4750 0 : return false;
4751 :
4752 661 : for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4753 583 : if (ParseNode* caseValue = caseNode->caseExpression()) {
4754 551 : MOZ_ASSERT(caseValue->isKind(PNK_NUMBER));
4755 :
4756 551 : int32_t i = int32_t(caseValue->pn_dval);
4757 551 : MOZ_ASSERT(double(i) == caseValue->pn_dval);
4758 :
4759 551 : i -= low;
4760 551 : MOZ_ASSERT(uint32_t(i) < tableLength);
4761 551 : MOZ_ASSERT(!table[i]);
4762 551 : table[i] = caseNode;
4763 : }
4764 : }
4765 : }
4766 : }
4767 :
4768 210 : JumpTarget defaultOffset{ -1 };
4769 :
4770 : // Emit code for each case's statements.
4771 1324 : for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4772 1114 : if (switchOp == JSOP_CONDSWITCH && !caseNode->isDefault()) {
4773 : // The case offset got saved in the caseNode structure after
4774 : // emitting the JSOP_CASE jump instruction above.
4775 508 : JumpList caseCond;
4776 508 : caseCond.offset = caseNode->offset();
4777 508 : if (!emitJumpTargetAndPatch(caseCond))
4778 0 : return false;
4779 : }
4780 :
4781 : JumpTarget here;
4782 1114 : if (!emitJumpTarget(&here))
4783 0 : return false;
4784 1114 : if (caseNode->isDefault())
4785 55 : defaultOffset = here;
4786 :
4787 : // If this is emitted as a TABLESWITCH, we'll need to know this case's
4788 : // offset later when emitting the table. Store it in the node's
4789 : // pn_offset (giving the field a different meaning vs. how we used it
4790 : // on the immediately preceding line of code).
4791 1114 : caseNode->setOffset(here.offset);
4792 :
4793 2228 : TDZCheckCache tdzCache(this);
4794 :
4795 1114 : if (!emitTree(caseNode->statementList()))
4796 0 : return false;
4797 : }
4798 :
4799 210 : if (!hasDefault) {
4800 : // If no default case, offset for default is to end of switch.
4801 155 : if (!emitJumpTarget(&defaultOffset))
4802 0 : return false;
4803 : }
4804 210 : MOZ_ASSERT(defaultOffset.offset != -1);
4805 :
4806 : // Set the default offset (to end of switch if no default).
4807 : jsbytecode* pc;
4808 210 : if (switchOp == JSOP_CONDSWITCH) {
4809 132 : pc = nullptr;
4810 132 : patchJumpsToTarget(condSwitchDefaultOff, defaultOffset);
4811 : } else {
4812 78 : MOZ_ASSERT(switchOp == JSOP_TABLESWITCH);
4813 78 : pc = code(top);
4814 78 : SET_JUMP_OFFSET(pc, defaultOffset.offset - top);
4815 78 : pc += JUMP_OFFSET_LEN;
4816 : }
4817 :
4818 : // Set the SRC_SWITCH note's offset operand to tell end of switch.
4819 210 : if (!setSrcNoteOffset(noteIndex, 0, lastNonJumpTargetOffset() - top))
4820 0 : return false;
4821 :
4822 210 : if (switchOp == JSOP_TABLESWITCH) {
4823 : // Skip over the already-initialized switch bounds.
4824 78 : pc += 2 * JUMP_OFFSET_LEN;
4825 :
4826 : // Fill in the jump table, if there is one.
4827 654 : for (uint32_t i = 0; i < tableLength; i++) {
4828 576 : CaseClause* caseNode = table[i];
4829 576 : ptrdiff_t off = caseNode ? caseNode->offset() - top : 0;
4830 576 : SET_JUMP_OFFSET(pc, off);
4831 576 : pc += JUMP_OFFSET_LEN;
4832 : }
4833 : }
4834 :
4835 : // Patch breaks before leaving the scope, as all breaks are under the
4836 : // lexical scope if it exists.
4837 210 : if (!controlInfo.patchBreaks(this))
4838 0 : return false;
4839 :
4840 210 : if (emitterScope && !emitterScope->leave(this))
4841 0 : return false;
4842 :
4843 210 : return true;
4844 : }
4845 :
4846 : bool
4847 9824 : BytecodeEmitter::isRunOnceLambda()
4848 : {
4849 : // The run once lambda flags set by the parser are approximate, and we look
4850 : // at properties of the function itself before deciding to emit a function
4851 : // as a run once lambda.
4852 :
4853 29296 : if (!(parent && parent->emittingRunOnceLambda) &&
4854 11401 : (emitterMode != LazyFunction || !lazyScript->treatAsRunOnce()))
4855 : {
4856 9736 : return false;
4857 : }
4858 :
4859 88 : FunctionBox* funbox = sc->asFunctionBox();
4860 176 : return !funbox->argumentsHasLocalBinding() &&
4861 176 : !funbox->isStarGenerator() &&
4862 176 : !funbox->isLegacyGenerator() &&
4863 264 : !funbox->isAsync() &&
4864 176 : !funbox->function()->explicitName();
4865 : }
4866 :
4867 : bool
4868 591 : BytecodeEmitter::emitYieldOp(JSOp op)
4869 : {
4870 591 : if (op == JSOP_FINALYIELDRVAL)
4871 211 : return emit1(JSOP_FINALYIELDRVAL);
4872 :
4873 380 : MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT);
4874 :
4875 : ptrdiff_t off;
4876 380 : if (!emitN(op, 3, &off))
4877 0 : return false;
4878 :
4879 380 : uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
4880 380 : if (yieldAndAwaitIndex >= JS_BIT(24)) {
4881 0 : reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
4882 0 : return false;
4883 : }
4884 :
4885 380 : if (op == JSOP_AWAIT)
4886 235 : yieldAndAwaitOffsetList.numAwaits++;
4887 : else
4888 145 : yieldAndAwaitOffsetList.numYields++;
4889 :
4890 380 : SET_UINT24(code(off), yieldAndAwaitIndex);
4891 :
4892 380 : if (!yieldAndAwaitOffsetList.append(offset()))
4893 0 : return false;
4894 :
4895 380 : return emit1(JSOP_DEBUGAFTERYIELD);
4896 : }
4897 :
4898 : bool
4899 13 : BytecodeEmitter::emitSetThis(ParseNode* pn)
4900 : {
4901 : // PNK_SETTHIS is used to update |this| after a super() call in a derived
4902 : // class constructor.
4903 :
4904 13 : MOZ_ASSERT(pn->isKind(PNK_SETTHIS));
4905 13 : MOZ_ASSERT(pn->pn_left->isKind(PNK_NAME));
4906 :
4907 26 : RootedAtom name(cx, pn->pn_left->name());
4908 26 : auto emitRhs = [&name, pn](BytecodeEmitter* bce, const NameLocation&, bool) {
4909 : // Emit the new |this| value.
4910 13 : if (!bce->emitTree(pn->pn_right))
4911 0 : return false;
4912 : // Get the original |this| and throw if we already initialized
4913 : // it. Do *not* use the NameLocation argument, as that's the special
4914 : // lexical location below to deal with super() semantics.
4915 13 : if (!bce->emitGetName(name))
4916 0 : return false;
4917 13 : if (!bce->emit1(JSOP_CHECKTHISREINIT))
4918 0 : return false;
4919 13 : if (!bce->emit1(JSOP_POP))
4920 0 : return false;
4921 13 : return true;
4922 13 : };
4923 :
4924 : // The 'this' binding is not lexical, but due to super() semantics this
4925 : // initialization needs to be treated as a lexical one.
4926 13 : NameLocation loc = lookupName(name);
4927 13 : NameLocation lexicalLoc;
4928 13 : if (loc.kind() == NameLocation::Kind::FrameSlot) {
4929 13 : lexicalLoc = NameLocation::FrameSlot(BindingKind::Let, loc.frameSlot());
4930 0 : } else if (loc.kind() == NameLocation::Kind::EnvironmentCoordinate) {
4931 0 : EnvironmentCoordinate coord = loc.environmentCoordinate();
4932 0 : uint8_t hops = AssertedCast<uint8_t>(coord.hops());
4933 0 : lexicalLoc = NameLocation::EnvironmentCoordinate(BindingKind::Let, hops, coord.slot());
4934 : } else {
4935 0 : MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic);
4936 0 : lexicalLoc = loc;
4937 : }
4938 :
4939 26 : return emitSetOrInitializeNameAtLocation(name, lexicalLoc, emitRhs, true);
4940 : }
4941 :
4942 : bool
4943 268 : BytecodeEmitter::emitScript(ParseNode* body)
4944 : {
4945 537 : AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, tokenStream(), body);
4946 :
4947 537 : TDZCheckCache tdzCache(this);
4948 537 : EmitterScope emitterScope(this);
4949 268 : if (sc->isGlobalContext()) {
4950 266 : switchToPrologue();
4951 266 : if (!emitterScope.enterGlobal(this, sc->asGlobalContext()))
4952 0 : return false;
4953 266 : switchToMain();
4954 2 : } else if (sc->isEvalContext()) {
4955 2 : switchToPrologue();
4956 2 : if (!emitterScope.enterEval(this, sc->asEvalContext()))
4957 0 : return false;
4958 2 : switchToMain();
4959 : } else {
4960 0 : MOZ_ASSERT(sc->isModuleContext());
4961 0 : if (!emitterScope.enterModule(this, sc->asModuleContext()))
4962 0 : return false;
4963 : }
4964 :
4965 268 : setFunctionBodyEndPos(body->pn_pos);
4966 :
4967 538 : if (sc->isEvalContext() && !sc->strict() &&
4968 268 : body->isKind(PNK_LEXICALSCOPE) && !body->isEmptyScope())
4969 : {
4970 : // Sloppy eval scripts may need to emit DEFFUNs in the prologue. If there is
4971 : // an immediately enclosed lexical scope, we need to enter the lexical
4972 : // scope in the prologue for the DEFFUNs to pick up the right
4973 : // environment chain.
4974 0 : EmitterScope lexicalEmitterScope(this);
4975 :
4976 0 : switchToPrologue();
4977 0 : if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical, body->scopeBindings()))
4978 0 : return false;
4979 0 : switchToMain();
4980 :
4981 0 : if (!emitLexicalScopeBody(body->scopeBody()))
4982 0 : return false;
4983 :
4984 0 : if (!lexicalEmitterScope.leave(this))
4985 0 : return false;
4986 : } else {
4987 268 : if (!emitTree(body))
4988 0 : return false;
4989 : }
4990 :
4991 269 : if (!emit1(JSOP_RETRVAL))
4992 0 : return false;
4993 :
4994 269 : if (!emitterScope.leave(this))
4995 0 : return false;
4996 :
4997 269 : if (!JSScript::fullyInitFromEmitter(cx, script, this))
4998 0 : return false;
4999 :
5000 : // URL and source map information must be set before firing
5001 : // Debugger::onNewScript.
5002 269 : if (!maybeSetDisplayURL() || !maybeSetSourceMap())
5003 0 : return false;
5004 :
5005 269 : tellDebuggerAboutCompiledScript(cx);
5006 :
5007 269 : return true;
5008 : }
5009 :
5010 : bool
5011 5404 : BytecodeEmitter::emitFunctionScript(ParseNode* body)
5012 : {
5013 5404 : FunctionBox* funbox = sc->asFunctionBox();
5014 10809 : AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, tokenStream(), funbox);
5015 :
5016 : // The ordering of these EmitterScopes is important. The named lambda
5017 : // scope needs to enclose the function scope needs to enclose the extra
5018 : // var scope.
5019 :
5020 10809 : Maybe<EmitterScope> namedLambdaEmitterScope;
5021 5404 : if (funbox->namedLambdaBindings()) {
5022 391 : namedLambdaEmitterScope.emplace(this);
5023 391 : if (!namedLambdaEmitterScope->enterNamedLambda(this, funbox))
5024 0 : return false;
5025 : }
5026 :
5027 : /*
5028 : * Emit a prologue for run-once scripts which will deoptimize JIT code
5029 : * if the script ends up running multiple times via foo.caller related
5030 : * shenanigans.
5031 : *
5032 : * Also mark the script so that initializers created within it may be
5033 : * given more precise types.
5034 : */
5035 5404 : if (isRunOnceLambda()) {
5036 10 : script->setTreatAsRunOnce();
5037 10 : MOZ_ASSERT(!script->hasRunOnce());
5038 :
5039 10 : switchToPrologue();
5040 10 : if (!emit1(JSOP_RUNONCE))
5041 0 : return false;
5042 10 : switchToMain();
5043 : }
5044 :
5045 5404 : setFunctionBodyEndPos(body->pn_pos);
5046 5404 : if (!emitTree(body))
5047 0 : return false;
5048 :
5049 5405 : if (!updateSourceCoordNotes(body->pn_pos.end))
5050 0 : return false;
5051 :
5052 : // Always end the script with a JSOP_RETRVAL. Some other parts of the
5053 : // codebase depend on this opcode,
5054 : // e.g. InterpreterRegs::setToEndOfScript.
5055 5405 : if (!emit1(JSOP_RETRVAL))
5056 0 : return false;
5057 :
5058 5405 : if (namedLambdaEmitterScope) {
5059 391 : if (!namedLambdaEmitterScope->leave(this))
5060 0 : return false;
5061 391 : namedLambdaEmitterScope.reset();
5062 : }
5063 :
5064 5405 : if (!JSScript::fullyInitFromEmitter(cx, script, this))
5065 0 : return false;
5066 :
5067 : // URL and source map information must be set before firing
5068 : // Debugger::onNewScript. Only top-level functions need this, as compiling
5069 : // the outer scripts of nested functions already processed the source.
5070 5405 : if (emitterMode != LazyFunction && !parent) {
5071 15 : if (!maybeSetDisplayURL() || !maybeSetSourceMap())
5072 0 : return false;
5073 :
5074 15 : tellDebuggerAboutCompiledScript(cx);
5075 : }
5076 :
5077 5405 : return true;
5078 : }
5079 :
5080 : template <typename NameEmitter>
5081 : bool
5082 : BytecodeEmitter::emitDestructuringDeclsWithEmitter(ParseNode* pattern, NameEmitter emitName)
5083 : {
5084 : if (pattern->isKind(PNK_ARRAY)) {
5085 : for (ParseNode* element = pattern->pn_head; element; element = element->pn_next) {
5086 : if (element->isKind(PNK_ELISION))
5087 : continue;
5088 : ParseNode* target = element;
5089 : if (element->isKind(PNK_SPREAD)) {
5090 : target = element->pn_kid;
5091 : }
5092 : if (target->isKind(PNK_ASSIGN))
5093 : target = target->pn_left;
5094 : if (target->isKind(PNK_NAME)) {
5095 : if (!emitName(this, target))
5096 : return false;
5097 : } else {
5098 : if (!emitDestructuringDeclsWithEmitter(target, emitName))
5099 : return false;
5100 : }
5101 : }
5102 : return true;
5103 : }
5104 :
5105 : MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
5106 : for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
5107 : MOZ_ASSERT(member->isKind(PNK_MUTATEPROTO) ||
5108 : member->isKind(PNK_COLON) ||
5109 : member->isKind(PNK_SHORTHAND));
5110 :
5111 : ParseNode* target = member->isKind(PNK_MUTATEPROTO) ? member->pn_kid : member->pn_right;
5112 :
5113 : if (target->isKind(PNK_ASSIGN))
5114 : target = target->pn_left;
5115 : if (target->isKind(PNK_NAME)) {
5116 : if (!emitName(this, target))
5117 : return false;
5118 : } else {
5119 : if (!emitDestructuringDeclsWithEmitter(target, emitName))
5120 : return false;
5121 : }
5122 : }
5123 : return true;
5124 : }
5125 :
5126 : bool
5127 542 : BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target, size_t* emitted)
5128 : {
5129 542 : *emitted = 0;
5130 :
5131 542 : if (target->isKind(PNK_SPREAD))
5132 0 : target = target->pn_kid;
5133 542 : else if (target->isKind(PNK_ASSIGN))
5134 0 : target = target->pn_left;
5135 :
5136 : // No need to recur into PNK_ARRAY and PNK_OBJECT subpatterns here, since
5137 : // emitSetOrInitializeDestructuring does the recursion when setting or
5138 : // initializing value. Getting reference doesn't recur.
5139 542 : if (target->isKind(PNK_NAME) || target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT))
5140 538 : return true;
5141 :
5142 : #ifdef DEBUG
5143 4 : int depth = stackDepth;
5144 : #endif
5145 :
5146 4 : switch (target->getKind()) {
5147 : case PNK_DOT: {
5148 4 : if (target->as<PropertyAccess>().isSuper()) {
5149 0 : if (!emitSuperPropLHS(&target->as<PropertyAccess>().expression()))
5150 0 : return false;
5151 0 : *emitted = 2;
5152 : } else {
5153 4 : if (!emitTree(target->pn_expr))
5154 0 : return false;
5155 4 : *emitted = 1;
5156 : }
5157 4 : break;
5158 : }
5159 :
5160 : case PNK_ELEM: {
5161 0 : if (target->as<PropertyByValue>().isSuper()) {
5162 0 : if (!emitSuperElemOperands(target, EmitElemOption::Ref))
5163 0 : return false;
5164 0 : *emitted = 3;
5165 : } else {
5166 0 : if (!emitElemOperands(target, EmitElemOption::Ref))
5167 0 : return false;
5168 0 : *emitted = 2;
5169 : }
5170 0 : break;
5171 : }
5172 :
5173 : case PNK_CALL:
5174 0 : MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget "
5175 : "rejects function calls as assignment "
5176 : "targets in destructuring assignments");
5177 : break;
5178 :
5179 : default:
5180 0 : MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind");
5181 : }
5182 :
5183 4 : MOZ_ASSERT(stackDepth == depth + int(*emitted));
5184 :
5185 4 : return true;
5186 : }
5187 :
5188 : bool
5189 542 : BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, DestructuringFlavor flav)
5190 : {
5191 : // Now emit the lvalue opcode sequence. If the lvalue is a nested
5192 : // destructuring initialiser-form, call ourselves to handle it, then pop
5193 : // the matched value. Otherwise emit an lvalue bytecode sequence followed
5194 : // by an assignment op.
5195 542 : if (target->isKind(PNK_SPREAD))
5196 0 : target = target->pn_kid;
5197 542 : else if (target->isKind(PNK_ASSIGN))
5198 4 : target = target->pn_left;
5199 542 : if (target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)) {
5200 13 : if (!emitDestructuringOps(target, flav))
5201 0 : return false;
5202 : // Per its post-condition, emitDestructuringOps has left the
5203 : // to-be-destructured value on top of the stack.
5204 13 : if (!emit1(JSOP_POP))
5205 0 : return false;
5206 : } else {
5207 529 : switch (target->getKind()) {
5208 : case PNK_NAME: {
5209 : auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&,
5210 525 : bool emittedBindOp)
5211 : {
5212 525 : if (emittedBindOp) {
5213 : // This is like ordinary assignment, but with one
5214 : // difference.
5215 : //
5216 : // In `a = b`, we first determine a binding for `a` (using
5217 : // JSOP_BINDNAME or JSOP_BINDGNAME), then we evaluate `b`,
5218 : // then a JSOP_SETNAME instruction.
5219 : //
5220 : // In `[a] = [b]`, per spec, `b` is evaluated first, then
5221 : // we determine a binding for `a`. Then we need to do
5222 : // assignment-- but the operands are on the stack in the
5223 : // wrong order for JSOP_SETPROP, so we have to add a
5224 : // JSOP_SWAP.
5225 : //
5226 : // In the cases where we are emitting a name op, emit a
5227 : // swap because of this.
5228 26 : return bce->emit1(JSOP_SWAP);
5229 : }
5230 :
5231 : // In cases of emitting a frame slot or environment slot,
5232 : // nothing needs be done.
5233 499 : return true;
5234 : };
5235 :
5236 525 : RootedAtom name(cx, target->name());
5237 525 : switch (flav) {
5238 : case DestructuringDeclaration:
5239 516 : if (!emitInitializeName(name, emitSwapScopeAndRhs))
5240 0 : return false;
5241 516 : break;
5242 :
5243 : case DestructuringFormalParameterInVarScope: {
5244 : // If there's an parameter expression var scope, the
5245 : // destructuring declaration needs to initialize the name in
5246 : // the function scope. The innermost scope is the var scope,
5247 : // and its enclosing scope is the function scope.
5248 0 : EmitterScope* funScope = innermostEmitterScope->enclosingInFrame();
5249 0 : NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
5250 0 : if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true))
5251 0 : return false;
5252 0 : break;
5253 : }
5254 :
5255 : case DestructuringAssignment:
5256 9 : if (!emitSetName(name, emitSwapScopeAndRhs))
5257 0 : return false;
5258 9 : break;
5259 : }
5260 :
5261 525 : break;
5262 : }
5263 :
5264 : case PNK_DOT: {
5265 : // The reference is already pushed by emitDestructuringLHSRef.
5266 : JSOp setOp;
5267 4 : if (target->as<PropertyAccess>().isSuper())
5268 0 : setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
5269 : else
5270 4 : setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
5271 4 : if (!emitAtomOp(target, setOp))
5272 0 : return false;
5273 4 : break;
5274 : }
5275 :
5276 : case PNK_ELEM: {
5277 : // The reference is already pushed by emitDestructuringLHSRef.
5278 0 : if (target->as<PropertyByValue>().isSuper()) {
5279 0 : JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
5280 : // emitDestructuringLHSRef already did emitSuperElemOperands
5281 : // part of emitSuperElemOp. Perform remaining part here.
5282 0 : if (!emitElemOpBase(setOp))
5283 0 : return false;
5284 : } else {
5285 0 : JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
5286 0 : if (!emitElemOpBase(setOp))
5287 0 : return false;
5288 : }
5289 0 : break;
5290 : }
5291 :
5292 : case PNK_CALL:
5293 0 : MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget "
5294 : "rejects function calls as assignment "
5295 : "targets in destructuring assignments");
5296 : break;
5297 :
5298 : default:
5299 0 : MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind");
5300 : }
5301 :
5302 : // Pop the assigned value.
5303 529 : if (!emit1(JSOP_POP))
5304 0 : return false;
5305 : }
5306 :
5307 542 : return true;
5308 : }
5309 :
5310 : bool
5311 541 : BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = IteratorKind::Sync */,
5312 : bool allowSelfHosted /* = false */)
5313 : {
5314 541 : MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
5315 : ".next() iteration is prohibited in self-hosted code because it "
5316 : "can run user-modifiable iteration code");
5317 :
5318 541 : if (!emit1(JSOP_DUP)) // ... ITER ITER
5319 0 : return false;
5320 541 : if (!emitAtomOp(cx->names().next, JSOP_CALLPROP)) // ... ITER NEXT
5321 0 : return false;
5322 541 : if (!emit1(JSOP_SWAP)) // ... NEXT ITER
5323 0 : return false;
5324 541 : if (!emitCall(JSOP_CALL, 0, pn)) // ... RESULT
5325 0 : return false;
5326 :
5327 541 : if (iterKind == IteratorKind::Async) {
5328 0 : if (!emitAwait()) // ... RESULT
5329 0 : return false;
5330 : }
5331 :
5332 541 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
5333 0 : return false;
5334 541 : checkTypeSet(JSOP_CALL);
5335 541 : return true;
5336 : }
5337 :
5338 : bool
5339 491 : BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync */,
5340 : CompletionKind completionKind /* = CompletionKind::Normal */,
5341 : bool allowSelfHosted /* = false */)
5342 : {
5343 491 : MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
5344 : ".close() on iterators is prohibited in self-hosted code because it "
5345 : "can run user-modifiable iteration code");
5346 :
5347 : // Generate inline logic corresponding to IteratorClose (ES 7.4.6).
5348 : //
5349 : // Callers need to ensure that the iterator object is at the top of the
5350 : // stack.
5351 :
5352 491 : if (!emit1(JSOP_DUP)) // ... ITER ITER
5353 0 : return false;
5354 :
5355 : // Step 3.
5356 : //
5357 : // Get the "return" method.
5358 491 : if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) // ... ITER RET
5359 0 : return false;
5360 :
5361 : // Step 4.
5362 : //
5363 : // Do nothing if "return" is null or undefined.
5364 982 : IfThenElseEmitter ifReturnMethodIsDefined(this);
5365 491 : if (!emit1(JSOP_DUP)) // ... ITER RET RET
5366 0 : return false;
5367 491 : if (!emit1(JSOP_UNDEFINED)) // ... ITER RET RET UNDEFINED
5368 0 : return false;
5369 491 : if (!emit1(JSOP_NE)) // ... ITER RET ?NEQL
5370 0 : return false;
5371 491 : if (!ifReturnMethodIsDefined.emitIfElse())
5372 0 : return false;
5373 :
5374 491 : if (completionKind == CompletionKind::Throw) {
5375 : // 7.4.6 IteratorClose ( iterator, completion )
5376 : // ...
5377 : // 3. Let return be ? GetMethod(iterator, "return").
5378 : // 4. If return is undefined, return Completion(completion).
5379 : // 5. Let innerResult be Call(return, iterator, « »).
5380 : // 6. If completion.[[Type]] is throw, return Completion(completion).
5381 : // 7. If innerResult.[[Type]] is throw, return
5382 : // Completion(innerResult).
5383 : //
5384 : // For CompletionKind::Normal case, JSOP_CALL for step 5 checks if RET
5385 : // is callable, and throws if not. Since step 6 doesn't match and
5386 : // error handling in step 3 and step 7 can be merged.
5387 : //
5388 : // For CompletionKind::Throw case, an error thrown by JSOP_CALL for
5389 : // step 5 is ignored by try-catch. So we should check if RET is
5390 : // callable here, outside of try-catch, and the throw immediately if
5391 : // not.
5392 336 : CheckIsCallableKind kind = CheckIsCallableKind::IteratorReturn;
5393 336 : if (!emitCheckIsCallable(kind)) // ... ITER RET
5394 0 : return false;
5395 : }
5396 :
5397 : // Steps 5, 8.
5398 : //
5399 : // Call "return" if it is not undefined or null, and check that it returns
5400 : // an Object.
5401 491 : if (!emit1(JSOP_SWAP)) // ... RET ITER
5402 0 : return false;
5403 :
5404 982 : Maybe<TryEmitter> tryCatch;
5405 :
5406 491 : if (completionKind == CompletionKind::Throw) {
5407 672 : tryCatch.emplace(this, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
5408 336 : TryEmitter::DontUseControl);
5409 :
5410 : // Mutate stack to balance stack for try-catch.
5411 336 : if (!emit1(JSOP_UNDEFINED)) // ... RET ITER UNDEF
5412 0 : return false;
5413 336 : if (!tryCatch->emitTry()) // ... RET ITER UNDEF
5414 0 : return false;
5415 336 : if (!emitDupAt(2)) // ... RET ITER UNDEF RET
5416 0 : return false;
5417 336 : if (!emitDupAt(2)) // ... RET ITER UNDEF RET ITER
5418 0 : return false;
5419 : }
5420 :
5421 491 : if (!emitCall(JSOP_CALL, 0)) // ... ... RESULT
5422 0 : return false;
5423 491 : checkTypeSet(JSOP_CALL);
5424 :
5425 491 : if (iterKind == IteratorKind::Async) {
5426 0 : if (completionKind != CompletionKind::Throw) {
5427 : // Await clobbers rval, so save the current rval.
5428 0 : if (!emit1(JSOP_GETRVAL)) // ... ... RESULT RVAL
5429 0 : return false;
5430 0 : if (!emit1(JSOP_SWAP)) // ... ... RVAL RESULT
5431 0 : return false;
5432 : }
5433 0 : if (!emitAwait()) // ... ... RVAL? RESULT
5434 0 : return false;
5435 : }
5436 :
5437 491 : if (completionKind == CompletionKind::Throw) {
5438 336 : if (!emit1(JSOP_SWAP)) // ... RET ITER RESULT UNDEF
5439 0 : return false;
5440 336 : if (!emit1(JSOP_POP)) // ... RET ITER RESULT
5441 0 : return false;
5442 :
5443 336 : if (!tryCatch->emitCatch()) // ... RET ITER RESULT
5444 0 : return false;
5445 :
5446 : // Just ignore the exception thrown by call and await.
5447 336 : if (!emit1(JSOP_EXCEPTION)) // ... RET ITER RESULT EXC
5448 0 : return false;
5449 336 : if (!emit1(JSOP_POP)) // ... RET ITER RESULT
5450 0 : return false;
5451 :
5452 336 : if (!tryCatch->emitEnd()) // ... RET ITER RESULT
5453 0 : return false;
5454 :
5455 : // Restore stack.
5456 336 : if (!emit2(JSOP_UNPICK, 2)) // ... RESULT RET ITER
5457 0 : return false;
5458 336 : if (!emitPopN(2)) // ... RESULT
5459 0 : return false;
5460 : } else {
5461 155 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ... RVAL? RESULT
5462 0 : return false;
5463 :
5464 155 : if (iterKind == IteratorKind::Async) {
5465 0 : if (!emit1(JSOP_SWAP)) // ... RESULT RVAL
5466 0 : return false;
5467 0 : if (!emit1(JSOP_SETRVAL)) // ... RESULT
5468 0 : return false;
5469 : }
5470 : }
5471 :
5472 491 : if (!ifReturnMethodIsDefined.emitElse())
5473 0 : return false;
5474 491 : if (!emit1(JSOP_POP)) // ... ITER
5475 0 : return false;
5476 491 : if (!ifReturnMethodIsDefined.emitEnd())
5477 0 : return false;
5478 :
5479 491 : return emit1(JSOP_POP); // ...
5480 : }
5481 :
5482 : template <typename InnerEmitter>
5483 : bool
5484 291 : BytecodeEmitter::wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth, InnerEmitter emitter)
5485 : {
5486 291 : MOZ_ASSERT(this->stackDepth >= iterDepth);
5487 :
5488 : // Pad a nop at the beginning of the bytecode covered by the trynote so
5489 : // that when unwinding environments, we may unwind to the scope
5490 : // corresponding to the pc *before* the start, in case the first bytecode
5491 : // emitted by |emitter| is the start of an inner scope. See comment above
5492 : // UnwindEnvironmentToTryPc.
5493 291 : if (!emit1(JSOP_TRY_DESTRUCTURING_ITERCLOSE))
5494 0 : return false;
5495 :
5496 291 : ptrdiff_t start = offset();
5497 291 : if (!emitter(this))
5498 0 : return false;
5499 291 : ptrdiff_t end = offset();
5500 291 : if (start != end)
5501 151 : return tryNoteList.append(JSTRY_DESTRUCTURING_ITERCLOSE, iterDepth, start, end);
5502 140 : return true;
5503 : }
5504 :
5505 : bool
5506 7 : BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern)
5507 : {
5508 7 : if (!emit1(JSOP_DUP)) // VALUE VALUE
5509 0 : return false;
5510 7 : if (!emit1(JSOP_UNDEFINED)) // VALUE VALUE UNDEFINED
5511 0 : return false;
5512 7 : if (!emit1(JSOP_STRICTEQ)) // VALUE EQL?
5513 0 : return false;
5514 : // Emit source note to enable ion compilation.
5515 7 : if (!newSrcNote(SRC_IF))
5516 0 : return false;
5517 7 : JumpList jump;
5518 7 : if (!emitJump(JSOP_IFEQ, &jump)) // VALUE
5519 0 : return false;
5520 7 : if (!emit1(JSOP_POP)) // .
5521 0 : return false;
5522 7 : if (!emitInitializerInBranch(defaultExpr, pattern)) // DEFAULTVALUE
5523 0 : return false;
5524 7 : if (!emitJumpTargetAndPatch(jump))
5525 0 : return false;
5526 7 : return true;
5527 : }
5528 :
5529 : bool
5530 385 : BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name,
5531 : FunctionPrefixKind prefixKind)
5532 : {
5533 385 : if (maybeFun->isKind(PNK_FUNCTION)) {
5534 : // Function doesn't have 'name' property at this point.
5535 : // Set function's name at compile time.
5536 379 : JSFunction* fun = maybeFun->pn_funbox->function();
5537 :
5538 : // Single node can be emitted multiple times if it appears in
5539 : // array destructuring default. If function already has a name,
5540 : // just return.
5541 379 : if (fun->hasCompileTimeName()) {
5542 : #ifdef DEBUG
5543 0 : RootedFunction rootedFun(cx, fun);
5544 0 : JSAtom* funName = NameToFunctionName(cx, name, prefixKind);
5545 0 : if (!funName)
5546 0 : return false;
5547 0 : MOZ_ASSERT(funName == rootedFun->compileTimeName());
5548 : #endif
5549 0 : return true;
5550 : }
5551 :
5552 379 : fun->setCompileTimeName(name);
5553 379 : return true;
5554 : }
5555 :
5556 : uint32_t nameIndex;
5557 6 : if (!makeAtomIndex(name, &nameIndex))
5558 0 : return false;
5559 6 : if (!emitIndexOp(JSOP_STRING, nameIndex)) // FUN NAME
5560 0 : return false;
5561 6 : uint8_t kind = uint8_t(prefixKind);
5562 6 : if (!emit2(JSOP_SETFUNNAME, kind)) // FUN
5563 0 : return false;
5564 6 : return true;
5565 : }
5566 :
5567 : bool
5568 9300 : BytecodeEmitter::emitInitializer(ParseNode* initializer, ParseNode* pattern)
5569 : {
5570 9300 : if (!emitTree(initializer))
5571 0 : return false;
5572 :
5573 18602 : if (!pattern->isInParens() && pattern->isKind(PNK_NAME) &&
5574 9301 : initializer->isDirectRHSAnonFunction())
5575 : {
5576 216 : RootedAtom name(cx, pattern->name());
5577 108 : if (!setOrEmitSetFunName(initializer, name, FunctionPrefixKind::None))
5578 0 : return false;
5579 : }
5580 :
5581 9301 : return true;
5582 : }
5583 :
5584 : bool
5585 220 : BytecodeEmitter::emitInitializerInBranch(ParseNode* initializer, ParseNode* pattern)
5586 : {
5587 440 : TDZCheckCache tdzCache(this);
5588 440 : return emitInitializer(initializer, pattern);
5589 : }
5590 :
5591 : bool
5592 75 : BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlavor flav)
5593 : {
5594 75 : MOZ_ASSERT(pattern->isKind(PNK_ARRAY));
5595 75 : MOZ_ASSERT(pattern->isArity(PN_LIST));
5596 75 : MOZ_ASSERT(this->stackDepth != 0);
5597 :
5598 : // Here's pseudo code for |let [a, b, , c=y, ...d] = x;|
5599 : //
5600 : // Lines that are annotated "covered by trynote" mean that upon throwing
5601 : // an exception, IteratorClose is called on iter only if done is false.
5602 : //
5603 : // let x, y;
5604 : // let a, b, c, d;
5605 : // let iter, lref, result, done, value; // stack values
5606 : //
5607 : // iter = x[Symbol.iterator]();
5608 : //
5609 : // // ==== emitted by loop for a ====
5610 : // lref = GetReference(a); // covered by trynote
5611 : //
5612 : // result = iter.next();
5613 : // done = result.done;
5614 : //
5615 : // if (done)
5616 : // value = undefined;
5617 : // else
5618 : // value = result.value;
5619 : //
5620 : // SetOrInitialize(lref, value); // covered by trynote
5621 : //
5622 : // // ==== emitted by loop for b ====
5623 : // lref = GetReference(b); // covered by trynote
5624 : //
5625 : // if (done) {
5626 : // value = undefined;
5627 : // } else {
5628 : // result = iter.next();
5629 : // done = result.done;
5630 : // if (done)
5631 : // value = undefined;
5632 : // else
5633 : // value = result.value;
5634 : // }
5635 : //
5636 : // SetOrInitialize(lref, value); // covered by trynote
5637 : //
5638 : // // ==== emitted by loop for elision ====
5639 : // if (done) {
5640 : // value = undefined;
5641 : // } else {
5642 : // result = iter.next();
5643 : // done = result.done;
5644 : // if (done)
5645 : // value = undefined;
5646 : // else
5647 : // value = result.value;
5648 : // }
5649 : //
5650 : // // ==== emitted by loop for c ====
5651 : // lref = GetReference(c); // covered by trynote
5652 : //
5653 : // if (done) {
5654 : // value = undefined;
5655 : // } else {
5656 : // result = iter.next();
5657 : // done = result.done;
5658 : // if (done)
5659 : // value = undefined;
5660 : // else
5661 : // value = result.value;
5662 : // }
5663 : //
5664 : // if (value === undefined)
5665 : // value = y; // covered by trynote
5666 : //
5667 : // SetOrInitialize(lref, value); // covered by trynote
5668 : //
5669 : // // ==== emitted by loop for d ====
5670 : // lref = GetReference(d); // covered by trynote
5671 : //
5672 : // if (done)
5673 : // value = [];
5674 : // else
5675 : // value = [...iter];
5676 : //
5677 : // SetOrInitialize(lref, value); // covered by trynote
5678 : //
5679 : // // === emitted after loop ===
5680 : // if (!done)
5681 : // IteratorClose(iter);
5682 :
5683 : // Use an iterator to destructure the RHS, instead of index lookup. We
5684 : // must leave the *original* value on the stack.
5685 75 : if (!emit1(JSOP_DUP)) // ... OBJ OBJ
5686 0 : return false;
5687 75 : if (!emitIterator()) // ... OBJ ITER
5688 0 : return false;
5689 :
5690 : // For an empty pattern [], call IteratorClose unconditionally. Nothing
5691 : // else needs to be done.
5692 75 : if (!pattern->pn_head)
5693 0 : return emitIteratorClose(); // ... OBJ
5694 :
5695 : // Push an initial FALSE value for DONE.
5696 75 : if (!emit1(JSOP_FALSE)) // ... OBJ ITER FALSE
5697 0 : return false;
5698 :
5699 : // JSTRY_DESTRUCTURING_ITERCLOSE expects the iterator and the done value
5700 : // to be the second to top and the top of the stack, respectively.
5701 : // IteratorClose is called upon exception only if done is false.
5702 75 : int32_t tryNoteDepth = stackDepth;
5703 :
5704 222 : for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
5705 147 : bool isFirst = member == pattern->pn_head;
5706 294 : DebugOnly<bool> hasNext = !!member->pn_next;
5707 :
5708 147 : size_t emitted = 0;
5709 :
5710 : // Spec requires LHS reference to be evaluated first.
5711 147 : ParseNode* lhsPattern = member;
5712 147 : if (lhsPattern->isKind(PNK_ASSIGN))
5713 3 : lhsPattern = lhsPattern->pn_left;
5714 :
5715 147 : bool isElision = lhsPattern->isKind(PNK_ELISION);
5716 147 : if (!isElision) {
5717 144 : auto emitLHSRef = [lhsPattern, &emitted](BytecodeEmitter* bce) {
5718 : return bce->emitDestructuringLHSRef(lhsPattern, &emitted); // ... OBJ ITER DONE *LREF
5719 288 : };
5720 144 : if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitLHSRef))
5721 0 : return false;
5722 : }
5723 :
5724 : // Pick the DONE value to the top of the stack.
5725 147 : if (emitted) {
5726 4 : if (!emit2(JSOP_PICK, emitted)) // ... OBJ ITER *LREF DONE
5727 0 : return false;
5728 : }
5729 :
5730 147 : if (isFirst) {
5731 : // If this element is the first, DONE is always FALSE, so pop it.
5732 : //
5733 : // Non-first elements should emit if-else depending on the
5734 : // member pattern, below.
5735 75 : if (!emit1(JSOP_POP)) // ... OBJ ITER *LREF
5736 0 : return false;
5737 : }
5738 :
5739 147 : if (member->isKind(PNK_SPREAD)) {
5740 0 : IfThenElseEmitter ifThenElse(this);
5741 0 : if (!isFirst) {
5742 : // If spread is not the first element of the pattern,
5743 : // iterator can already be completed.
5744 : // ... OBJ ITER *LREF DONE
5745 0 : if (!ifThenElse.emitIfElse()) // ... OBJ ITER *LREF
5746 0 : return false;
5747 :
5748 0 : if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ ITER *LREF ARRAY
5749 0 : return false;
5750 0 : if (!ifThenElse.emitElse()) // ... OBJ ITER *LREF
5751 0 : return false;
5752 : }
5753 :
5754 : // If iterator is not completed, create a new array with the rest
5755 : // of the iterator.
5756 0 : if (!emitDupAt(emitted)) // ... OBJ ITER *LREF ITER
5757 0 : return false;
5758 0 : if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ ITER *LREF ITER ARRAY
5759 0 : return false;
5760 0 : if (!emitNumberOp(0)) // ... OBJ ITER *LREF ITER ARRAY INDEX
5761 0 : return false;
5762 0 : if (!emitSpread()) // ... OBJ ITER *LREF ARRAY INDEX
5763 0 : return false;
5764 0 : if (!emit1(JSOP_POP)) // ... OBJ ITER *LREF ARRAY
5765 0 : return false;
5766 :
5767 0 : if (!isFirst) {
5768 0 : if (!ifThenElse.emitEnd())
5769 0 : return false;
5770 0 : MOZ_ASSERT(ifThenElse.pushed() == 1);
5771 : }
5772 :
5773 : // At this point the iterator is done. Unpick a TRUE value for DONE above ITER.
5774 0 : if (!emit1(JSOP_TRUE)) // ... OBJ ITER *LREF ARRAY TRUE
5775 0 : return false;
5776 0 : if (!emit2(JSOP_UNPICK, emitted + 1)) // ... OBJ ITER TRUE *LREF ARRAY
5777 0 : return false;
5778 :
5779 0 : auto emitAssignment = [member, flav](BytecodeEmitter* bce) {
5780 : return bce->emitSetOrInitializeDestructuring(member, flav); // ... OBJ ITER TRUE
5781 0 : };
5782 0 : if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitAssignment))
5783 0 : return false;
5784 :
5785 0 : MOZ_ASSERT(!hasNext);
5786 0 : break;
5787 : }
5788 :
5789 147 : ParseNode* pndefault = nullptr;
5790 147 : if (member->isKind(PNK_ASSIGN))
5791 3 : pndefault = member->pn_right;
5792 :
5793 147 : MOZ_ASSERT(!member->isKind(PNK_SPREAD));
5794 :
5795 294 : IfThenElseEmitter ifAlreadyDone(this);
5796 147 : if (!isFirst) {
5797 : // ... OBJ ITER *LREF DONE
5798 72 : if (!ifAlreadyDone.emitIfElse()) // ... OBJ ITER *LREF
5799 0 : return false;
5800 :
5801 72 : if (!emit1(JSOP_UNDEFINED)) // ... OBJ ITER *LREF UNDEF
5802 0 : return false;
5803 72 : if (!emit1(JSOP_NOP_DESTRUCTURING)) // ... OBJ ITER *LREF UNDEF
5804 0 : return false;
5805 :
5806 : // The iterator is done. Unpick a TRUE value for DONE above ITER.
5807 72 : if (!emit1(JSOP_TRUE)) // ... OBJ ITER *LREF UNDEF TRUE
5808 0 : return false;
5809 72 : if (!emit2(JSOP_UNPICK, emitted + 1)) // ... OBJ ITER TRUE *LREF UNDEF
5810 0 : return false;
5811 :
5812 72 : if (!ifAlreadyDone.emitElse()) // ... OBJ ITER *LREF
5813 0 : return false;
5814 : }
5815 :
5816 147 : if (!emitDupAt(emitted)) // ... OBJ ITER *LREF ITER
5817 0 : return false;
5818 147 : if (!emitIteratorNext(pattern)) // ... OBJ ITER *LREF RESULT
5819 0 : return false;
5820 147 : if (!emit1(JSOP_DUP)) // ... OBJ ITER *LREF RESULT RESULT
5821 0 : return false;
5822 147 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ... OBJ ITER *LREF RESULT DONE
5823 0 : return false;
5824 :
5825 147 : if (!emit1(JSOP_DUP)) // ... OBJ ITER *LREF RESULT DONE DONE
5826 0 : return false;
5827 147 : if (!emit2(JSOP_UNPICK, emitted + 2)) // ... OBJ ITER DONE *LREF RESULT DONE
5828 0 : return false;
5829 :
5830 294 : IfThenElseEmitter ifDone(this);
5831 147 : if (!ifDone.emitIfElse()) // ... OBJ ITER DONE *LREF RESULT
5832 0 : return false;
5833 :
5834 147 : if (!emit1(JSOP_POP)) // ... OBJ ITER DONE *LREF
5835 0 : return false;
5836 147 : if (!emit1(JSOP_UNDEFINED)) // ... OBJ ITER DONE *LREF UNDEF
5837 0 : return false;
5838 147 : if (!emit1(JSOP_NOP_DESTRUCTURING)) // ... OBJ ITER DONE *LREF UNDEF
5839 0 : return false;
5840 :
5841 147 : if (!ifDone.emitElse()) // ... OBJ ITER DONE *LREF RESULT
5842 0 : return false;
5843 :
5844 147 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ... OBJ ITER DONE *LREF VALUE
5845 0 : return false;
5846 :
5847 147 : if (!ifDone.emitEnd())
5848 0 : return false;
5849 147 : MOZ_ASSERT(ifDone.pushed() == 0);
5850 :
5851 147 : if (!isFirst) {
5852 72 : if (!ifAlreadyDone.emitEnd())
5853 0 : return false;
5854 72 : MOZ_ASSERT(ifAlreadyDone.pushed() == 2);
5855 : }
5856 :
5857 147 : if (pndefault) {
5858 3 : auto emitDefault = [pndefault, lhsPattern](BytecodeEmitter* bce) {
5859 : return bce->emitDefault(pndefault, lhsPattern); // ... OBJ ITER DONE *LREF VALUE
5860 6 : };
5861 :
5862 3 : if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitDefault))
5863 0 : return false;
5864 : }
5865 :
5866 147 : if (!isElision) {
5867 144 : auto emitAssignment = [lhsPattern, flav](BytecodeEmitter* bce) {
5868 : return bce->emitSetOrInitializeDestructuring(lhsPattern, flav); // ... OBJ ITER DONE
5869 288 : };
5870 :
5871 144 : if (!wrapWithDestructuringIteratorCloseTryNote(tryNoteDepth, emitAssignment))
5872 0 : return false;
5873 : } else {
5874 3 : if (!emit1(JSOP_POP)) // ... OBJ ITER DONE
5875 0 : return false;
5876 : }
5877 : }
5878 :
5879 : // The last DONE value is on top of the stack. If not DONE, call
5880 : // IteratorClose.
5881 : // ... OBJ ITER DONE
5882 150 : IfThenElseEmitter ifDone(this);
5883 75 : if (!ifDone.emitIfElse()) // ... OBJ ITER
5884 0 : return false;
5885 75 : if (!emit1(JSOP_POP)) // ... OBJ
5886 0 : return false;
5887 75 : if (!ifDone.emitElse()) // ... OBJ ITER
5888 0 : return false;
5889 75 : if (!emitIteratorClose()) // ... OBJ
5890 0 : return false;
5891 75 : if (!ifDone.emitEnd())
5892 0 : return false;
5893 :
5894 75 : return true;
5895 : }
5896 :
5897 : bool
5898 5 : BytecodeEmitter::emitComputedPropertyName(ParseNode* computedPropName)
5899 : {
5900 5 : MOZ_ASSERT(computedPropName->isKind(PNK_COMPUTED_NAME));
5901 5 : return emitTree(computedPropName->pn_kid) && emit1(JSOP_TOID);
5902 : }
5903 :
5904 : bool
5905 169 : BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFlavor flav)
5906 : {
5907 169 : MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
5908 169 : MOZ_ASSERT(pattern->isArity(PN_LIST));
5909 :
5910 169 : MOZ_ASSERT(this->stackDepth > 0); // ... RHS
5911 :
5912 169 : if (!emit1(JSOP_CHECKOBJCOERCIBLE)) // ... RHS
5913 0 : return false;
5914 :
5915 279 : bool needsRestPropertyExcludedSet = pattern->pn_count > 1 &&
5916 279 : pattern->last()->isKind(PNK_SPREAD);
5917 169 : if (needsRestPropertyExcludedSet) {
5918 0 : if (!emitDestructuringObjRestExclusionSet(pattern)) // ... RHS SET
5919 0 : return false;
5920 :
5921 0 : if (!emit1(JSOP_SWAP)) // ... SET RHS
5922 0 : return false;
5923 : }
5924 :
5925 567 : for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
5926 : ParseNode* subpattern;
5927 398 : if (member->isKind(PNK_MUTATEPROTO) || member->isKind(PNK_SPREAD))
5928 0 : subpattern = member->pn_kid;
5929 : else
5930 398 : subpattern = member->pn_right;
5931 :
5932 398 : ParseNode* lhs = subpattern;
5933 398 : MOZ_ASSERT_IF(member->isKind(PNK_SPREAD), !lhs->isKind(PNK_ASSIGN));
5934 398 : if (lhs->isKind(PNK_ASSIGN))
5935 4 : lhs = lhs->pn_left;
5936 :
5937 : size_t emitted;
5938 398 : if (!emitDestructuringLHSRef(lhs, &emitted)) // ... *SET RHS *LREF
5939 0 : return false;
5940 :
5941 : // Duplicate the value being destructured to use as a reference base.
5942 398 : if (!emitDupAt(emitted)) // ... *SET RHS *LREF RHS
5943 0 : return false;
5944 :
5945 398 : if (member->isKind(PNK_SPREAD)) {
5946 0 : if (!updateSourceCoordNotes(member->pn_pos.begin))
5947 0 : return false;
5948 :
5949 0 : if (!emitNewInit(JSProto_Object)) // ... *SET RHS *LREF RHS TARGET
5950 0 : return false;
5951 0 : if (!emit1(JSOP_DUP)) // ... *SET RHS *LREF RHS TARGET TARGET
5952 0 : return false;
5953 0 : if (!emit2(JSOP_PICK, 2)) // ... *SET RHS *LREF TARGET TARGET RHS
5954 0 : return false;
5955 :
5956 0 : if (needsRestPropertyExcludedSet) {
5957 0 : if (!emit2(JSOP_PICK, emitted + 4)) // ... RHS *LREF TARGET TARGET RHS SET
5958 0 : return false;
5959 : }
5960 :
5961 : CopyOption option = needsRestPropertyExcludedSet
5962 0 : ? CopyOption::Filtered
5963 0 : : CopyOption::Unfiltered;
5964 0 : if (!emitCopyDataProperties(option)) // ... RHS *LREF TARGET
5965 0 : return false;
5966 :
5967 : // Destructure TARGET per this member's lhs.
5968 0 : if (!emitSetOrInitializeDestructuring(lhs, flav)) // ... RHS
5969 0 : return false;
5970 :
5971 0 : MOZ_ASSERT(member == pattern->last(), "Rest property is always last");
5972 0 : break;
5973 : }
5974 :
5975 : // Now push the property name currently being matched, which is the
5976 : // current property name "label" on the left of a colon in the object
5977 : // initialiser.
5978 398 : bool needsGetElem = true;
5979 :
5980 398 : if (member->isKind(PNK_MUTATEPROTO)) {
5981 0 : if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... *SET RHS *LREF PROP
5982 0 : return false;
5983 0 : needsGetElem = false;
5984 : } else {
5985 398 : MOZ_ASSERT(member->isKind(PNK_COLON) || member->isKind(PNK_SHORTHAND));
5986 :
5987 398 : ParseNode* key = member->pn_left;
5988 398 : if (key->isKind(PNK_NUMBER)) {
5989 0 : if (!emitNumberOp(key->pn_dval)) // ... *SET RHS *LREF RHS KEY
5990 0 : return false;
5991 398 : } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) {
5992 398 : if (!emitAtomOp(key->pn_atom, JSOP_GETPROP)) // ... *SET RHS *LREF PROP
5993 0 : return false;
5994 398 : needsGetElem = false;
5995 : } else {
5996 0 : if (!emitComputedPropertyName(key)) // ... *SET RHS *LREF RHS KEY
5997 0 : return false;
5998 :
5999 : // Add the computed property key to the exclusion set.
6000 0 : if (needsRestPropertyExcludedSet) {
6001 0 : if (!emitDupAt(emitted + 3)) // ... SET RHS *LREF RHS KEY SET
6002 0 : return false;
6003 0 : if (!emitDupAt(1)) // ... SET RHS *LREF RHS KEY SET KEY
6004 0 : return false;
6005 0 : if (!emit1(JSOP_UNDEFINED)) // ... SET RHS *LREF RHS KEY SET KEY UNDEFINED
6006 0 : return false;
6007 0 : if (!emit1(JSOP_INITELEM)) // ... SET RHS *LREF RHS KEY SET
6008 0 : return false;
6009 0 : if (!emit1(JSOP_POP)) // ... SET RHS *LREF RHS KEY
6010 0 : return false;
6011 : }
6012 : }
6013 : }
6014 :
6015 : // Get the property value if not done already.
6016 398 : if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... *SET RHS *LREF PROP
6017 0 : return false;
6018 :
6019 398 : if (subpattern->isKind(PNK_ASSIGN)) {
6020 4 : if (!emitDefault(subpattern->pn_right, lhs)) // ... *SET RHS *LREF VALUE
6021 0 : return false;
6022 : }
6023 :
6024 : // Destructure PROP per this member's lhs.
6025 398 : if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... *SET RHS
6026 0 : return false;
6027 : }
6028 :
6029 169 : return true;
6030 : }
6031 :
6032 : bool
6033 0 : BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern)
6034 : {
6035 0 : MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
6036 0 : MOZ_ASSERT(pattern->isArity(PN_LIST));
6037 0 : MOZ_ASSERT(pattern->last()->isKind(PNK_SPREAD));
6038 :
6039 0 : ptrdiff_t offset = this->offset();
6040 0 : if (!emitNewInit(JSProto_Object))
6041 0 : return false;
6042 :
6043 : // Try to construct the shape of the object as we go, so we can emit a
6044 : // JSOP_NEWOBJECT with the final shape instead.
6045 : // In the case of computed property names and indices, we cannot fix the
6046 : // shape at bytecode compile time. When the shape cannot be determined,
6047 : // |obj| is nulled out.
6048 :
6049 : // No need to do any guessing for the object kind, since we know the upper
6050 : // bound of how many properties we plan to have.
6051 0 : gc::AllocKind kind = gc::GetGCObjectKind(pattern->pn_count - 1);
6052 0 : RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
6053 0 : if (!obj)
6054 0 : return false;
6055 :
6056 0 : RootedAtom pnatom(cx);
6057 0 : for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) {
6058 0 : if (member->isKind(PNK_SPREAD))
6059 0 : break;
6060 :
6061 0 : bool isIndex = false;
6062 0 : if (member->isKind(PNK_MUTATEPROTO)) {
6063 0 : pnatom.set(cx->names().proto);
6064 : } else {
6065 0 : ParseNode* key = member->pn_left;
6066 0 : if (key->isKind(PNK_NUMBER)) {
6067 0 : if (!emitNumberOp(key->pn_dval))
6068 0 : return false;
6069 0 : isIndex = true;
6070 0 : } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) {
6071 0 : pnatom.set(key->pn_atom);
6072 : } else {
6073 : // Otherwise this is a computed property name which needs to
6074 : // be added dynamically.
6075 0 : obj.set(nullptr);
6076 0 : continue;
6077 : }
6078 : }
6079 :
6080 : // Initialize elements with |undefined|.
6081 0 : if (!emit1(JSOP_UNDEFINED))
6082 0 : return false;
6083 :
6084 0 : if (isIndex) {
6085 0 : obj.set(nullptr);
6086 0 : if (!emit1(JSOP_INITELEM))
6087 0 : return false;
6088 : } else {
6089 : uint32_t index;
6090 0 : if (!makeAtomIndex(pnatom, &index))
6091 0 : return false;
6092 :
6093 0 : if (obj) {
6094 0 : MOZ_ASSERT(!obj->inDictionaryMode());
6095 0 : Rooted<jsid> id(cx, AtomToId(pnatom));
6096 0 : if (!NativeDefineProperty(cx, obj, id, UndefinedHandleValue, nullptr, nullptr,
6097 : JSPROP_ENUMERATE))
6098 : {
6099 0 : return false;
6100 : }
6101 0 : if (obj->inDictionaryMode())
6102 0 : obj.set(nullptr);
6103 : }
6104 :
6105 0 : if (!emitIndex32(JSOP_INITPROP, index))
6106 0 : return false;
6107 : }
6108 : }
6109 :
6110 0 : if (obj) {
6111 : // The object survived and has a predictable shape: update the
6112 : // original bytecode.
6113 0 : if (!replaceNewInitWithNewObject(obj, offset))
6114 0 : return false;
6115 : }
6116 :
6117 0 : return true;
6118 : }
6119 :
6120 : bool
6121 244 : BytecodeEmitter::emitDestructuringOps(ParseNode* pattern, DestructuringFlavor flav)
6122 : {
6123 244 : if (pattern->isKind(PNK_ARRAY))
6124 75 : return emitDestructuringOpsArray(pattern, flav);
6125 169 : return emitDestructuringOpsObject(pattern, flav);
6126 : }
6127 :
6128 : bool
6129 252 : BytecodeEmitter::emitTemplateString(ParseNode* pn)
6130 : {
6131 252 : MOZ_ASSERT(pn->isArity(PN_LIST));
6132 :
6133 252 : bool pushedString = false;
6134 :
6135 1708 : for (ParseNode* pn2 = pn->pn_head; pn2 != NULL; pn2 = pn2->pn_next) {
6136 1456 : bool isString = (pn2->getKind() == PNK_STRING || pn2->getKind() == PNK_TEMPLATE_STRING);
6137 :
6138 : // Skip empty strings. These are very common: a template string like
6139 : // `${a}${b}` has three empty strings and without this optimization
6140 : // we'd emit four JSOP_ADD operations instead of just one.
6141 1456 : if (isString && pn2->pn_atom->empty())
6142 115 : continue;
6143 :
6144 1341 : if (!isString) {
6145 : // We update source notes before emitting the expression
6146 602 : if (!updateSourceCoordNotes(pn2->pn_pos.begin))
6147 0 : return false;
6148 : }
6149 :
6150 1341 : if (!emitTree(pn2))
6151 0 : return false;
6152 :
6153 1341 : if (!isString) {
6154 : // We need to convert the expression to a string
6155 602 : if (!emit1(JSOP_TOSTRING))
6156 0 : return false;
6157 : }
6158 :
6159 1341 : if (pushedString) {
6160 : // We've pushed two strings onto the stack. Add them together, leaving just one.
6161 1089 : if (!emit1(JSOP_ADD))
6162 0 : return false;
6163 : } else {
6164 252 : pushedString = true;
6165 : }
6166 : }
6167 :
6168 252 : if (!pushedString) {
6169 : // All strings were empty, this can happen for something like `${""}`.
6170 : // Just push an empty string.
6171 0 : if (!emitAtomOp(cx->names().empty, JSOP_STRING))
6172 0 : return false;
6173 : }
6174 :
6175 252 : return true;
6176 : }
6177 :
6178 : bool
6179 9556 : BytecodeEmitter::emitDeclarationList(ParseNode* declList)
6180 : {
6181 9556 : MOZ_ASSERT(declList->isArity(PN_LIST));
6182 :
6183 : ParseNode* next;
6184 19223 : for (ParseNode* decl = declList->pn_head; decl; decl = next) {
6185 9666 : if (!updateSourceCoordNotes(decl->pn_pos.begin))
6186 0 : return false;
6187 9666 : next = decl->pn_next;
6188 :
6189 9666 : if (decl->isKind(PNK_ASSIGN)) {
6190 130 : MOZ_ASSERT(decl->isOp(JSOP_NOP));
6191 :
6192 130 : ParseNode* pattern = decl->pn_left;
6193 130 : MOZ_ASSERT(pattern->isKind(PNK_ARRAY) || pattern->isKind(PNK_OBJECT));
6194 :
6195 130 : if (!emitTree(decl->pn_right))
6196 0 : return false;
6197 :
6198 130 : if (!emitDestructuringOps(pattern, DestructuringDeclaration))
6199 0 : return false;
6200 :
6201 130 : if (!emit1(JSOP_POP))
6202 0 : return false;
6203 : } else {
6204 9536 : if (!emitSingleDeclaration(declList, decl, decl->expr()))
6205 0 : return false;
6206 : }
6207 : }
6208 9557 : return true;
6209 : }
6210 :
6211 : bool
6212 9536 : BytecodeEmitter::emitSingleDeclaration(ParseNode* declList, ParseNode* decl,
6213 : ParseNode* initializer)
6214 : {
6215 9536 : MOZ_ASSERT(decl->isKind(PNK_NAME));
6216 :
6217 : // Nothing to do for initializer-less 'var' declarations, as there's no TDZ.
6218 9536 : if (!initializer && declList->isKind(PNK_VAR))
6219 304 : return true;
6220 :
6221 27544 : auto emitRhs = [initializer, declList, decl](BytecodeEmitter* bce, const NameLocation&, bool) {
6222 9232 : if (!initializer) {
6223 : // Lexical declarations are initialized to undefined without an
6224 : // initializer.
6225 152 : MOZ_ASSERT(declList->isKind(PNK_LET),
6226 : "var declarations without initializers handled above, "
6227 : "and const declarations must have initializers");
6228 152 : Unused << declList; // silence clang -Wunused-lambda-capture in opt builds
6229 152 : return bce->emit1(JSOP_UNDEFINED);
6230 : }
6231 :
6232 9080 : MOZ_ASSERT(initializer);
6233 9080 : return bce->emitInitializer(initializer, decl);
6234 9232 : };
6235 :
6236 9232 : if (!emitInitializeName(decl, emitRhs))
6237 0 : return false;
6238 :
6239 : // Pop the RHS.
6240 9233 : return emit1(JSOP_POP);
6241 : }
6242 :
6243 : static bool
6244 5736 : EmitAssignmentRhs(BytecodeEmitter* bce, ParseNode* rhs, uint8_t offset)
6245 : {
6246 : // If there is a RHS tree, emit the tree.
6247 5736 : if (rhs)
6248 5736 : return bce->emitTree(rhs);
6249 :
6250 : // Otherwise the RHS value to assign is already on the stack, i.e., the
6251 : // next enumeration value in a for-in or for-of loop. Depending on how
6252 : // many other values have been pushed on the stack, we need to get the
6253 : // already-pushed RHS value.
6254 0 : if (offset != 1 && !bce->emit2(JSOP_PICK, offset - 1))
6255 0 : return false;
6256 :
6257 0 : return true;
6258 : }
6259 :
6260 : bool
6261 5736 : BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
6262 : {
6263 : // Name assignments are handled separately because choosing ops and when
6264 : // to emit BINDNAME is involved and should avoid duplication.
6265 5736 : if (lhs->isKind(PNK_NAME)) {
6266 : auto emitRhs = [op, lhs, rhs](BytecodeEmitter* bce, const NameLocation& lhsLoc,
6267 2654 : bool emittedBindOp)
6268 18622 : {
6269 : // For compound assignments, first get the LHS value, then emit
6270 : // the RHS and the op.
6271 2654 : if (op != JSOP_NOP) {
6272 371 : if (!bce->emitGetNameAtLocationForCompoundAssignment(lhs->name(), lhsLoc))
6273 0 : return false;
6274 : }
6275 :
6276 : // Emit the RHS. If we emitted a BIND[G]NAME, then the scope is on
6277 : // the top of the stack and we need to pick the right RHS value.
6278 5308 : if (!EmitAssignmentRhs(bce, rhs, emittedBindOp ? 2 : 1))
6279 0 : return false;
6280 :
6281 9874 : if (!lhs->isInParens() && op == JSOP_NOP && rhs && rhs->isDirectRHSAnonFunction()) {
6282 44 : RootedAtom name(bce->cx, lhs->name());
6283 44 : if (!bce->setOrEmitSetFunName(rhs, name, FunctionPrefixKind::None))
6284 0 : return false;
6285 : }
6286 :
6287 : // Emit the compound assignment op if there is one.
6288 3025 : if (op != JSOP_NOP && !bce->emit1(op))
6289 0 : return false;
6290 :
6291 2654 : return true;
6292 2654 : };
6293 :
6294 2654 : return emitSetName(lhs, emitRhs);
6295 : }
6296 :
6297 : // Deal with non-name assignments.
6298 3082 : uint32_t atomIndex = (uint32_t) -1;
6299 3082 : uint8_t offset = 1;
6300 :
6301 3082 : switch (lhs->getKind()) {
6302 : case PNK_DOT:
6303 2735 : if (lhs->as<PropertyAccess>().isSuper()) {
6304 0 : if (!emitSuperPropLHS(&lhs->as<PropertyAccess>().expression()))
6305 0 : return false;
6306 0 : offset += 2;
6307 : } else {
6308 2735 : if (!emitTree(lhs->expr()))
6309 0 : return false;
6310 2735 : offset += 1;
6311 : }
6312 2735 : if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
6313 0 : return false;
6314 2735 : break;
6315 : case PNK_ELEM: {
6316 340 : MOZ_ASSERT(lhs->isArity(PN_BINARY));
6317 340 : EmitElemOption opt = op == JSOP_NOP ? EmitElemOption::Get : EmitElemOption::CompoundAssign;
6318 340 : if (lhs->as<PropertyByValue>().isSuper()) {
6319 0 : if (!emitSuperElemOperands(lhs, opt))
6320 0 : return false;
6321 0 : offset += 3;
6322 : } else {
6323 340 : if (!emitElemOperands(lhs, opt))
6324 0 : return false;
6325 340 : offset += 2;
6326 : }
6327 340 : break;
6328 : }
6329 : case PNK_ARRAY:
6330 : case PNK_OBJECT:
6331 7 : break;
6332 : case PNK_CALL:
6333 0 : if (!emitTree(lhs))
6334 0 : return false;
6335 :
6336 : // Assignment to function calls is forbidden, but we have to make the
6337 : // call first. Now we can throw.
6338 0 : if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS))
6339 0 : return false;
6340 :
6341 : // Rebalance the stack to placate stack-depth assertions.
6342 0 : if (!emit1(JSOP_POP))
6343 0 : return false;
6344 0 : break;
6345 : default:
6346 0 : MOZ_ASSERT(0);
6347 : }
6348 :
6349 3082 : if (op != JSOP_NOP) {
6350 60 : MOZ_ASSERT(rhs);
6351 60 : switch (lhs->getKind()) {
6352 : case PNK_DOT: {
6353 : JSOp getOp;
6354 32 : if (lhs->as<PropertyAccess>().isSuper()) {
6355 0 : if (!emit1(JSOP_DUP2))
6356 0 : return false;
6357 0 : getOp = JSOP_GETPROP_SUPER;
6358 : } else {
6359 32 : if (!emit1(JSOP_DUP))
6360 0 : return false;
6361 32 : bool isLength = (lhs->pn_atom == cx->names().length);
6362 32 : getOp = isLength ? JSOP_LENGTH : JSOP_GETPROP;
6363 : }
6364 32 : if (!emitIndex32(getOp, atomIndex))
6365 0 : return false;
6366 32 : break;
6367 : }
6368 : case PNK_ELEM: {
6369 : JSOp elemOp;
6370 28 : if (lhs->as<PropertyByValue>().isSuper()) {
6371 0 : if (!emitDupAt(2))
6372 0 : return false;
6373 0 : if (!emitDupAt(2))
6374 0 : return false;
6375 0 : if (!emitDupAt(2))
6376 0 : return false;
6377 0 : elemOp = JSOP_GETELEM_SUPER;
6378 : } else {
6379 28 : if (!emit1(JSOP_DUP2))
6380 0 : return false;
6381 28 : elemOp = JSOP_GETELEM;
6382 : }
6383 28 : if (!emitElemOpBase(elemOp))
6384 0 : return false;
6385 28 : break;
6386 : }
6387 : case PNK_CALL:
6388 : // We just emitted a JSOP_THROWMSG and popped the call's return
6389 : // value. Push a random value to make sure the stack depth is
6390 : // correct.
6391 0 : if (!emit1(JSOP_NULL))
6392 0 : return false;
6393 0 : break;
6394 : default:;
6395 : }
6396 : }
6397 :
6398 3082 : if (!EmitAssignmentRhs(this, rhs, offset))
6399 0 : return false;
6400 :
6401 : /* If += etc., emit the binary operator with a source note. */
6402 3082 : if (op != JSOP_NOP) {
6403 60 : if (!newSrcNote(SRC_ASSIGNOP))
6404 0 : return false;
6405 60 : if (!emit1(op))
6406 0 : return false;
6407 : }
6408 :
6409 : /* Finally, emit the specialized assignment bytecode. */
6410 3082 : switch (lhs->getKind()) {
6411 : case PNK_DOT: {
6412 5470 : JSOp setOp = lhs->as<PropertyAccess>().isSuper() ?
6413 0 : (sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER) :
6414 5470 : (sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP);
6415 2735 : if (!emitIndexOp(setOp, atomIndex))
6416 0 : return false;
6417 2735 : break;
6418 : }
6419 : case PNK_CALL:
6420 : // We threw above, so nothing to do here.
6421 0 : break;
6422 : case PNK_ELEM: {
6423 680 : JSOp setOp = lhs->as<PropertyByValue>().isSuper() ?
6424 0 : sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER :
6425 680 : sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
6426 340 : if (!emit1(setOp))
6427 0 : return false;
6428 340 : break;
6429 : }
6430 : case PNK_ARRAY:
6431 : case PNK_OBJECT:
6432 7 : if (!emitDestructuringOps(lhs, DestructuringAssignment))
6433 0 : return false;
6434 7 : break;
6435 : default:
6436 0 : MOZ_ASSERT(0);
6437 : }
6438 3082 : return true;
6439 : }
6440 :
6441 : bool
6442 4773 : ParseNode::getConstantValue(JSContext* cx, AllowConstantObjects allowObjects,
6443 : MutableHandleValue vp, Value* compare, size_t ncompare,
6444 : NewObjectKind newKind)
6445 : {
6446 4773 : MOZ_ASSERT(newKind == TenuredObject || newKind == SingletonObject);
6447 :
6448 4773 : switch (getKind()) {
6449 : case PNK_NUMBER:
6450 102 : vp.setNumber(pn_dval);
6451 102 : return true;
6452 : case PNK_TEMPLATE_STRING:
6453 : case PNK_STRING:
6454 3454 : vp.setString(pn_atom);
6455 3454 : return true;
6456 : case PNK_TRUE:
6457 2 : vp.setBoolean(true);
6458 2 : return true;
6459 : case PNK_FALSE:
6460 2 : vp.setBoolean(false);
6461 2 : return true;
6462 : case PNK_NULL:
6463 6 : vp.setNull();
6464 6 : return true;
6465 : case PNK_RAW_UNDEFINED:
6466 0 : vp.setUndefined();
6467 0 : return true;
6468 : case PNK_CALLSITEOBJ:
6469 : case PNK_ARRAY: {
6470 : unsigned count;
6471 : ParseNode* pn;
6472 :
6473 473 : if (allowObjects == DontAllowObjects) {
6474 4 : vp.setMagic(JS_GENERIC_MAGIC);
6475 4 : return true;
6476 : }
6477 :
6478 469 : ObjectGroup::NewArrayKind arrayKind = ObjectGroup::NewArrayKind::Normal;
6479 469 : if (allowObjects == ForCopyOnWriteArray) {
6480 452 : arrayKind = ObjectGroup::NewArrayKind::CopyOnWrite;
6481 452 : allowObjects = DontAllowObjects;
6482 : }
6483 :
6484 469 : if (getKind() == PNK_CALLSITEOBJ) {
6485 1 : count = pn_count - 1;
6486 1 : pn = pn_head->pn_next;
6487 : } else {
6488 468 : MOZ_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
6489 468 : count = pn_count;
6490 468 : pn = pn_head;
6491 : }
6492 :
6493 939 : AutoValueVector values(cx);
6494 469 : if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), count))
6495 0 : return false;
6496 : size_t idx;
6497 2076 : for (idx = 0; pn; idx++, pn = pn->pn_next) {
6498 1614 : if (!pn->getConstantValue(cx, allowObjects, values[idx], values.begin(), idx))
6499 0 : return false;
6500 1614 : if (values[idx].isMagic(JS_GENERIC_MAGIC)) {
6501 7 : vp.setMagic(JS_GENERIC_MAGIC);
6502 7 : return true;
6503 : }
6504 : }
6505 462 : MOZ_ASSERT(idx == count);
6506 :
6507 462 : JSObject* obj = ObjectGroup::newArrayObject(cx, values.begin(), values.length(),
6508 462 : newKind, arrayKind);
6509 463 : if (!obj)
6510 0 : return false;
6511 :
6512 463 : if (!CombineArrayElementTypes(cx, obj, compare, ncompare))
6513 0 : return false;
6514 :
6515 463 : vp.setObject(*obj);
6516 463 : return true;
6517 : }
6518 : case PNK_OBJECT: {
6519 734 : MOZ_ASSERT(isOp(JSOP_NEWINIT));
6520 734 : MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
6521 :
6522 734 : if (allowObjects == DontAllowObjects) {
6523 3 : vp.setMagic(JS_GENERIC_MAGIC);
6524 3 : return true;
6525 : }
6526 731 : MOZ_ASSERT(allowObjects == AllowObjects);
6527 :
6528 1462 : Rooted<IdValueVector> properties(cx, IdValueVector(cx));
6529 :
6530 1462 : RootedValue value(cx), idvalue(cx);
6531 3395 : for (ParseNode* pn = pn_head; pn; pn = pn->pn_next) {
6532 2664 : if (!pn->pn_right->getConstantValue(cx, allowObjects, &value))
6533 0 : return false;
6534 2664 : if (value.isMagic(JS_GENERIC_MAGIC)) {
6535 0 : vp.setMagic(JS_GENERIC_MAGIC);
6536 0 : return true;
6537 : }
6538 :
6539 2664 : ParseNode* pnid = pn->pn_left;
6540 2664 : if (pnid->isKind(PNK_NUMBER)) {
6541 0 : idvalue = NumberValue(pnid->pn_dval);
6542 : } else {
6543 2664 : MOZ_ASSERT(pnid->isKind(PNK_OBJECT_PROPERTY_NAME) || pnid->isKind(PNK_STRING));
6544 2664 : MOZ_ASSERT(pnid->pn_atom != cx->names().proto);
6545 2664 : idvalue = StringValue(pnid->pn_atom);
6546 : }
6547 :
6548 5328 : RootedId id(cx);
6549 2664 : if (!ValueToId<CanGC>(cx, idvalue, &id))
6550 0 : return false;
6551 :
6552 2664 : if (!properties.append(IdValuePair(id, value)))
6553 0 : return false;
6554 : }
6555 :
6556 731 : JSObject* obj = ObjectGroup::newPlainObject(cx, properties.begin(), properties.length(),
6557 731 : newKind);
6558 731 : if (!obj)
6559 0 : return false;
6560 :
6561 731 : if (!CombinePlainObjectPropertyTypes(cx, obj, compare, ncompare))
6562 0 : return false;
6563 :
6564 731 : vp.setObject(*obj);
6565 731 : return true;
6566 : }
6567 : default:
6568 0 : MOZ_CRASH("Unexpected node");
6569 : }
6570 : return false;
6571 : }
6572 :
6573 : bool
6574 41 : BytecodeEmitter::emitSingletonInitialiser(ParseNode* pn)
6575 : {
6576 41 : NewObjectKind newKind = (pn->getKind() == PNK_OBJECT) ? SingletonObject : TenuredObject;
6577 :
6578 82 : RootedValue value(cx);
6579 41 : if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value, nullptr, 0, newKind))
6580 0 : return false;
6581 :
6582 41 : MOZ_ASSERT_IF(newKind == SingletonObject, value.toObject().isSingleton());
6583 :
6584 41 : ObjectBox* objbox = parser.newObjectBox(&value.toObject());
6585 41 : if (!objbox)
6586 0 : return false;
6587 :
6588 41 : return emitObjectOp(objbox, JSOP_OBJECT);
6589 : }
6590 :
6591 : bool
6592 1 : BytecodeEmitter::emitCallSiteObject(ParseNode* pn)
6593 : {
6594 2 : RootedValue value(cx);
6595 1 : if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value))
6596 0 : return false;
6597 :
6598 1 : MOZ_ASSERT(value.isObject());
6599 :
6600 1 : ObjectBox* objbox1 = parser.newObjectBox(&value.toObject());
6601 1 : if (!objbox1)
6602 0 : return false;
6603 :
6604 1 : if (!pn->as<CallSiteNode>().getRawArrayValue(cx, &value))
6605 0 : return false;
6606 :
6607 1 : MOZ_ASSERT(value.isObject());
6608 :
6609 1 : ObjectBox* objbox2 = parser.newObjectBox(&value.toObject());
6610 1 : if (!objbox2)
6611 0 : return false;
6612 :
6613 1 : return emitObjectPairOp(objbox1, objbox2, JSOP_CALLSITEOBJ);
6614 : }
6615 :
6616 : /* See the SRC_FOR source note offsetBias comments later in this file. */
6617 : JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
6618 : JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
6619 :
6620 : namespace {
6621 :
6622 : class EmitLevelManager
6623 : {
6624 : BytecodeEmitter* bce;
6625 : public:
6626 227349 : explicit EmitLevelManager(BytecodeEmitter* bce) : bce(bce) { bce->emitLevel++; }
6627 227361 : ~EmitLevelManager() { bce->emitLevel--; }
6628 : };
6629 :
6630 : } /* anonymous namespace */
6631 :
6632 : bool
6633 467 : BytecodeEmitter::emitCatch(ParseNode* pn)
6634 : {
6635 : // We must be nested under a try-finally statement.
6636 467 : TryFinallyControl& controlInfo = innermostNestableControl->as<TryFinallyControl>();
6637 :
6638 : /* Pick up the pending exception and bind it to the catch variable. */
6639 467 : if (!emit1(JSOP_EXCEPTION))
6640 0 : return false;
6641 :
6642 : /*
6643 : * Dup the exception object if there is a guard for rethrowing to use
6644 : * it later when rethrowing or in other catches.
6645 : */
6646 467 : if (pn->pn_kid2 && !emit1(JSOP_DUP))
6647 0 : return false;
6648 :
6649 467 : ParseNode* pn2 = pn->pn_kid1;
6650 467 : switch (pn2->getKind()) {
6651 : case PNK_ARRAY:
6652 : case PNK_OBJECT:
6653 0 : if (!emitDestructuringOps(pn2, DestructuringDeclaration))
6654 0 : return false;
6655 0 : if (!emit1(JSOP_POP))
6656 0 : return false;
6657 0 : break;
6658 :
6659 : case PNK_NAME:
6660 467 : if (!emitLexicalInitialization(pn2))
6661 0 : return false;
6662 467 : if (!emit1(JSOP_POP))
6663 0 : return false;
6664 467 : break;
6665 :
6666 : default:
6667 0 : MOZ_ASSERT(0);
6668 : }
6669 :
6670 : // If there is a guard expression, emit it and arrange to jump to the next
6671 : // catch block if the guard expression is false.
6672 467 : if (pn->pn_kid2) {
6673 0 : if (!emitTree(pn->pn_kid2))
6674 0 : return false;
6675 :
6676 : // If the guard expression is false, fall through, pop the block scope,
6677 : // and jump to the next catch block. Otherwise jump over that code and
6678 : // pop the dupped exception.
6679 0 : JumpList guardCheck;
6680 0 : if (!emitJump(JSOP_IFNE, &guardCheck))
6681 0 : return false;
6682 :
6683 : {
6684 0 : NonLocalExitControl nle(this, NonLocalExitControl::Throw);
6685 :
6686 : // Move exception back to cx->exception to prepare for
6687 : // the next catch.
6688 0 : if (!emit1(JSOP_THROWING))
6689 0 : return false;
6690 :
6691 : // Leave the scope for this catch block.
6692 0 : if (!nle.prepareForNonLocalJump(&controlInfo))
6693 0 : return false;
6694 :
6695 : // Jump to the next handler added by emitTry.
6696 0 : if (!emitJump(JSOP_GOTO, &controlInfo.guardJump))
6697 0 : return false;
6698 : }
6699 :
6700 : // Back to normal control flow.
6701 0 : if (!emitJumpTargetAndPatch(guardCheck))
6702 0 : return false;
6703 :
6704 : // Pop duplicated exception object as we no longer need it.
6705 0 : if (!emit1(JSOP_POP))
6706 0 : return false;
6707 : }
6708 :
6709 : /* Emit the catch body. */
6710 467 : return emitTree(pn->pn_kid3);
6711 : }
6712 :
6713 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the
6714 : // comment on EmitSwitch.
6715 : MOZ_NEVER_INLINE bool
6716 489 : BytecodeEmitter::emitTry(ParseNode* pn)
6717 : {
6718 489 : ParseNode* catchList = pn->pn_kid2;
6719 489 : ParseNode* finallyNode = pn->pn_kid3;
6720 :
6721 : TryEmitter::Kind kind;
6722 489 : if (catchList) {
6723 467 : if (finallyNode)
6724 19 : kind = TryEmitter::TryCatchFinally;
6725 : else
6726 448 : kind = TryEmitter::TryCatch;
6727 : } else {
6728 22 : MOZ_ASSERT(finallyNode);
6729 22 : kind = TryEmitter::TryFinally;
6730 : }
6731 978 : TryEmitter tryCatch(this, kind);
6732 :
6733 489 : if (!tryCatch.emitTry())
6734 0 : return false;
6735 :
6736 489 : if (!emitTree(pn->pn_kid1))
6737 0 : return false;
6738 :
6739 : // If this try has a catch block, emit it.
6740 489 : if (catchList) {
6741 467 : MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
6742 :
6743 : // The emitted code for a catch block looks like:
6744 : //
6745 : // [pushlexicalenv] only if any local aliased
6746 : // exception
6747 : // if there is a catchguard:
6748 : // dup
6749 : // setlocal 0; pop assign or possibly destructure exception
6750 : // if there is a catchguard:
6751 : // < catchguard code >
6752 : // ifne POST
6753 : // debugleaveblock
6754 : // [poplexicalenv] only if any local aliased
6755 : // throwing pop exception to cx->exception
6756 : // goto <next catch block>
6757 : // POST: pop
6758 : // < catch block contents >
6759 : // debugleaveblock
6760 : // [poplexicalenv] only if any local aliased
6761 : // goto <end of catch blocks> non-local; finally applies
6762 : //
6763 : // If there's no catch block without a catchguard, the last <next catch
6764 : // block> points to rethrow code. This code will [gosub] to the finally
6765 : // code if appropriate, and is also used for the catch-all trynote for
6766 : // capturing exceptions thrown from catch{} blocks.
6767 : //
6768 934 : for (ParseNode* pn3 = catchList->pn_head; pn3; pn3 = pn3->pn_next) {
6769 467 : if (!tryCatch.emitCatch())
6770 0 : return false;
6771 :
6772 : // Emit the lexical scope and catch body.
6773 467 : MOZ_ASSERT(pn3->isKind(PNK_LEXICALSCOPE));
6774 467 : if (!emitTree(pn3))
6775 0 : return false;
6776 : }
6777 : }
6778 :
6779 : // Emit the finally handler, if there is one.
6780 489 : if (finallyNode) {
6781 41 : if (!tryCatch.emitFinally(Some(finallyNode->pn_pos.begin)))
6782 0 : return false;
6783 :
6784 41 : if (!emitTree(finallyNode))
6785 0 : return false;
6786 : }
6787 :
6788 489 : if (!tryCatch.emitEnd())
6789 0 : return false;
6790 :
6791 489 : return true;
6792 : }
6793 :
6794 : bool
6795 6761 : BytecodeEmitter::emitIf(ParseNode* pn)
6796 : {
6797 13523 : IfThenElseEmitter ifThenElse(this);
6798 :
6799 : if_again:
6800 : /* Emit code for the condition before pushing stmtInfo. */
6801 7037 : if (!emitTreeInBranch(pn->pn_kid1))
6802 0 : return false;
6803 :
6804 7038 : ParseNode* elseNode = pn->pn_kid3;
6805 7038 : if (elseNode) {
6806 925 : if (!ifThenElse.emitIfElse())
6807 0 : return false;
6808 : } else {
6809 6113 : if (!ifThenElse.emitIf())
6810 0 : return false;
6811 : }
6812 :
6813 : /* Emit code for the then part. */
6814 7038 : if (!emitTreeInBranch(pn->pn_kid2))
6815 0 : return false;
6816 :
6817 7038 : if (elseNode) {
6818 925 : if (!ifThenElse.emitElse())
6819 0 : return false;
6820 :
6821 925 : if (elseNode->isKind(PNK_IF)) {
6822 276 : pn = elseNode;
6823 276 : goto if_again;
6824 : }
6825 :
6826 : /* Emit code for the else part. */
6827 649 : if (!emitTreeInBranch(elseNode))
6828 0 : return false;
6829 : }
6830 :
6831 6762 : if (!ifThenElse.emitEnd())
6832 0 : return false;
6833 :
6834 6762 : return true;
6835 : }
6836 :
6837 : bool
6838 43 : BytecodeEmitter::emitHoistedFunctionsInList(ParseNode* list)
6839 : {
6840 43 : MOZ_ASSERT(list->pn_xflags & PNX_FUNCDEFS);
6841 :
6842 526 : for (ParseNode* pn = list->pn_head; pn; pn = pn->pn_next) {
6843 483 : ParseNode* maybeFun = pn;
6844 :
6845 483 : if (!sc->strict()) {
6846 148 : while (maybeFun->isKind(PNK_LABEL))
6847 0 : maybeFun = maybeFun->as<LabeledStatement>().statement();
6848 : }
6849 :
6850 483 : if (maybeFun->isKind(PNK_FUNCTION) && maybeFun->functionIsHoisted()) {
6851 68 : if (!emitTree(maybeFun))
6852 0 : return false;
6853 : }
6854 : }
6855 :
6856 43 : return true;
6857 : }
6858 :
6859 : bool
6860 12188 : BytecodeEmitter::emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLineNote)
6861 : {
6862 12188 : if (body->isKind(PNK_STATEMENTLIST) && body->pn_xflags & PNX_FUNCDEFS) {
6863 : // This block contains function statements whose definitions are
6864 : // hoisted to the top of the block. Emit these as a separate pass
6865 : // before the rest of the block.
6866 43 : if (!emitHoistedFunctionsInList(body))
6867 0 : return false;
6868 : }
6869 :
6870 : // Line notes were updated by emitLexicalScope.
6871 12188 : return emitTree(body, ValueUsage::WantValue, emitLineNote);
6872 : }
6873 :
6874 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
6875 : // the comment on emitSwitch.
6876 : MOZ_NEVER_INLINE bool
6877 12679 : BytecodeEmitter::emitLexicalScope(ParseNode* pn)
6878 : {
6879 12679 : MOZ_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
6880 :
6881 25359 : TDZCheckCache tdzCache(this);
6882 :
6883 12679 : ParseNode* body = pn->scopeBody();
6884 12679 : if (pn->isEmptyScope())
6885 9774 : return emitLexicalScopeBody(body);
6886 :
6887 : // Update line number notes before emitting TDZ poison in
6888 : // EmitterScope::enterLexical to avoid spurious pausing on seemingly
6889 : // non-effectful lines in Debugger.
6890 : //
6891 : // For example, consider the following code.
6892 : //
6893 : // L1: {
6894 : // L2: let x = 42;
6895 : // L3: }
6896 : //
6897 : // If line number notes were not updated before the TDZ poison, the TDZ
6898 : // poison bytecode sequence of 'uninitialized; initlexical' will have line
6899 : // number L1, and the Debugger will pause there.
6900 2905 : if (!ParseNodeRequiresSpecialLineNumberNotes(body)) {
6901 2414 : ParseNode* pnForPos = body;
6902 2414 : if (body->isKind(PNK_STATEMENTLIST) && body->pn_head)
6903 1947 : pnForPos = body->pn_head;
6904 2414 : if (!updateLineNumberNotes(pnForPos->pn_pos.begin))
6905 0 : return false;
6906 : }
6907 :
6908 5811 : EmitterScope emitterScope(this);
6909 : ScopeKind kind;
6910 2905 : if (body->isKind(PNK_CATCH))
6911 467 : kind = body->pn_kid1->isKind(PNK_NAME) ? ScopeKind::SimpleCatch : ScopeKind::Catch;
6912 : else
6913 2438 : kind = ScopeKind::Lexical;
6914 :
6915 2905 : if (!emitterScope.enterLexical(this, kind, pn->scopeBindings()))
6916 0 : return false;
6917 :
6918 2905 : if (body->isKind(PNK_FOR)) {
6919 : // for loops need to emit {FRESHEN,RECREATE}LEXICALENV if there are
6920 : // lexical declarations in the head. Signal this by passing a
6921 : // non-nullptr lexical scope.
6922 491 : if (!emitFor(body, &emitterScope))
6923 0 : return false;
6924 : } else {
6925 2414 : if (!emitLexicalScopeBody(body, SUPPRESS_LINENOTE))
6926 0 : return false;
6927 : }
6928 :
6929 2906 : return emitterScope.leave(this);
6930 : }
6931 :
6932 : bool
6933 0 : BytecodeEmitter::emitWith(ParseNode* pn)
6934 : {
6935 0 : if (!emitTree(pn->pn_left))
6936 0 : return false;
6937 :
6938 0 : EmitterScope emitterScope(this);
6939 0 : if (!emitterScope.enterWith(this))
6940 0 : return false;
6941 :
6942 0 : if (!emitTree(pn->pn_right))
6943 0 : return false;
6944 :
6945 0 : return emitterScope.leave(this);
6946 : }
6947 :
6948 : bool
6949 0 : BytecodeEmitter::emitCopyDataProperties(CopyOption option)
6950 : {
6951 0 : DebugOnly<int32_t> depth = this->stackDepth;
6952 :
6953 : uint32_t argc;
6954 0 : if (option == CopyOption::Filtered) {
6955 0 : MOZ_ASSERT(depth > 2); // TARGET SOURCE SET
6956 0 : argc = 3;
6957 :
6958 0 : if (!emitAtomOp(cx->names().CopyDataProperties,
6959 0 : JSOP_GETINTRINSIC)) // TARGET SOURCE SET COPYDATAPROPERTIES
6960 : {
6961 0 : return false;
6962 : }
6963 : } else {
6964 0 : MOZ_ASSERT(depth > 1); // TARGET SOURCE
6965 0 : argc = 2;
6966 :
6967 0 : if (!emitAtomOp(cx->names().CopyDataPropertiesUnfiltered,
6968 0 : JSOP_GETINTRINSIC)) // TARGET SOURCE COPYDATAPROPERTIES
6969 : {
6970 0 : return false;
6971 : }
6972 : }
6973 :
6974 0 : if (!emit1(JSOP_UNDEFINED)) // TARGET SOURCE *SET COPYDATAPROPERTIES UNDEFINED
6975 0 : return false;
6976 0 : if (!emit2(JSOP_PICK, argc + 1)) // SOURCE *SET COPYDATAPROPERTIES UNDEFINED TARGET
6977 0 : return false;
6978 0 : if (!emit2(JSOP_PICK, argc + 1)) // *SET COPYDATAPROPERTIES UNDEFINED TARGET SOURCE
6979 0 : return false;
6980 0 : if (option == CopyOption::Filtered) {
6981 0 : if (!emit2(JSOP_PICK, argc + 1)) // COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET
6982 0 : return false;
6983 : }
6984 0 : if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) // IGNORED
6985 0 : return false;
6986 0 : checkTypeSet(JSOP_CALL_IGNORES_RV);
6987 :
6988 0 : if (!emit1(JSOP_POP)) // -
6989 0 : return false;
6990 :
6991 0 : MOZ_ASSERT(depth - int(argc) == this->stackDepth);
6992 0 : return true;
6993 : }
6994 :
6995 : bool
6996 472 : BytecodeEmitter::emitIterator()
6997 : {
6998 : // Convert iterable to iterator.
6999 472 : if (!emit1(JSOP_DUP)) // OBJ OBJ
7000 0 : return false;
7001 472 : if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
7002 0 : return false;
7003 472 : if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
7004 0 : return false;
7005 472 : if (!emit1(JSOP_SWAP)) // ITERFN OBJ
7006 0 : return false;
7007 472 : if (!emitCall(JSOP_CALLITER, 0)) // ITER
7008 0 : return false;
7009 472 : checkTypeSet(JSOP_CALLITER);
7010 472 : if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
7011 0 : return false;
7012 472 : return true;
7013 : }
7014 :
7015 : bool
7016 0 : BytecodeEmitter::emitAsyncIterator()
7017 : {
7018 : // Convert iterable to iterator.
7019 0 : if (!emit1(JSOP_DUP)) // OBJ OBJ
7020 0 : return false;
7021 0 : if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::asyncIterator))) // OBJ OBJ @@ASYNCITERATOR
7022 0 : return false;
7023 0 : if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
7024 0 : return false;
7025 :
7026 0 : IfThenElseEmitter ifAsyncIterIsUndefined(this);
7027 0 : if (!emit1(JSOP_DUP)) // OBJ ITERFN ITERFN
7028 0 : return false;
7029 0 : if (!emit1(JSOP_UNDEFINED)) // OBJ ITERFN ITERFN UNDEF
7030 0 : return false;
7031 0 : if (!emit1(JSOP_EQ)) // OBJ ITERFN EQ
7032 0 : return false;
7033 0 : if (!ifAsyncIterIsUndefined.emitIfElse()) // OBJ ITERFN
7034 0 : return false;
7035 :
7036 0 : if (!emit1(JSOP_POP)) // OBJ
7037 0 : return false;
7038 0 : if (!emit1(JSOP_DUP)) // OBJ OBJ
7039 0 : return false;
7040 0 : if (!emit2(JSOP_SYMBOL, uint8_t(JS::SymbolCode::iterator))) // OBJ OBJ @@ITERATOR
7041 0 : return false;
7042 0 : if (!emitElemOpBase(JSOP_CALLELEM)) // OBJ ITERFN
7043 0 : return false;
7044 0 : if (!emit1(JSOP_SWAP)) // ITERFN OBJ
7045 0 : return false;
7046 0 : if (!emitCall(JSOP_CALLITER, 0)) // ITER
7047 0 : return false;
7048 0 : checkTypeSet(JSOP_CALLITER);
7049 0 : if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
7050 0 : return false;
7051 :
7052 0 : if (!emit1(JSOP_TOASYNCITER)) // ITER
7053 0 : return false;
7054 :
7055 0 : if (!ifAsyncIterIsUndefined.emitElse()) // OBJ ITERFN
7056 0 : return false;
7057 :
7058 0 : if (!emit1(JSOP_SWAP)) // ITERFN OBJ
7059 0 : return false;
7060 0 : if (!emitCall(JSOP_CALLITER, 0)) // ITER
7061 0 : return false;
7062 0 : checkTypeSet(JSOP_CALLITER);
7063 0 : if (!emitCheckIsObj(CheckIsObjectKind::GetIterator)) // ITER
7064 0 : return false;
7065 :
7066 0 : if (!ifAsyncIterIsUndefined.emitEnd()) // ITER
7067 0 : return false;
7068 :
7069 0 : return true;
7070 : }
7071 :
7072 : bool
7073 58 : BytecodeEmitter::emitSpread(bool allowSelfHosted)
7074 : {
7075 116 : LoopControl loopInfo(this, StatementKind::Spread);
7076 :
7077 : // Jump down to the loop condition to minimize overhead assuming at least
7078 : // one iteration, as the other loop forms do. Annotate so IonMonkey can
7079 : // find the loop-closing jump.
7080 : unsigned noteIndex;
7081 58 : if (!newSrcNote(SRC_FOR_OF, ¬eIndex))
7082 0 : return false;
7083 :
7084 : // Jump down to the loop condition to minimize overhead, assuming at least
7085 : // one iteration. (This is also what we do for loops; whether this
7086 : // assumption holds for spreads is an unanswered question.)
7087 58 : JumpList initialJump;
7088 58 : if (!emitJump(JSOP_GOTO, &initialJump)) // ITER ARR I (during the goto)
7089 0 : return false;
7090 :
7091 58 : JumpTarget top{ -1 };
7092 58 : if (!emitLoopHead(nullptr, &top)) // ITER ARR I
7093 0 : return false;
7094 :
7095 : // When we enter the goto above, we have ITER ARR I on the stack. But when
7096 : // we reach this point on the loop backedge (if spreading produces at least
7097 : // one value), we've additionally pushed a RESULT iteration value.
7098 : // Increment manually to reflect this.
7099 58 : this->stackDepth++;
7100 :
7101 58 : JumpList beq;
7102 58 : JumpTarget breakTarget{ -1 };
7103 : {
7104 : #ifdef DEBUG
7105 58 : auto loopDepth = this->stackDepth;
7106 : #endif
7107 :
7108 : // Emit code to assign result.value to the iteration variable.
7109 58 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER ARR I VALUE
7110 0 : return false;
7111 58 : if (!emit1(JSOP_INITELEM_INC)) // ITER ARR (I+1)
7112 0 : return false;
7113 :
7114 58 : MOZ_ASSERT(this->stackDepth == loopDepth - 1);
7115 :
7116 : // Spread operations can't contain |continue|, so don't bother setting loop
7117 : // and enclosing "update" offsets, as we do with for-loops.
7118 :
7119 : // COME FROM the beginning of the loop to here.
7120 58 : if (!emitLoopEntry(nullptr, initialJump)) // ITER ARR I
7121 0 : return false;
7122 :
7123 58 : if (!emitDupAt(2)) // ITER ARR I ITER
7124 0 : return false;
7125 58 : if (!emitIteratorNext(nullptr, IteratorKind::Sync, allowSelfHosted)) // ITER ARR I RESULT
7126 0 : return false;
7127 58 : if (!emit1(JSOP_DUP)) // ITER ARR I RESULT RESULT
7128 0 : return false;
7129 58 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER ARR I RESULT DONE
7130 0 : return false;
7131 :
7132 58 : if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget)) // ITER ARR I RESULT
7133 0 : return false;
7134 :
7135 58 : MOZ_ASSERT(this->stackDepth == loopDepth);
7136 : }
7137 :
7138 : // Let Ion know where the closing jump of this loop is.
7139 58 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
7140 0 : return false;
7141 :
7142 : // No breaks or continues should occur in spreads.
7143 58 : MOZ_ASSERT(loopInfo.breaks.offset == -1);
7144 58 : MOZ_ASSERT(loopInfo.continues.offset == -1);
7145 :
7146 58 : if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
7147 0 : return false;
7148 :
7149 58 : if (!emit2(JSOP_PICK, 3)) // ARR FINAL_INDEX RESULT ITER
7150 0 : return false;
7151 :
7152 58 : return emitPopN(2); // ARR FINAL_INDEX
7153 : }
7154 :
7155 : bool
7156 372 : BytecodeEmitter::emitInitializeForInOrOfTarget(ParseNode* forHead)
7157 : {
7158 372 : MOZ_ASSERT(forHead->isKind(PNK_FORIN) || forHead->isKind(PNK_FOROF));
7159 372 : MOZ_ASSERT(forHead->isArity(PN_TERNARY));
7160 :
7161 372 : MOZ_ASSERT(this->stackDepth >= 1,
7162 : "must have a per-iteration value for initializing");
7163 :
7164 372 : ParseNode* target = forHead->pn_kid1;
7165 372 : MOZ_ASSERT(!forHead->pn_kid2);
7166 :
7167 : // If the for-in/of loop didn't have a variable declaration, per-loop
7168 : // initialization is just assigning the iteration value to a target
7169 : // expression.
7170 372 : if (!parser.isDeclarationList(target))
7171 0 : return emitAssignment(target, JSOP_NOP, nullptr); // ... ITERVAL
7172 :
7173 : // Otherwise, per-loop initialization is (possibly) declaration
7174 : // initialization. If the declaration is a lexical declaration, it must be
7175 : // initialized. If the declaration is a variable declaration, an
7176 : // assignment to that name (which does *not* necessarily assign to the
7177 : // variable!) must be generated.
7178 :
7179 372 : if (!updateSourceCoordNotes(target->pn_pos.begin))
7180 0 : return false;
7181 :
7182 372 : MOZ_ASSERT(target->isForLoopDeclaration());
7183 372 : target = parser.singleBindingFromDeclaration(target);
7184 :
7185 372 : if (target->isKind(PNK_NAME)) {
7186 : auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&,
7187 320 : bool emittedBindOp)
7188 : {
7189 320 : if (emittedBindOp) {
7190 : // Per-iteration initialization in for-in/of loops computes the
7191 : // iteration value *before* initializing. Thus the
7192 : // initializing value may be buried under a bind-specific value
7193 : // on the stack. Swap it to the top of the stack.
7194 0 : MOZ_ASSERT(bce->stackDepth >= 2);
7195 0 : return bce->emit1(JSOP_SWAP);
7196 : }
7197 :
7198 : // In cases of emitting a frame slot or environment slot,
7199 : // nothing needs be done.
7200 320 : MOZ_ASSERT(bce->stackDepth >= 1);
7201 320 : return true;
7202 : };
7203 :
7204 : // The caller handles removing the iteration value from the stack.
7205 320 : return emitInitializeName(target, emitSwapScopeAndRhs);
7206 : }
7207 :
7208 52 : MOZ_ASSERT(!target->isKind(PNK_ASSIGN),
7209 : "for-in/of loop destructuring declarations can't have initializers");
7210 :
7211 52 : MOZ_ASSERT(target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT));
7212 52 : return emitDestructuringOps(target, DestructuringDeclaration);
7213 : }
7214 :
7215 : bool
7216 336 : BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitterScope)
7217 : {
7218 336 : MOZ_ASSERT(forOfLoop->isKind(PNK_FOR));
7219 336 : MOZ_ASSERT(forOfLoop->isArity(PN_BINARY));
7220 :
7221 336 : ParseNode* forOfHead = forOfLoop->pn_left;
7222 336 : MOZ_ASSERT(forOfHead->isKind(PNK_FOROF));
7223 336 : MOZ_ASSERT(forOfHead->isArity(PN_TERNARY));
7224 :
7225 336 : unsigned iflags = forOfLoop->pn_iflags;
7226 336 : IteratorKind iterKind = (iflags & JSITER_FORAWAITOF)
7227 336 : ? IteratorKind::Async
7228 336 : : IteratorKind::Sync;
7229 336 : MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox());
7230 336 : MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox()->isAsync());
7231 :
7232 336 : ParseNode* forHeadExpr = forOfHead->pn_kid3;
7233 :
7234 : // Certain builtins (e.g. Array.from) are implemented in self-hosting
7235 : // as for-of loops.
7236 336 : bool allowSelfHostedIter = false;
7237 687 : if (emitterMode == BytecodeEmitter::SelfHosting &&
7238 351 : forHeadExpr->isKind(PNK_CALL) &&
7239 15 : forHeadExpr->pn_head->name() == cx->names().allowContentIter)
7240 : {
7241 15 : allowSelfHostedIter = true;
7242 : }
7243 :
7244 : // Evaluate the expression being iterated. The forHeadExpr should use a
7245 : // distinct TDZCheckCache to evaluate since (abstractly) it runs in its own
7246 : // LexicalEnvironment.
7247 336 : if (!emitTreeInBranch(forHeadExpr)) // ITERABLE
7248 0 : return false;
7249 336 : if (iterKind == IteratorKind::Async) {
7250 0 : if (!emitAsyncIterator()) // ITER
7251 0 : return false;
7252 : } else {
7253 336 : if (!emitIterator()) // ITER
7254 0 : return false;
7255 : }
7256 :
7257 336 : int32_t iterDepth = stackDepth;
7258 :
7259 : // For-of loops have both the iterator and the result.value on the stack.
7260 : // Push an undefined to balance the stack.
7261 336 : if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
7262 0 : return false;
7263 :
7264 672 : ForOfLoopControl loopInfo(this, iterDepth, allowSelfHostedIter, iterKind);
7265 :
7266 : // Annotate so IonMonkey can find the loop-closing jump.
7267 : unsigned noteIndex;
7268 336 : if (!newSrcNote(SRC_FOR_OF, ¬eIndex))
7269 0 : return false;
7270 :
7271 336 : JumpList initialJump;
7272 336 : if (!emitJump(JSOP_GOTO, &initialJump)) // ITER UNDEF
7273 0 : return false;
7274 :
7275 336 : JumpTarget top{ -1 };
7276 336 : if (!emitLoopHead(nullptr, &top)) // ITER UNDEF
7277 0 : return false;
7278 :
7279 : // If the loop had an escaping lexical declaration, replace the current
7280 : // environment with an dead zoned one to implement TDZ semantics.
7281 336 : if (headLexicalEmitterScope) {
7282 : // The environment chain only includes an environment for the for-of
7283 : // loop head *if* a scope binding is captured, thereby requiring
7284 : // recreation each iteration. If a lexical scope exists for the head,
7285 : // it must be the innermost one. If that scope has closed-over
7286 : // bindings inducing an environment, recreate the current environment.
7287 640 : DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
7288 320 : MOZ_ASSERT(forOfTarget->isKind(PNK_LET) || forOfTarget->isKind(PNK_CONST));
7289 320 : MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
7290 320 : MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
7291 :
7292 320 : if (headLexicalEmitterScope->hasEnvironment()) {
7293 50 : if (!emit1(JSOP_RECREATELEXICALENV)) // ITER UNDEF
7294 0 : return false;
7295 : }
7296 :
7297 : // For uncaptured bindings, put them back in TDZ.
7298 320 : if (!headLexicalEmitterScope->deadZoneFrameSlots(this))
7299 0 : return false;
7300 : }
7301 :
7302 336 : JumpList beq;
7303 336 : JumpTarget breakTarget{ -1 };
7304 : {
7305 : #ifdef DEBUG
7306 336 : auto loopDepth = this->stackDepth;
7307 : #endif
7308 :
7309 : // Make sure this code is attributed to the "for".
7310 336 : if (!updateSourceCoordNotes(forOfHead->pn_pos.begin))
7311 0 : return false;
7312 :
7313 336 : if (!emit1(JSOP_POP)) // ITER
7314 0 : return false;
7315 336 : if (!emit1(JSOP_DUP)) // ITER ITER
7316 0 : return false;
7317 :
7318 336 : if (!emitIteratorNext(forOfHead, iterKind, allowSelfHostedIter))
7319 0 : return false; // ITER RESULT
7320 :
7321 336 : if (!emit1(JSOP_DUP)) // ITER RESULT RESULT
7322 0 : return false;
7323 336 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE
7324 0 : return false;
7325 :
7326 672 : IfThenElseEmitter ifDone(this);
7327 :
7328 336 : if (!ifDone.emitIf()) // ITER RESULT
7329 0 : return false;
7330 :
7331 : // Remove RESULT from the stack to release it.
7332 336 : if (!emit1(JSOP_POP)) // ITER
7333 0 : return false;
7334 336 : if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
7335 0 : return false;
7336 :
7337 : // If the iteration is done, leave loop here, instead of the branch at
7338 : // the end of the loop.
7339 336 : if (!loopInfo.emitSpecialBreakForDone(this)) // ITER UNDEF
7340 0 : return false;
7341 :
7342 336 : if (!ifDone.emitEnd()) // ITER RESULT
7343 0 : return false;
7344 :
7345 : // Emit code to assign result.value to the iteration variable.
7346 : //
7347 : // Note that ES 13.7.5.13, step 5.c says getting result.value does not
7348 : // call IteratorClose, so start JSTRY_ITERCLOSE after the GETPROP.
7349 336 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER VALUE
7350 0 : return false;
7351 :
7352 336 : if (!loopInfo.emitBeginCodeNeedingIteratorClose(this))
7353 0 : return false;
7354 :
7355 336 : if (!emitInitializeForInOrOfTarget(forOfHead)) // ITER VALUE
7356 0 : return false;
7357 :
7358 336 : MOZ_ASSERT(stackDepth == loopDepth,
7359 : "the stack must be balanced around the initializing "
7360 : "operation");
7361 :
7362 : // Remove VALUE from the stack to release it.
7363 336 : if (!emit1(JSOP_POP)) // ITER
7364 0 : return false;
7365 336 : if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
7366 0 : return false;
7367 :
7368 : // Perform the loop body.
7369 336 : ParseNode* forBody = forOfLoop->pn_right;
7370 336 : if (!emitTree(forBody)) // ITER UNDEF
7371 0 : return false;
7372 :
7373 336 : MOZ_ASSERT(stackDepth == loopDepth,
7374 : "the stack must be balanced around the for-of body");
7375 :
7376 336 : if (!loopInfo.emitEndCodeNeedingIteratorClose(this))
7377 0 : return false;
7378 :
7379 : // Set offset for continues.
7380 336 : loopInfo.continueTarget = { offset() };
7381 :
7382 336 : if (!emitLoopEntry(forHeadExpr, initialJump)) // ITER UNDEF
7383 0 : return false;
7384 :
7385 336 : if (!emit1(JSOP_FALSE)) // ITER UNDEF FALSE
7386 0 : return false;
7387 336 : if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
7388 0 : return false; // ITER UNDEF
7389 :
7390 336 : MOZ_ASSERT(this->stackDepth == loopDepth);
7391 : }
7392 :
7393 : // Let Ion know where the closing jump of this loop is.
7394 336 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
7395 0 : return false;
7396 :
7397 336 : if (!loopInfo.patchBreaksAndContinues(this))
7398 0 : return false;
7399 :
7400 336 : if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
7401 0 : return false;
7402 :
7403 336 : return emitPopN(2); //
7404 : }
7405 :
7406 : bool
7407 36 : BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitterScope)
7408 : {
7409 36 : MOZ_ASSERT(forInLoop->isKind(PNK_FOR));
7410 36 : MOZ_ASSERT(forInLoop->isArity(PN_BINARY));
7411 36 : MOZ_ASSERT(forInLoop->isOp(JSOP_ITER));
7412 :
7413 36 : ParseNode* forInHead = forInLoop->pn_left;
7414 36 : MOZ_ASSERT(forInHead->isKind(PNK_FORIN));
7415 36 : MOZ_ASSERT(forInHead->isArity(PN_TERNARY));
7416 :
7417 : // Annex B: Evaluate the var-initializer expression if present.
7418 : // |for (var i = initializer in expr) { ... }|
7419 36 : ParseNode* forInTarget = forInHead->pn_kid1;
7420 36 : if (parser.isDeclarationList(forInTarget)) {
7421 36 : ParseNode* decl = parser.singleBindingFromDeclaration(forInTarget);
7422 36 : if (decl->isKind(PNK_NAME)) {
7423 36 : if (ParseNode* initializer = decl->expr()) {
7424 0 : MOZ_ASSERT(forInTarget->isKind(PNK_VAR),
7425 : "for-in initializers are only permitted for |var| declarations");
7426 :
7427 0 : if (!updateSourceCoordNotes(decl->pn_pos.begin))
7428 0 : return false;
7429 :
7430 0 : auto emitRhs = [decl, initializer](BytecodeEmitter* bce, const NameLocation&, bool) {
7431 : return bce->emitInitializer(initializer, decl);
7432 0 : };
7433 :
7434 0 : if (!emitInitializeName(decl, emitRhs))
7435 0 : return false;
7436 :
7437 : // Pop the initializer.
7438 0 : if (!emit1(JSOP_POP))
7439 0 : return false;
7440 : }
7441 : }
7442 : }
7443 :
7444 : // Evaluate the expression being iterated.
7445 36 : ParseNode* expr = forInHead->pn_kid3;
7446 36 : if (!emitTreeInBranch(expr)) // EXPR
7447 0 : return false;
7448 :
7449 : // Convert the value to the appropriate sort of iterator object for the
7450 : // loop variant (for-in, for-each-in, or destructuring for-in).
7451 36 : unsigned iflags = forInLoop->pn_iflags;
7452 36 : MOZ_ASSERT(0 == (iflags & ~(JSITER_FOREACH | JSITER_ENUMERATE)));
7453 36 : if (!emit2(JSOP_ITER, AssertedCast<uint8_t>(iflags))) // ITER
7454 0 : return false;
7455 :
7456 : // For-in loops have both the iterator and the value on the stack. Push
7457 : // undefined to balance the stack.
7458 36 : if (!emit1(JSOP_UNDEFINED)) // ITER ITERVAL
7459 0 : return false;
7460 :
7461 72 : LoopControl loopInfo(this, StatementKind::ForInLoop);
7462 :
7463 : /* Annotate so IonMonkey can find the loop-closing jump. */
7464 : unsigned noteIndex;
7465 36 : if (!newSrcNote(SRC_FOR_IN, ¬eIndex))
7466 0 : return false;
7467 :
7468 : // Jump down to the loop condition to minimize overhead (assuming at least
7469 : // one iteration, just like the other loop forms).
7470 36 : JumpList initialJump;
7471 36 : if (!emitJump(JSOP_GOTO, &initialJump)) // ITER ITERVAL
7472 0 : return false;
7473 :
7474 36 : JumpTarget top{ -1 };
7475 36 : if (!emitLoopHead(nullptr, &top)) // ITER ITERVAL
7476 0 : return false;
7477 :
7478 : // If the loop had an escaping lexical declaration, replace the current
7479 : // environment with an dead zoned one to implement TDZ semantics.
7480 36 : if (headLexicalEmitterScope) {
7481 : // The environment chain only includes an environment for the for-in
7482 : // loop head *if* a scope binding is captured, thereby requiring
7483 : // recreation each iteration. If a lexical scope exists for the head,
7484 : // it must be the innermost one. If that scope has closed-over
7485 : // bindings inducing an environment, recreate the current environment.
7486 31 : MOZ_ASSERT(forInTarget->isKind(PNK_LET) || forInTarget->isKind(PNK_CONST));
7487 31 : MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
7488 31 : MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
7489 :
7490 31 : if (headLexicalEmitterScope->hasEnvironment()) {
7491 3 : if (!emit1(JSOP_RECREATELEXICALENV)) // ITER ITERVAL
7492 0 : return false;
7493 : }
7494 :
7495 : // For uncaptured bindings, put them back in TDZ.
7496 31 : if (!headLexicalEmitterScope->deadZoneFrameSlots(this))
7497 0 : return false;
7498 : }
7499 :
7500 : {
7501 : #ifdef DEBUG
7502 36 : auto loopDepth = this->stackDepth;
7503 : #endif
7504 36 : MOZ_ASSERT(loopDepth >= 2);
7505 :
7506 36 : if (!emitInitializeForInOrOfTarget(forInHead)) // ITER ITERVAL
7507 0 : return false;
7508 :
7509 36 : MOZ_ASSERT(this->stackDepth == loopDepth,
7510 : "iterator and iterval must be left on the stack");
7511 : }
7512 :
7513 : // Perform the loop body.
7514 36 : ParseNode* forBody = forInLoop->pn_right;
7515 36 : if (!emitTree(forBody)) // ITER ITERVAL
7516 0 : return false;
7517 :
7518 : // Set offset for continues.
7519 36 : loopInfo.continueTarget = { offset() };
7520 :
7521 : // Make sure this code is attributed to the "for".
7522 36 : if (!updateSourceCoordNotes(forInHead->pn_pos.begin))
7523 0 : return false;
7524 :
7525 36 : if (!emitLoopEntry(nullptr, initialJump)) // ITER ITERVAL
7526 0 : return false;
7527 36 : if (!emit1(JSOP_POP)) // ITER
7528 0 : return false;
7529 36 : if (!emit1(JSOP_MOREITER)) // ITER NEXTITERVAL?
7530 0 : return false;
7531 36 : if (!emit1(JSOP_ISNOITER)) // ITER NEXTITERVAL? ISNOITER
7532 0 : return false;
7533 :
7534 36 : JumpList beq;
7535 36 : JumpTarget breakTarget{ -1 };
7536 36 : if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
7537 0 : return false; // ITER NEXTITERVAL
7538 :
7539 : // Set the srcnote offset so we can find the closing jump.
7540 36 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - initialJump.offset))
7541 0 : return false;
7542 :
7543 36 : if (!loopInfo.patchBreaksAndContinues(this))
7544 0 : return false;
7545 :
7546 : // Pop the enumeration value.
7547 36 : if (!emit1(JSOP_POP)) // ITER
7548 0 : return false;
7549 :
7550 36 : if (!tryNoteList.append(JSTRY_FOR_IN, this->stackDepth, top.offset, offset()))
7551 0 : return false;
7552 :
7553 36 : return emit1(JSOP_ENDITER); //
7554 : }
7555 :
7556 : /* C-style `for (init; cond; update) ...` loop. */
7557 : bool
7558 441 : BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope)
7559 : {
7560 882 : LoopControl loopInfo(this, StatementKind::ForLoop);
7561 :
7562 441 : ParseNode* forHead = pn->pn_left;
7563 441 : ParseNode* forBody = pn->pn_right;
7564 :
7565 : // If the head of this for-loop declared any lexical variables, the parser
7566 : // wrapped this PNK_FOR node in a PNK_LEXICALSCOPE representing the
7567 : // implicit scope of those variables. By the time we get here, we have
7568 : // already entered that scope. So far, so good.
7569 : //
7570 : // ### Scope freshening
7571 : //
7572 : // Each iteration of a `for (let V...)` loop creates a fresh loop variable
7573 : // binding for V, even if the loop is a C-style `for(;;)` loop:
7574 : //
7575 : // var funcs = [];
7576 : // for (let i = 0; i < 2; i++)
7577 : // funcs.push(function() { return i; });
7578 : // assertEq(funcs[0](), 0); // the two closures capture...
7579 : // assertEq(funcs[1](), 1); // ...two different `i` bindings
7580 : //
7581 : // This is implemented by "freshening" the implicit block -- changing the
7582 : // scope chain to a fresh clone of the instantaneous block object -- each
7583 : // iteration, just before evaluating the "update" in for(;;) loops.
7584 : //
7585 : // No freshening occurs in `for (const ...;;)` as there's no point: you
7586 : // can't reassign consts. This is observable through the Debugger API. (The
7587 : // ES6 spec also skips cloning the environment in this case.)
7588 441 : bool forLoopRequiresFreshening = false;
7589 441 : if (ParseNode* init = forHead->pn_kid1) {
7590 : // Emit the `init` clause, whether it's an expression or a variable
7591 : // declaration. (The loop variables were hoisted into an enclosing
7592 : // scope, but we still need to emit code for the initializers.)
7593 394 : if (!updateSourceCoordNotes(init->pn_pos.begin))
7594 0 : return false;
7595 394 : if (init->isForLoopDeclaration()) {
7596 370 : if (!emitTree(init))
7597 0 : return false;
7598 : } else {
7599 : // 'init' is an expression, not a declaration. emitTree left its
7600 : // value on the stack.
7601 24 : if (!emitTree(init, ValueUsage::IgnoreValue))
7602 0 : return false;
7603 24 : if (!emit1(JSOP_POP))
7604 0 : return false;
7605 : }
7606 :
7607 : // ES 13.7.4.8 step 2. The initial freshening.
7608 : //
7609 : // If an initializer let-declaration may be captured during loop iteration,
7610 : // the current scope has an environment. If so, freshen the current
7611 : // environment to expose distinct bindings for each loop iteration.
7612 394 : forLoopRequiresFreshening = init->isKind(PNK_LET) && headLexicalEmitterScope;
7613 394 : if (forLoopRequiresFreshening) {
7614 : // The environment chain only includes an environment for the for(;;)
7615 : // loop head's let-declaration *if* a scope binding is captured, thus
7616 : // requiring a fresh environment each iteration. If a lexical scope
7617 : // exists for the head, it must be the innermost one. If that scope
7618 : // has closed-over bindings inducing an environment, recreate the
7619 : // current environment.
7620 140 : MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
7621 140 : MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
7622 :
7623 140 : if (headLexicalEmitterScope->hasEnvironment()) {
7624 0 : if (!emit1(JSOP_FRESHENLEXICALENV))
7625 0 : return false;
7626 : }
7627 : }
7628 : }
7629 :
7630 : /*
7631 : * NB: the SRC_FOR note has offsetBias 1 (JSOP_NOP_LENGTH).
7632 : * Use tmp to hold the biased srcnote "top" offset, which differs
7633 : * from the top local variable by the length of the JSOP_GOTO
7634 : * emitted in between tmp and top if this loop has a condition.
7635 : */
7636 : unsigned noteIndex;
7637 441 : if (!newSrcNote(SRC_FOR, ¬eIndex))
7638 0 : return false;
7639 441 : if (!emit1(JSOP_NOP))
7640 0 : return false;
7641 441 : ptrdiff_t tmp = offset();
7642 :
7643 441 : JumpList jmp;
7644 441 : if (forHead->pn_kid2) {
7645 : /* Goto the loop condition, which branches back to iterate. */
7646 432 : if (!emitJump(JSOP_GOTO, &jmp))
7647 0 : return false;
7648 : }
7649 :
7650 : /* Emit code for the loop body. */
7651 441 : JumpTarget top{ -1 };
7652 441 : if (!emitLoopHead(forBody, &top))
7653 0 : return false;
7654 441 : if (jmp.offset == -1 && !emitLoopEntry(forBody, jmp))
7655 0 : return false;
7656 :
7657 441 : if (!emitTreeInBranch(forBody))
7658 0 : return false;
7659 :
7660 : // Set loop and enclosing "update" offsets, for continue. Note that we
7661 : // continue to immediately *before* the block-freshening: continuing must
7662 : // refresh the block.
7663 441 : if (!emitJumpTarget(&loopInfo.continueTarget))
7664 0 : return false;
7665 :
7666 : // ES 13.7.4.8 step 3.e. The per-iteration freshening.
7667 441 : if (forLoopRequiresFreshening) {
7668 140 : MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
7669 140 : MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
7670 :
7671 140 : if (headLexicalEmitterScope->hasEnvironment()) {
7672 0 : if (!emit1(JSOP_FRESHENLEXICALENV))
7673 0 : return false;
7674 : }
7675 : }
7676 :
7677 : // Check for update code to do before the condition (if any).
7678 : // The update code may not be executed at all; it needs its own TDZ cache.
7679 441 : if (ParseNode* update = forHead->pn_kid3) {
7680 864 : TDZCheckCache tdzCache(this);
7681 :
7682 432 : if (!updateSourceCoordNotes(update->pn_pos.begin))
7683 0 : return false;
7684 432 : if (!emitTree(update, ValueUsage::IgnoreValue))
7685 0 : return false;
7686 432 : if (!emit1(JSOP_POP))
7687 0 : return false;
7688 :
7689 : /* Restore the absolute line number for source note readers. */
7690 432 : uint32_t lineNum = parser.tokenStream().srcCoords.lineNum(pn->pn_pos.end);
7691 432 : if (currentLine() != lineNum) {
7692 431 : if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum)))
7693 0 : return false;
7694 431 : current->currentLine = lineNum;
7695 431 : current->lastColumn = 0;
7696 : }
7697 : }
7698 :
7699 441 : ptrdiff_t tmp3 = offset();
7700 :
7701 441 : if (forHead->pn_kid2) {
7702 : /* Fix up the goto from top to target the loop condition. */
7703 432 : MOZ_ASSERT(jmp.offset >= 0);
7704 432 : if (!emitLoopEntry(forHead->pn_kid2, jmp))
7705 0 : return false;
7706 :
7707 432 : if (!emitTree(forHead->pn_kid2))
7708 0 : return false;
7709 9 : } else if (!forHead->pn_kid3) {
7710 : // If there is no condition clause and no update clause, mark
7711 : // the loop-ending "goto" with the location of the "for".
7712 : // This ensures that the debugger will stop on each loop
7713 : // iteration.
7714 9 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
7715 0 : return false;
7716 : }
7717 :
7718 : /* Set the first note offset so we can find the loop condition. */
7719 441 : if (!setSrcNoteOffset(noteIndex, 0, tmp3 - tmp))
7720 0 : return false;
7721 441 : if (!setSrcNoteOffset(noteIndex, 1, loopInfo.continueTarget.offset - tmp))
7722 0 : return false;
7723 :
7724 : /* If no loop condition, just emit a loop-closing jump. */
7725 441 : JumpList beq;
7726 441 : JumpTarget breakTarget{ -1 };
7727 441 : if (!emitBackwardJump(forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO, top, &beq, &breakTarget))
7728 0 : return false;
7729 :
7730 : /* The third note offset helps us find the loop-closing jump. */
7731 441 : if (!setSrcNoteOffset(noteIndex, 2, beq.offset - tmp))
7732 0 : return false;
7733 :
7734 441 : if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
7735 0 : return false;
7736 :
7737 441 : if (!loopInfo.patchBreaksAndContinues(this))
7738 0 : return false;
7739 :
7740 441 : return true;
7741 : }
7742 :
7743 : bool
7744 813 : BytecodeEmitter::emitFor(ParseNode* pn, EmitterScope* headLexicalEmitterScope)
7745 : {
7746 813 : MOZ_ASSERT(pn->isKind(PNK_FOR));
7747 :
7748 813 : if (pn->pn_left->isKind(PNK_FORHEAD))
7749 441 : return emitCStyleFor(pn, headLexicalEmitterScope);
7750 :
7751 372 : if (!updateLineNumberNotes(pn->pn_pos.begin))
7752 0 : return false;
7753 :
7754 372 : if (pn->pn_left->isKind(PNK_FORIN))
7755 36 : return emitForIn(pn, headLexicalEmitterScope);
7756 :
7757 336 : MOZ_ASSERT(pn->pn_left->isKind(PNK_FOROF));
7758 336 : return emitForOf(pn, headLexicalEmitterScope);
7759 : }
7760 :
7761 : bool
7762 0 : BytecodeEmitter::emitComprehensionForInOrOfVariables(ParseNode* pn, bool* lexicalScope)
7763 : {
7764 : // ES6 specifies that lexical for-loop variables get a fresh binding each
7765 : // iteration, and that evaluation of the expression looped over occurs with
7766 : // these variables dead zoned. But these rules only apply to *standard*
7767 : // for-in/of loops, and we haven't extended these requirements to
7768 : // comprehension syntax.
7769 :
7770 0 : *lexicalScope = pn->isKind(PNK_LEXICALSCOPE);
7771 0 : if (*lexicalScope) {
7772 : // This is initially-ES7-tracked syntax, now with considerably murkier
7773 : // outlook. The scope work is done by the caller by instantiating an
7774 : // EmitterScope. There's nothing to do here.
7775 : } else {
7776 : // This is legacy comprehension syntax. We'll have PNK_LET here, using
7777 : // a lexical scope provided by/for the entire comprehension. Name
7778 : // analysis assumes declarations initialize lets, but as we're handling
7779 : // this declaration manually, we must also initialize manually to avoid
7780 : // triggering dead zone checks.
7781 0 : MOZ_ASSERT(pn->isKind(PNK_LET));
7782 0 : MOZ_ASSERT(pn->pn_count == 1);
7783 :
7784 0 : if (!emitDeclarationList(pn))
7785 0 : return false;
7786 : }
7787 :
7788 0 : return true;
7789 : }
7790 :
7791 : bool
7792 0 : BytecodeEmitter::emitComprehensionForOf(ParseNode* pn)
7793 : {
7794 0 : MOZ_ASSERT(pn->isKind(PNK_COMPREHENSIONFOR));
7795 :
7796 0 : ParseNode* forHead = pn->pn_left;
7797 0 : MOZ_ASSERT(forHead->isKind(PNK_FOROF));
7798 :
7799 0 : ParseNode* forHeadExpr = forHead->pn_kid3;
7800 0 : ParseNode* forBody = pn->pn_right;
7801 :
7802 0 : ParseNode* loopDecl = forHead->pn_kid1;
7803 0 : bool lexicalScope = false;
7804 0 : if (!emitComprehensionForInOrOfVariables(loopDecl, &lexicalScope))
7805 0 : return false;
7806 :
7807 : // For-of loops run with two values on the stack: the iterator and the
7808 : // current result object.
7809 :
7810 : // Evaluate the expression to the right of 'of'.
7811 0 : if (!emitTree(forHeadExpr)) // EXPR
7812 0 : return false;
7813 0 : if (!emitIterator()) // ITER
7814 0 : return false;
7815 :
7816 : // Push a dummy result so that we properly enter iteration midstream.
7817 0 : if (!emit1(JSOP_UNDEFINED)) // ITER VALUE
7818 0 : return false;
7819 :
7820 : // Enter the block before the loop body, after evaluating the obj.
7821 : // Initialize let bindings with undefined when entering, as the name
7822 : // assigned to is a plain assignment.
7823 0 : TDZCheckCache tdzCache(this);
7824 0 : Maybe<EmitterScope> emitterScope;
7825 : ParseNode* loopVariableName;
7826 0 : if (lexicalScope) {
7827 0 : loopVariableName = parser.singleBindingFromDeclaration(loopDecl->pn_expr);
7828 0 : emitterScope.emplace(this);
7829 0 : if (!emitterScope->enterComprehensionFor(this, loopDecl->scopeBindings()))
7830 0 : return false;
7831 : } else {
7832 0 : loopVariableName = parser.singleBindingFromDeclaration(loopDecl);
7833 : }
7834 :
7835 0 : LoopControl loopInfo(this, StatementKind::ForOfLoop);
7836 :
7837 : // Jump down to the loop condition to minimize overhead assuming at least
7838 : // one iteration, as the other loop forms do. Annotate so IonMonkey can
7839 : // find the loop-closing jump.
7840 : unsigned noteIndex;
7841 0 : if (!newSrcNote(SRC_FOR_OF, ¬eIndex))
7842 0 : return false;
7843 0 : JumpList jmp;
7844 0 : if (!emitJump(JSOP_GOTO, &jmp))
7845 0 : return false;
7846 :
7847 0 : JumpTarget top{ -1 };
7848 0 : if (!emitLoopHead(nullptr, &top))
7849 0 : return false;
7850 :
7851 : #ifdef DEBUG
7852 0 : int loopDepth = this->stackDepth;
7853 : #endif
7854 :
7855 0 : if (!emit1(JSOP_POP)) // ITER
7856 0 : return false;
7857 0 : if (!emit1(JSOP_DUP)) // ITER ITER
7858 0 : return false;
7859 0 : if (!emitIteratorNext(forHead)) // ITER RESULT
7860 0 : return false;
7861 0 : if (!emit1(JSOP_DUP)) // ITER RESULT RESULT
7862 0 : return false;
7863 0 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE
7864 0 : return false;
7865 :
7866 0 : IfThenElseEmitter ifDone(this);
7867 :
7868 0 : if (!ifDone.emitIf()) // ITER RESULT
7869 0 : return false;
7870 :
7871 : // Remove RESULT from the stack to release it.
7872 0 : if (!emit1(JSOP_POP)) // ITER
7873 0 : return false;
7874 0 : if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
7875 0 : return false;
7876 :
7877 : // If the iteration is done, leave loop here, instead of the branch at
7878 : // the end of the loop.
7879 0 : if (!loopInfo.emitSpecialBreakForDone(this)) // ITER UNDEF
7880 0 : return false;
7881 :
7882 0 : if (!ifDone.emitEnd()) // ITER RESULT
7883 0 : return false;
7884 :
7885 : // Emit code to assign result.value to the iteration variable.
7886 0 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER VALUE
7887 0 : return false;
7888 :
7889 : // Notice: Comprehension for-of doesn't perform IteratorClose, since it's
7890 : // not in the spec.
7891 0 : if (!emitAssignment(loopVariableName, JSOP_NOP, nullptr)) // ITER VALUE
7892 0 : return false;
7893 :
7894 : // Remove VALUE from the stack to release it.
7895 0 : if (!emit1(JSOP_POP)) // ITER
7896 0 : return false;
7897 0 : if (!emit1(JSOP_UNDEFINED)) // ITER UNDEF
7898 0 : return false;
7899 :
7900 : // The stack should be balanced around the assignment opcode sequence.
7901 0 : MOZ_ASSERT(this->stackDepth == loopDepth);
7902 :
7903 : // Emit code for the loop body.
7904 0 : if (!emitTree(forBody)) // ITER UNDEF
7905 0 : return false;
7906 :
7907 : // The stack should be balanced around the assignment opcode sequence.
7908 0 : MOZ_ASSERT(this->stackDepth == loopDepth);
7909 :
7910 : // Set offset for continues.
7911 0 : loopInfo.continueTarget = { offset() };
7912 :
7913 0 : if (!emitLoopEntry(forHeadExpr, jmp))
7914 0 : return false;
7915 :
7916 0 : if (!emit1(JSOP_FALSE)) // ITER VALUE FALSE
7917 0 : return false;
7918 :
7919 0 : JumpList beq;
7920 0 : JumpTarget breakTarget{ -1 };
7921 0 : if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
7922 0 : return false; // ITER VALUE
7923 :
7924 0 : MOZ_ASSERT(this->stackDepth == loopDepth);
7925 :
7926 : // Let Ion know where the closing jump of this loop is.
7927 0 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - jmp.offset))
7928 0 : return false;
7929 :
7930 0 : if (!loopInfo.patchBreaksAndContinues(this))
7931 0 : return false;
7932 :
7933 0 : if (!tryNoteList.append(JSTRY_FOR_OF, stackDepth, top.offset, breakTarget.offset))
7934 0 : return false;
7935 :
7936 0 : if (emitterScope) {
7937 0 : if (!emitterScope->leave(this))
7938 0 : return false;
7939 0 : emitterScope.reset();
7940 : }
7941 :
7942 : // Pop the result and the iter.
7943 0 : return emitPopN(2); //
7944 : }
7945 :
7946 : bool
7947 0 : BytecodeEmitter::emitComprehensionForIn(ParseNode* pn)
7948 : {
7949 0 : MOZ_ASSERT(pn->isKind(PNK_COMPREHENSIONFOR));
7950 :
7951 0 : ParseNode* forHead = pn->pn_left;
7952 0 : MOZ_ASSERT(forHead->isKind(PNK_FORIN));
7953 :
7954 0 : ParseNode* forBody = pn->pn_right;
7955 :
7956 0 : ParseNode* loopDecl = forHead->pn_kid1;
7957 0 : bool lexicalScope = false;
7958 0 : if (loopDecl && !emitComprehensionForInOrOfVariables(loopDecl, &lexicalScope))
7959 0 : return false;
7960 :
7961 : // Evaluate the expression to the right of 'in'.
7962 0 : if (!emitTree(forHead->pn_kid3))
7963 0 : return false;
7964 :
7965 : /*
7966 : * Emit a bytecode to convert top of stack value to the iterator
7967 : * object depending on the loop variant (for-in, for-each-in, or
7968 : * destructuring for-in).
7969 : */
7970 0 : MOZ_ASSERT(pn->isOp(JSOP_ITER));
7971 0 : if (!emit2(JSOP_ITER, (uint8_t) pn->pn_iflags))
7972 0 : return false;
7973 :
7974 : // For-in loops have both the iterator and the value on the stack. Push
7975 : // undefined to balance the stack.
7976 0 : if (!emit1(JSOP_UNDEFINED))
7977 0 : return false;
7978 :
7979 : // Enter the block before the loop body, after evaluating the obj.
7980 : // Initialize let bindings with undefined when entering, as the name
7981 : // assigned to is a plain assignment.
7982 0 : TDZCheckCache tdzCache(this);
7983 0 : Maybe<EmitterScope> emitterScope;
7984 0 : if (lexicalScope) {
7985 0 : emitterScope.emplace(this);
7986 0 : if (!emitterScope->enterComprehensionFor(this, loopDecl->scopeBindings()))
7987 0 : return false;
7988 : }
7989 :
7990 0 : LoopControl loopInfo(this, StatementKind::ForInLoop);
7991 :
7992 : /* Annotate so IonMonkey can find the loop-closing jump. */
7993 : unsigned noteIndex;
7994 0 : if (!newSrcNote(SRC_FOR_IN, ¬eIndex))
7995 0 : return false;
7996 :
7997 : /*
7998 : * Jump down to the loop condition to minimize overhead assuming at
7999 : * least one iteration, as the other loop forms do.
8000 : */
8001 0 : JumpList jmp;
8002 0 : if (!emitJump(JSOP_GOTO, &jmp))
8003 0 : return false;
8004 :
8005 0 : JumpTarget top{ -1 };
8006 0 : if (!emitLoopHead(nullptr, &top))
8007 0 : return false;
8008 :
8009 : #ifdef DEBUG
8010 0 : int loopDepth = this->stackDepth;
8011 : #endif
8012 :
8013 : // Emit code to assign the enumeration value to the left hand side, but
8014 : // also leave it on the stack.
8015 0 : if (!emitAssignment(forHead->pn_kid2, JSOP_NOP, nullptr))
8016 0 : return false;
8017 :
8018 : /* The stack should be balanced around the assignment opcode sequence. */
8019 0 : MOZ_ASSERT(this->stackDepth == loopDepth);
8020 :
8021 : /* Emit code for the loop body. */
8022 0 : if (!emitTree(forBody))
8023 0 : return false;
8024 :
8025 : // Set offset for continues.
8026 0 : loopInfo.continueTarget = { offset() };
8027 :
8028 0 : if (!emitLoopEntry(nullptr, jmp))
8029 0 : return false;
8030 0 : if (!emit1(JSOP_POP))
8031 0 : return false;
8032 0 : if (!emit1(JSOP_MOREITER))
8033 0 : return false;
8034 0 : if (!emit1(JSOP_ISNOITER))
8035 0 : return false;
8036 0 : JumpList beq;
8037 0 : JumpTarget breakTarget{ -1 };
8038 0 : if (!emitBackwardJump(JSOP_IFEQ, top, &beq, &breakTarget))
8039 0 : return false;
8040 :
8041 : /* Set the srcnote offset so we can find the closing jump. */
8042 0 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - jmp.offset))
8043 0 : return false;
8044 :
8045 0 : if (!loopInfo.patchBreaksAndContinues(this))
8046 0 : return false;
8047 :
8048 : // Pop the enumeration value.
8049 0 : if (!emit1(JSOP_POP))
8050 0 : return false;
8051 :
8052 0 : JumpTarget endIter{ offset() };
8053 0 : if (!tryNoteList.append(JSTRY_FOR_IN, this->stackDepth, top.offset, endIter.offset))
8054 0 : return false;
8055 0 : if (!emit1(JSOP_ENDITER))
8056 0 : return false;
8057 :
8058 0 : if (emitterScope) {
8059 0 : if (!emitterScope->leave(this))
8060 0 : return false;
8061 0 : emitterScope.reset();
8062 : }
8063 :
8064 0 : return true;
8065 : }
8066 :
8067 : bool
8068 0 : BytecodeEmitter::emitComprehensionFor(ParseNode* compFor)
8069 : {
8070 0 : MOZ_ASSERT(compFor->pn_left->isKind(PNK_FORIN) ||
8071 : compFor->pn_left->isKind(PNK_FOROF));
8072 :
8073 0 : if (!updateLineNumberNotes(compFor->pn_pos.begin))
8074 0 : return false;
8075 :
8076 0 : return compFor->pn_left->isKind(PNK_FORIN)
8077 0 : ? emitComprehensionForIn(compFor)
8078 0 : : emitComprehensionForOf(compFor);
8079 : }
8080 :
8081 : MOZ_NEVER_INLINE bool
8082 5861 : BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
8083 : {
8084 5861 : FunctionBox* funbox = pn->pn_funbox;
8085 11723 : RootedFunction fun(cx, funbox->function());
8086 11723 : RootedAtom name(cx, fun->explicitName());
8087 5861 : MOZ_ASSERT_IF(fun->isInterpretedLazy(), fun->lazyScript());
8088 :
8089 : /*
8090 : * Set the |wasEmitted| flag in the funbox once the function has been
8091 : * emitted. Function definitions that need hoisting to the top of the
8092 : * function will be seen by emitFunction in two places.
8093 : */
8094 5861 : if (funbox->wasEmitted) {
8095 : // Annex B block-scoped functions are hoisted like any other
8096 : // block-scoped function to the top of their scope. When their
8097 : // definitions are seen for the second time, we need to emit the
8098 : // assignment that assigns the function to the outer 'var' binding.
8099 68 : if (funbox->isAnnexB) {
8100 0 : auto emitRhs = [&name](BytecodeEmitter* bce, const NameLocation&, bool) {
8101 : // The RHS is the value of the lexically bound name in the
8102 : // innermost scope.
8103 0 : return bce->emitGetName(name);
8104 0 : };
8105 :
8106 : // Get the location of the 'var' binding in the body scope. The
8107 : // name must be found, else there is a bug in the Annex B handling
8108 : // in Parser.
8109 : //
8110 : // In sloppy eval contexts, this location is dynamic.
8111 0 : Maybe<NameLocation> lhsLoc = locationOfNameBoundInScope(name, varEmitterScope);
8112 :
8113 : // If there are parameter expressions, the var name could be a
8114 : // parameter.
8115 0 : if (!lhsLoc && sc->isFunctionBox() && sc->asFunctionBox()->hasExtraBodyVarScope())
8116 0 : lhsLoc = locationOfNameBoundInScope(name, varEmitterScope->enclosingInFrame());
8117 :
8118 0 : if (!lhsLoc) {
8119 0 : lhsLoc = Some(NameLocation::DynamicAnnexBVar());
8120 : } else {
8121 0 : MOZ_ASSERT(lhsLoc->bindingKind() == BindingKind::Var ||
8122 : lhsLoc->bindingKind() == BindingKind::FormalParameter ||
8123 : (lhsLoc->bindingKind() == BindingKind::Let &&
8124 : sc->asFunctionBox()->hasParameterExprs));
8125 : }
8126 :
8127 0 : if (!emitSetOrInitializeNameAtLocation(name, *lhsLoc, emitRhs, false))
8128 0 : return false;
8129 0 : if (!emit1(JSOP_POP))
8130 0 : return false;
8131 : }
8132 :
8133 68 : MOZ_ASSERT_IF(fun->hasScript(), fun->nonLazyScript());
8134 68 : MOZ_ASSERT(pn->functionIsHoisted());
8135 68 : return true;
8136 : }
8137 :
8138 5793 : funbox->wasEmitted = true;
8139 :
8140 : /*
8141 : * Mark as singletons any function which will only be executed once, or
8142 : * which is inner to a lambda we only expect to run once. In the latter
8143 : * case, if the lambda runs multiple times then CloneFunctionObject will
8144 : * make a deep clone of its contents.
8145 : */
8146 5793 : if (fun->isInterpreted()) {
8147 5793 : bool singleton = checkRunOnceContext();
8148 5793 : if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
8149 0 : return false;
8150 :
8151 5793 : SharedContext* outersc = sc;
8152 5793 : if (fun->isInterpretedLazy()) {
8153 : // We need to update the static scope chain regardless of whether
8154 : // the LazyScript has already been initialized, due to the case
8155 : // where we previously successfully compiled an inner function's
8156 : // lazy script but failed to compile the outer script after the
8157 : // fact. If we attempt to compile the outer script again, the
8158 : // static scope chain will be newly allocated and will mismatch
8159 : // the previously compiled LazyScript's.
8160 1811 : ScriptSourceObject* source = &script->sourceObject()->as<ScriptSourceObject>();
8161 1811 : fun->lazyScript()->setEnclosingScopeAndSource(innermostScope(), source);
8162 1811 : if (emittingRunOnceLambda)
8163 0 : fun->lazyScript()->setTreatAsRunOnce();
8164 : } else {
8165 3982 : MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript);
8166 :
8167 : // Inherit most things (principals, version, etc) from the
8168 : // parent. Use default values for the rest.
8169 7965 : Rooted<JSScript*> parent(cx, script);
8170 3982 : MOZ_ASSERT(parent->getVersion() == parser.options().version);
8171 3982 : MOZ_ASSERT(parent->mutedErrors() == parser.options().mutedErrors());
8172 3982 : const TransitiveCompileOptions& transitiveOptions = parser.options();
8173 7965 : CompileOptions options(cx, transitiveOptions);
8174 :
8175 7965 : Rooted<JSObject*> sourceObject(cx, script->sourceObject());
8176 7964 : Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
8177 : funbox->bufStart, funbox->bufEnd,
8178 : funbox->toStringStart,
8179 7965 : funbox->toStringEnd));
8180 3982 : if (!script)
8181 0 : return false;
8182 :
8183 : BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
8184 7965 : pn->pn_pos, emitterMode);
8185 3982 : if (!bce2.init())
8186 0 : return false;
8187 :
8188 : /* We measured the max scope depth when we parsed the function. */
8189 3982 : if (!bce2.emitFunctionScript(pn->pn_body))
8190 0 : return false;
8191 :
8192 3983 : if (funbox->isLikelyConstructorWrapper())
8193 0 : script->setLikelyConstructorWrapper();
8194 : }
8195 :
8196 5794 : if (outersc->isFunctionBox())
8197 1120 : outersc->asFunctionBox()->setHasInnerFunctions();
8198 : } else {
8199 0 : MOZ_ASSERT(IsAsmJSModule(fun));
8200 : }
8201 :
8202 : /* Make the function object a literal in the outer script's pool. */
8203 5794 : unsigned index = objectList.add(pn->pn_funbox);
8204 :
8205 : /* Non-hoisted functions simply emit their respective op. */
8206 5794 : if (!pn->functionIsHoisted()) {
8207 : /* JSOP_LAMBDA_ARROW is always preceded by a new.target */
8208 3975 : MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
8209 3975 : if (funbox->isAsync()) {
8210 108 : MOZ_ASSERT(!needsProto);
8211 108 : return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow(),
8212 216 : fun->isStarGenerator());
8213 : }
8214 :
8215 3867 : if (fun->isArrow()) {
8216 695 : if (sc->allowNewTarget()) {
8217 589 : if (!emit1(JSOP_NEWTARGET))
8218 0 : return false;
8219 : } else {
8220 106 : if (!emit1(JSOP_NULL))
8221 0 : return false;
8222 : }
8223 : }
8224 :
8225 3867 : if (needsProto) {
8226 15 : MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA);
8227 15 : pn->setOp(JSOP_FUNWITHPROTO);
8228 : }
8229 :
8230 3867 : if (pn->getOp() == JSOP_DEFFUN) {
8231 0 : if (!emitIndex32(JSOP_LAMBDA, index))
8232 0 : return false;
8233 0 : return emit1(JSOP_DEFFUN);
8234 : }
8235 :
8236 3867 : return emitIndex32(pn->getOp(), index);
8237 : }
8238 :
8239 1819 : MOZ_ASSERT(!needsProto);
8240 :
8241 : bool topLevelFunction;
8242 1819 : if (sc->isFunctionBox() || (sc->isEvalContext() && sc->strict())) {
8243 : // No nested functions inside other functions are top-level.
8244 68 : topLevelFunction = false;
8245 : } else {
8246 : // In sloppy eval scripts, top-level functions in are accessed
8247 : // dynamically. In global and module scripts, top-level functions are
8248 : // those bound in the var scope.
8249 1751 : NameLocation loc = lookupName(name);
8250 3502 : topLevelFunction = loc.kind() == NameLocation::Kind::Dynamic ||
8251 1751 : loc.bindingKind() == BindingKind::Var;
8252 : }
8253 :
8254 1819 : if (topLevelFunction) {
8255 1751 : if (sc->isModuleContext()) {
8256 : // For modules, we record the function and instantiate the binding
8257 : // during ModuleDeclarationInstantiation(), before the script is run.
8258 :
8259 0 : RootedModuleObject module(cx, sc->asModuleContext()->module());
8260 0 : if (!module->noteFunctionDeclaration(cx, name, fun))
8261 0 : return false;
8262 : } else {
8263 1751 : MOZ_ASSERT(sc->isGlobalContext() || sc->isEvalContext());
8264 1751 : MOZ_ASSERT(pn->getOp() == JSOP_NOP);
8265 1751 : switchToPrologue();
8266 1751 : if (funbox->isAsync()) {
8267 2 : if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow(),
8268 2 : fun->isStarGenerator()))
8269 : {
8270 0 : return false;
8271 : }
8272 : } else {
8273 1749 : if (!emitIndex32(JSOP_LAMBDA, index))
8274 0 : return false;
8275 : }
8276 1751 : if (!emit1(JSOP_DEFFUN))
8277 0 : return false;
8278 1751 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
8279 0 : return false;
8280 1751 : switchToMain();
8281 : }
8282 : } else {
8283 : // For functions nested within functions and blocks, make a lambda and
8284 : // initialize the binding name of the function in the current scope.
8285 :
8286 68 : bool isAsync = funbox->isAsync();
8287 68 : bool isStarGenerator = funbox->isStarGenerator();
8288 : auto emitLambda = [index, isAsync, isStarGenerator](BytecodeEmitter* bce,
8289 140 : const NameLocation&, bool) {
8290 68 : if (isAsync) {
8291 4 : return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
8292 4 : /* isArrow = */ false, isStarGenerator);
8293 : }
8294 64 : return bce->emitIndexOp(JSOP_LAMBDA, index);
8295 68 : };
8296 :
8297 68 : if (!emitInitializeName(name, emitLambda))
8298 0 : return false;
8299 68 : if (!emit1(JSOP_POP))
8300 0 : return false;
8301 : }
8302 :
8303 1819 : return true;
8304 : }
8305 :
8306 : bool
8307 114 : BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
8308 114 : if (isArrow) {
8309 26 : if (sc->allowNewTarget()) {
8310 25 : if (!emit1(JSOP_NEWTARGET))
8311 0 : return false;
8312 : } else {
8313 1 : if (!emit1(JSOP_NULL))
8314 0 : return false;
8315 : }
8316 26 : if (!emitIndex32(JSOP_LAMBDA_ARROW, index))
8317 0 : return false;
8318 : } else {
8319 88 : if (!emitIndex32(JSOP_LAMBDA, index))
8320 0 : return false;
8321 : }
8322 :
8323 114 : return true;
8324 : }
8325 :
8326 : bool
8327 114 : BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
8328 : bool isStarGenerator)
8329 : {
8330 : // needsHomeObject can be true for propertyList for extended class.
8331 : // In that case push both unwrapped and wrapped function, in order to
8332 : // initialize home object of unwrapped function, and set wrapped function
8333 : // as a property.
8334 : //
8335 : // lambda // unwrapped
8336 : // dup // unwrapped unwrapped
8337 : // toasync // unwrapped wrapped
8338 : //
8339 : // Emitted code is surrounded by the following code.
8340 : //
8341 : // // classObj classCtor classProto
8342 : // (emitted code) // classObj classCtor classProto unwrapped wrapped
8343 : // swap // classObj classCtor classProto wrapped unwrapped
8344 : // inithomeobject 1 // classObj classCtor classProto wrapped unwrapped
8345 : // // initialize the home object of unwrapped
8346 : // // with classProto here
8347 : // pop // classObj classCtor classProto wrapped
8348 : // inithiddenprop // classObj classCtor classProto wrapped
8349 : // // initialize the property of the classProto
8350 : // // with wrapped function here
8351 : // pop // classObj classCtor classProto
8352 : //
8353 : // needsHomeObject is false for other cases, push wrapped function only.
8354 114 : if (!emitAsyncWrapperLambda(index, isArrow))
8355 0 : return false;
8356 114 : if (needsHomeObject) {
8357 0 : if (!emit1(JSOP_DUP))
8358 0 : return false;
8359 : }
8360 114 : if (isStarGenerator) {
8361 0 : if (!emit1(JSOP_TOASYNCGEN))
8362 0 : return false;
8363 : } else {
8364 114 : if (!emit1(JSOP_TOASYNC))
8365 0 : return false;
8366 : }
8367 114 : return true;
8368 : }
8369 :
8370 : bool
8371 20 : BytecodeEmitter::emitDo(ParseNode* pn)
8372 : {
8373 : /* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */
8374 : unsigned noteIndex;
8375 20 : if (!newSrcNote(SRC_WHILE, ¬eIndex))
8376 0 : return false;
8377 20 : if (!emit1(JSOP_NOP))
8378 0 : return false;
8379 :
8380 : unsigned noteIndex2;
8381 20 : if (!newSrcNote(SRC_WHILE, ¬eIndex2))
8382 0 : return false;
8383 :
8384 : /* Compile the loop body. */
8385 : JumpTarget top;
8386 20 : if (!emitLoopHead(pn->pn_left, &top))
8387 0 : return false;
8388 :
8389 40 : LoopControl loopInfo(this, StatementKind::DoLoop);
8390 :
8391 20 : JumpList empty;
8392 20 : if (!emitLoopEntry(nullptr, empty))
8393 0 : return false;
8394 :
8395 20 : if (!emitTree(pn->pn_left))
8396 0 : return false;
8397 :
8398 : // Set the offset for continues.
8399 20 : if (!emitJumpTarget(&loopInfo.continueTarget))
8400 0 : return false;
8401 :
8402 : /* Compile the loop condition, now that continues know where to go. */
8403 20 : if (!emitTree(pn->pn_right))
8404 0 : return false;
8405 :
8406 20 : JumpList beq;
8407 20 : JumpTarget breakTarget{ -1 };
8408 20 : if (!emitBackwardJump(JSOP_IFNE, top, &beq, &breakTarget))
8409 0 : return false;
8410 :
8411 20 : if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
8412 0 : return false;
8413 :
8414 : /*
8415 : * Update the annotations with the update and back edge positions, for
8416 : * IonBuilder.
8417 : *
8418 : * Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
8419 : * note gets bigger.
8420 : */
8421 20 : if (!setSrcNoteOffset(noteIndex2, 0, beq.offset - top.offset))
8422 0 : return false;
8423 20 : if (!setSrcNoteOffset(noteIndex, 0, 1 + (loopInfo.continueTarget.offset - top.offset)))
8424 0 : return false;
8425 :
8426 20 : if (!loopInfo.patchBreaksAndContinues(this))
8427 0 : return false;
8428 :
8429 20 : return true;
8430 : }
8431 :
8432 : bool
8433 183 : BytecodeEmitter::emitWhile(ParseNode* pn)
8434 : {
8435 : /*
8436 : * Minimize bytecodes issued for one or more iterations by jumping to
8437 : * the condition below the body and closing the loop if the condition
8438 : * is true with a backward branch. For iteration count i:
8439 : *
8440 : * i test at the top test at the bottom
8441 : * = =============== ==================
8442 : * 0 ifeq-pass goto; ifne-fail
8443 : * 1 ifeq-fail; goto; ifne-pass goto; ifne-pass; ifne-fail
8444 : * 2 2*(ifeq-fail; goto); ifeq-pass goto; 2*ifne-pass; ifne-fail
8445 : * . . .
8446 : * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail
8447 : */
8448 :
8449 : // If we have a single-line while, like "while (x) ;", we want to
8450 : // emit the line note before the initial goto, so that the
8451 : // debugger sees a single entry point. This way, if there is a
8452 : // breakpoint on the line, it will only fire once; and "next"ing
8453 : // will skip the whole loop. However, for the multi-line case we
8454 : // want to emit the line note after the initial goto, so that
8455 : // "cont" stops on each iteration -- but without a stop before the
8456 : // first iteration.
8457 366 : if (parser.tokenStream().srcCoords.lineNum(pn->pn_pos.begin) ==
8458 183 : parser.tokenStream().srcCoords.lineNum(pn->pn_pos.end))
8459 : {
8460 0 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
8461 0 : return false;
8462 : }
8463 :
8464 183 : JumpTarget top{ -1 };
8465 183 : if (!emitJumpTarget(&top))
8466 0 : return false;
8467 :
8468 366 : LoopControl loopInfo(this, StatementKind::WhileLoop);
8469 183 : loopInfo.continueTarget = top;
8470 :
8471 : unsigned noteIndex;
8472 183 : if (!newSrcNote(SRC_WHILE, ¬eIndex))
8473 0 : return false;
8474 :
8475 183 : JumpList jmp;
8476 183 : if (!emitJump(JSOP_GOTO, &jmp))
8477 0 : return false;
8478 :
8479 183 : if (!emitLoopHead(pn->pn_right, &top))
8480 0 : return false;
8481 :
8482 183 : if (!emitTreeInBranch(pn->pn_right))
8483 0 : return false;
8484 :
8485 183 : if (!emitLoopEntry(pn->pn_left, jmp))
8486 0 : return false;
8487 183 : if (!emitTree(pn->pn_left))
8488 0 : return false;
8489 :
8490 183 : JumpList beq;
8491 183 : JumpTarget breakTarget{ -1 };
8492 183 : if (!emitBackwardJump(JSOP_IFNE, top, &beq, &breakTarget))
8493 0 : return false;
8494 :
8495 183 : if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top.offset, breakTarget.offset))
8496 0 : return false;
8497 :
8498 183 : if (!setSrcNoteOffset(noteIndex, 0, beq.offset - jmp.offset))
8499 0 : return false;
8500 :
8501 183 : if (!loopInfo.patchBreaksAndContinues(this))
8502 0 : return false;
8503 :
8504 183 : return true;
8505 : }
8506 :
8507 : bool
8508 479 : BytecodeEmitter::emitBreak(PropertyName* label)
8509 : {
8510 : BreakableControl* target;
8511 : SrcNoteType noteType;
8512 479 : if (label) {
8513 : // Any statement with the matching label may be the break target.
8514 0 : auto hasSameLabel = [label](LabelControl* labelControl) {
8515 0 : return labelControl->label() == label;
8516 0 : };
8517 0 : target = findInnermostNestableControl<LabelControl>(hasSameLabel);
8518 0 : noteType = SRC_BREAK2LABEL;
8519 : } else {
8520 479 : auto isNotLabel = [](BreakableControl* control) {
8521 479 : return !control->is<LabelControl>();
8522 479 : };
8523 479 : target = findInnermostNestableControl<BreakableControl>(isNotLabel);
8524 479 : noteType = (target->kind() == StatementKind::Switch) ? SRC_SWITCHBREAK : SRC_BREAK;
8525 : }
8526 :
8527 479 : return emitGoto(target, &target->breaks, noteType);
8528 : }
8529 :
8530 : bool
8531 121 : BytecodeEmitter::emitContinue(PropertyName* label)
8532 : {
8533 121 : LoopControl* target = nullptr;
8534 121 : if (label) {
8535 : // Find the loop statement enclosed by the matching label.
8536 0 : NestableControl* control = innermostNestableControl;
8537 0 : while (!control->is<LabelControl>() || control->as<LabelControl>().label() != label) {
8538 0 : if (control->is<LoopControl>())
8539 0 : target = &control->as<LoopControl>();
8540 0 : control = control->enclosing();
8541 : }
8542 : } else {
8543 121 : target = findInnermostNestableControl<LoopControl>();
8544 : }
8545 121 : return emitGoto(target, &target->continues, SRC_CONTINUE);
8546 : }
8547 :
8548 : bool
8549 6976 : BytecodeEmitter::emitGetFunctionThis(ParseNode* pn)
8550 : {
8551 6976 : MOZ_ASSERT(sc->thisBinding() == ThisBinding::Function);
8552 6976 : MOZ_ASSERT(pn->isKind(PNK_NAME));
8553 6976 : MOZ_ASSERT(pn->name() == cx->names().dotThis);
8554 :
8555 6976 : if (!emitTree(pn))
8556 0 : return false;
8557 6976 : if (sc->needsThisTDZChecks() && !emit1(JSOP_CHECKTHIS))
8558 0 : return false;
8559 :
8560 6976 : return true;
8561 : }
8562 :
8563 : bool
8564 13 : BytecodeEmitter::emitGetThisForSuperBase(ParseNode* pn)
8565 : {
8566 13 : MOZ_ASSERT(pn->isKind(PNK_SUPERBASE));
8567 13 : return emitGetFunctionThis(pn->pn_kid);
8568 : }
8569 :
8570 : bool
8571 7700 : BytecodeEmitter::emitThisLiteral(ParseNode* pn)
8572 : {
8573 7700 : MOZ_ASSERT(pn->isKind(PNK_THIS));
8574 :
8575 7700 : if (ParseNode* thisName = pn->pn_kid)
8576 6963 : return emitGetFunctionThis(thisName);
8577 :
8578 737 : if (sc->thisBinding() == ThisBinding::Module)
8579 0 : return emit1(JSOP_UNDEFINED);
8580 :
8581 737 : MOZ_ASSERT(sc->thisBinding() == ThisBinding::Global);
8582 737 : return emit1(JSOP_GLOBALTHIS);
8583 : }
8584 :
8585 : bool
8586 14 : BytecodeEmitter::emitCheckDerivedClassConstructorReturn()
8587 : {
8588 14 : MOZ_ASSERT(lookupName(cx->names().dotThis).hasKnownSlot());
8589 14 : if (!emitGetName(cx->names().dotThis))
8590 0 : return false;
8591 14 : if (!emit1(JSOP_CHECKRETURN))
8592 0 : return false;
8593 14 : return true;
8594 : }
8595 :
8596 : bool
8597 6164 : BytecodeEmitter::emitReturn(ParseNode* pn)
8598 : {
8599 6164 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
8600 0 : return false;
8601 :
8602 6164 : bool needsIteratorResult = sc->isFunctionBox() && sc->asFunctionBox()->needsIteratorResult();
8603 6164 : if (needsIteratorResult) {
8604 0 : if (!emitPrepareIteratorResult())
8605 0 : return false;
8606 : }
8607 :
8608 : /* Push a return value */
8609 6164 : if (ParseNode* pn2 = pn->pn_kid) {
8610 5666 : if (!emitTree(pn2))
8611 0 : return false;
8612 : } else {
8613 : /* No explicit return value provided */
8614 498 : if (!emit1(JSOP_UNDEFINED))
8615 0 : return false;
8616 : }
8617 :
8618 6164 : if (needsIteratorResult) {
8619 0 : if (!emitFinishIteratorResult(true))
8620 0 : return false;
8621 : }
8622 :
8623 : // We know functionBodyEndPos is set because "return" is only
8624 : // valid in a function, and so we've passed through
8625 : // emitFunctionScript.
8626 6164 : MOZ_ASSERT(functionBodyEndPosSet);
8627 6164 : if (!updateSourceCoordNotes(functionBodyEndPos))
8628 0 : return false;
8629 :
8630 : /*
8631 : * EmitNonLocalJumpFixup may add fixup bytecode to close open try
8632 : * blocks having finally clauses and to exit intermingled let blocks.
8633 : * We can't simply transfer control flow to our caller in that case,
8634 : * because we must gosub to those finally clauses from inner to outer,
8635 : * with the correct stack pointer (i.e., after popping any with,
8636 : * for/in, etc., slots nested inside the finally's try).
8637 : *
8638 : * In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
8639 : * extra JSOP_RETRVAL after the fixups.
8640 : */
8641 6164 : ptrdiff_t top = offset();
8642 :
8643 6164 : bool needsFinalYield = sc->isFunctionBox() && sc->asFunctionBox()->needsFinalYield();
8644 : bool isDerivedClassConstructor =
8645 6164 : sc->isFunctionBox() && sc->asFunctionBox()->isDerivedClassConstructor();
8646 :
8647 6164 : if (!emit1((needsFinalYield || isDerivedClassConstructor) ? JSOP_SETRVAL : JSOP_RETURN))
8648 0 : return false;
8649 :
8650 : // Make sure that we emit this before popping the blocks in prepareForNonLocalJump,
8651 : // to ensure that the error is thrown while the scope-chain is still intact.
8652 6164 : if (isDerivedClassConstructor) {
8653 1 : if (!emitCheckDerivedClassConstructorReturn())
8654 0 : return false;
8655 : }
8656 :
8657 12328 : NonLocalExitControl nle(this, NonLocalExitControl::Return);
8658 :
8659 6164 : if (!nle.prepareForNonLocalJumpToOutermost())
8660 0 : return false;
8661 :
8662 6164 : if (needsFinalYield) {
8663 : // We know that .generator is on the function scope, as we just exited
8664 : // all nested scopes.
8665 : NameLocation loc =
8666 84 : *locationOfNameBoundInFunctionScope(cx->names().dotGenerator, varEmitterScope);
8667 84 : if (!emitGetNameAtLocation(cx->names().dotGenerator, loc))
8668 0 : return false;
8669 84 : if (!emitYieldOp(JSOP_FINALYIELDRVAL))
8670 0 : return false;
8671 6080 : } else if (isDerivedClassConstructor) {
8672 1 : MOZ_ASSERT(code()[top] == JSOP_SETRVAL);
8673 1 : if (!emit1(JSOP_RETRVAL))
8674 0 : return false;
8675 6079 : } else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) != offset()) {
8676 1651 : code()[top] = JSOP_SETRVAL;
8677 1651 : if (!emit1(JSOP_RETRVAL))
8678 0 : return false;
8679 : }
8680 :
8681 6164 : return true;
8682 : }
8683 :
8684 : bool
8685 380 : BytecodeEmitter::emitGetDotGenerator()
8686 : {
8687 380 : NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
8688 380 : return emitGetNameAtLocation(cx->names().dotGenerator, loc);
8689 : }
8690 :
8691 : bool
8692 127 : BytecodeEmitter::emitInitialYield(ParseNode* pn)
8693 : {
8694 127 : if (!emitTree(pn->pn_kid))
8695 0 : return false;
8696 :
8697 127 : if (!emitYieldOp(JSOP_INITIALYIELD))
8698 0 : return false;
8699 :
8700 127 : if (!emit1(JSOP_POP))
8701 0 : return false;
8702 :
8703 127 : return true;
8704 : }
8705 :
8706 : bool
8707 15 : BytecodeEmitter::emitYield(ParseNode* pn)
8708 : {
8709 15 : MOZ_ASSERT(sc->isFunctionBox());
8710 15 : MOZ_ASSERT(pn->getOp() == JSOP_YIELD);
8711 :
8712 15 : bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
8713 15 : if (needsIteratorResult) {
8714 15 : if (!emitPrepareIteratorResult())
8715 0 : return false;
8716 : }
8717 15 : if (pn->pn_kid) {
8718 15 : if (!emitTree(pn->pn_kid))
8719 0 : return false;
8720 : } else {
8721 0 : if (!emit1(JSOP_UNDEFINED))
8722 0 : return false;
8723 : }
8724 15 : if (needsIteratorResult) {
8725 15 : if (!emitFinishIteratorResult(false))
8726 0 : return false;
8727 : }
8728 :
8729 15 : if (!emitGetDotGenerator())
8730 0 : return false;
8731 :
8732 15 : if (!emitYieldOp(JSOP_YIELD))
8733 0 : return false;
8734 :
8735 15 : return true;
8736 : }
8737 :
8738 : bool
8739 235 : BytecodeEmitter::emitAwait()
8740 : {
8741 235 : if (!emitGetDotGenerator())
8742 0 : return false;
8743 235 : if (!emitYieldOp(JSOP_AWAIT))
8744 0 : return false;
8745 235 : return true;
8746 : }
8747 :
8748 : bool
8749 235 : BytecodeEmitter::emitAwait(ParseNode* pn)
8750 : {
8751 235 : MOZ_ASSERT(sc->isFunctionBox());
8752 235 : MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
8753 :
8754 235 : if (!emitTree(pn->pn_kid))
8755 0 : return false;
8756 235 : return emitAwait();
8757 : }
8758 :
8759 : bool
8760 3 : BytecodeEmitter::emitYieldStar(ParseNode* iter)
8761 : {
8762 3 : MOZ_ASSERT(sc->isFunctionBox());
8763 3 : MOZ_ASSERT(sc->asFunctionBox()->isStarGenerator());
8764 :
8765 3 : bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
8766 :
8767 3 : if (!emitTree(iter)) // ITERABLE
8768 0 : return false;
8769 3 : if (isAsyncGenerator) {
8770 0 : if (!emitAsyncIterator()) // ITER
8771 0 : return false;
8772 : } else {
8773 3 : if (!emitIterator()) // ITER
8774 0 : return false;
8775 : }
8776 :
8777 : // Initial send value is undefined.
8778 3 : if (!emit1(JSOP_UNDEFINED)) // ITER RECEIVED
8779 0 : return false;
8780 :
8781 : int32_t savedDepthTemp;
8782 3 : int32_t startDepth = stackDepth;
8783 3 : MOZ_ASSERT(startDepth >= 2);
8784 :
8785 : TryEmitter tryCatch(this, TryEmitter::TryCatchFinally, TryEmitter::DontUseRetVal,
8786 6 : TryEmitter::DontUseControl);
8787 3 : if (!tryCatch.emitJumpOverCatchAndFinally()) // ITER RESULT
8788 0 : return false;
8789 :
8790 3 : JumpTarget tryStart{ offset() };
8791 3 : if (!tryCatch.emitTry()) // ITER RESULT
8792 0 : return false;
8793 :
8794 3 : MOZ_ASSERT(this->stackDepth == startDepth);
8795 :
8796 : // Load the generator object.
8797 3 : if (!emitGetDotGenerator()) // ITER RESULT GENOBJ
8798 0 : return false;
8799 :
8800 : // Yield RESULT as-is, without re-boxing.
8801 3 : if (!emitYieldOp(JSOP_YIELD)) // ITER RECEIVED
8802 0 : return false;
8803 :
8804 3 : if (!tryCatch.emitCatch()) // ITER RESULT
8805 0 : return false;
8806 :
8807 3 : stackDepth = startDepth; // ITER RESULT
8808 3 : if (!emit1(JSOP_EXCEPTION)) // ITER RESULT EXCEPTION
8809 0 : return false;
8810 3 : if (!emitDupAt(2)) // ITER RESULT EXCEPTION ITER
8811 0 : return false;
8812 3 : if (!emit1(JSOP_DUP)) // ITER RESULT EXCEPTION ITER ITER
8813 0 : return false;
8814 3 : if (!emitAtomOp(cx->names().throw_, JSOP_CALLPROP)) // ITER RESULT EXCEPTION ITER THROW
8815 0 : return false;
8816 3 : if (!emit1(JSOP_DUP)) // ITER RESULT EXCEPTION ITER THROW THROW
8817 0 : return false;
8818 3 : if (!emit1(JSOP_UNDEFINED)) // ITER RESULT EXCEPTION ITER THROW THROW UNDEFINED
8819 0 : return false;
8820 3 : if (!emit1(JSOP_EQ)) // ITER RESULT EXCEPTION ITER THROW ?EQL
8821 0 : return false;
8822 :
8823 6 : IfThenElseEmitter ifThrowMethodIsNotDefined(this);
8824 3 : if (!ifThrowMethodIsNotDefined.emitIf()) // ITER RESULT EXCEPTION ITER THROW
8825 0 : return false;
8826 3 : savedDepthTemp = stackDepth;
8827 3 : if (!emit1(JSOP_POP)) // ITER RESULT EXCEPTION ITER
8828 0 : return false;
8829 : // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
8830 : //
8831 : // If the iterator does not have a "throw" method, it calls IteratorClose
8832 : // and then throws a TypeError.
8833 3 : IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
8834 3 : if (!emitIteratorClose(iterKind)) // ITER RESULT EXCEPTION
8835 0 : return false;
8836 3 : if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
8837 0 : return false;
8838 3 : stackDepth = savedDepthTemp;
8839 3 : if (!ifThrowMethodIsNotDefined.emitEnd()) // ITER OLDRESULT EXCEPTION ITER THROW
8840 0 : return false;
8841 : // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.4.
8842 : // RESULT = ITER.throw(EXCEPTION) // ITER OLDRESULT EXCEPTION ITER THROW
8843 3 : if (!emit1(JSOP_SWAP)) // ITER OLDRESULT EXCEPTION THROW ITER
8844 0 : return false;
8845 3 : if (!emit2(JSOP_PICK, 2)) // ITER OLDRESULT THROW ITER EXCEPTION
8846 0 : return false;
8847 3 : if (!emitCall(JSOP_CALL, 1, iter)) // ITER OLDRESULT RESULT
8848 0 : return false;
8849 3 : checkTypeSet(JSOP_CALL);
8850 :
8851 3 : if (isAsyncGenerator) {
8852 0 : if (!emitAwait()) // ITER OLDRESULT RESULT
8853 0 : return false;
8854 : }
8855 :
8856 3 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorThrow)) // ITER OLDRESULT RESULT
8857 0 : return false;
8858 3 : if (!emit1(JSOP_SWAP)) // ITER RESULT OLDRESULT
8859 0 : return false;
8860 3 : if (!emit1(JSOP_POP)) // ITER RESULT
8861 0 : return false;
8862 3 : MOZ_ASSERT(this->stackDepth == startDepth);
8863 3 : JumpList checkResult;
8864 : // ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.ii.
8865 : //
8866 : // Note that there is no GOSUB to the finally block here. If the iterator has a
8867 : // "throw" method, it does not perform IteratorClose.
8868 3 : if (!emitJump(JSOP_GOTO, &checkResult)) // goto checkResult
8869 0 : return false;
8870 :
8871 3 : if (!tryCatch.emitFinally())
8872 0 : return false;
8873 :
8874 : // ES 14.4.13, yield * AssignmentExpression, step 5.c
8875 : //
8876 : // Call iterator.return() for receiving a "forced return" completion from
8877 : // the generator.
8878 :
8879 6 : IfThenElseEmitter ifGeneratorClosing(this);
8880 3 : if (!emit1(JSOP_ISGENCLOSING)) // ITER RESULT FTYPE FVALUE CLOSING
8881 0 : return false;
8882 3 : if (!ifGeneratorClosing.emitIf()) // ITER RESULT FTYPE FVALUE
8883 0 : return false;
8884 :
8885 : // Step ii.
8886 : //
8887 : // Get the "return" method.
8888 3 : if (!emitDupAt(3)) // ITER RESULT FTYPE FVALUE ITER
8889 0 : return false;
8890 3 : if (!emit1(JSOP_DUP)) // ITER RESULT FTYPE FVALUE ITER ITER
8891 0 : return false;
8892 3 : if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) // ITER RESULT FTYPE FVALUE ITER RET
8893 0 : return false;
8894 :
8895 : // Step iii.
8896 : //
8897 : // Do nothing if "return" is undefined.
8898 6 : IfThenElseEmitter ifReturnMethodIsDefined(this);
8899 3 : if (!emit1(JSOP_DUP)) // ITER RESULT FTYPE FVALUE ITER RET RET
8900 0 : return false;
8901 3 : if (!emit1(JSOP_UNDEFINED)) // ITER RESULT FTYPE FVALUE ITER RET RET UNDEFINED
8902 0 : return false;
8903 3 : if (!emit1(JSOP_NE)) // ITER RESULT FTYPE FVALUE ITER RET ?NEQL
8904 0 : return false;
8905 :
8906 : // Step iv.
8907 : //
8908 : // Call "return" with the argument passed to Generator.prototype.return,
8909 : // which is currently in rval.value.
8910 3 : if (!ifReturnMethodIsDefined.emitIfElse()) // ITER OLDRESULT FTYPE FVALUE ITER RET
8911 0 : return false;
8912 3 : if (!emit1(JSOP_SWAP)) // ITER OLDRESULT FTYPE FVALUE RET ITER
8913 0 : return false;
8914 3 : if (!emit1(JSOP_GETRVAL)) // ITER OLDRESULT FTYPE FVALUE RET ITER RVAL
8915 0 : return false;
8916 3 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER OLDRESULT FTYPE FVALUE RET ITER VALUE
8917 0 : return false;
8918 3 : if (!emitCall(JSOP_CALL, 1)) // ITER OLDRESULT FTYPE FVALUE RESULT
8919 0 : return false;
8920 3 : checkTypeSet(JSOP_CALL);
8921 :
8922 3 : if (iterKind == IteratorKind::Async) {
8923 0 : if (!emitAwait()) // ... FTYPE FVALUE RESULT
8924 0 : return false;
8925 : }
8926 :
8927 : // Step v.
8928 3 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ITER OLDRESULT FTYPE FVALUE RESULT
8929 0 : return false;
8930 :
8931 : // Steps vi-viii.
8932 : //
8933 : // Check if the returned object from iterator.return() is done. If not,
8934 : // continuing yielding.
8935 6 : IfThenElseEmitter ifReturnDone(this);
8936 3 : if (!emit1(JSOP_DUP)) // ITER OLDRESULT FTYPE FVALUE RESULT RESULT
8937 0 : return false;
8938 3 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER OLDRESULT FTYPE FVALUE RESULT DONE
8939 0 : return false;
8940 3 : if (!ifReturnDone.emitIfElse()) // ITER OLDRESULT FTYPE FVALUE RESULT
8941 0 : return false;
8942 3 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ITER OLDRESULT FTYPE FVALUE VALUE
8943 0 : return false;
8944 :
8945 3 : if (isAsyncGenerator) {
8946 0 : if (!emitAwait()) // ITER OLDRESULT FTYPE FVALUE VALUE
8947 0 : return false;
8948 : }
8949 :
8950 3 : if (!emitPrepareIteratorResult()) // ITER OLDRESULT FTYPE FVALUE VALUE RESULT
8951 0 : return false;
8952 3 : if (!emit1(JSOP_SWAP)) // ITER OLDRESULT FTYPE FVALUE RESULT VALUE
8953 0 : return false;
8954 3 : if (!emitFinishIteratorResult(true)) // ITER OLDRESULT FTYPE FVALUE RESULT
8955 0 : return false;
8956 3 : if (!emit1(JSOP_SETRVAL)) // ITER OLDRESULT FTYPE FVALUE
8957 0 : return false;
8958 3 : savedDepthTemp = this->stackDepth;
8959 3 : if (!ifReturnDone.emitElse()) // ITER OLDRESULT FTYPE FVALUE RESULT
8960 0 : return false;
8961 3 : if (!emit2(JSOP_UNPICK, 3)) // ITER RESULT OLDRESULT FTYPE FVALUE
8962 0 : return false;
8963 3 : if (!emitPopN(3)) // ITER RESULT
8964 0 : return false;
8965 : {
8966 : // goto tryStart;
8967 3 : JumpList beq;
8968 3 : JumpTarget breakTarget{ -1 };
8969 3 : if (!emitBackwardJump(JSOP_GOTO, tryStart, &beq, &breakTarget)) // ITER RESULT
8970 0 : return false;
8971 : }
8972 3 : this->stackDepth = savedDepthTemp;
8973 3 : if (!ifReturnDone.emitEnd())
8974 0 : return false;
8975 :
8976 3 : if (!ifReturnMethodIsDefined.emitElse()) // ITER RESULT FTYPE FVALUE ITER RET
8977 0 : return false;
8978 3 : if (!emitPopN(2)) // ITER RESULT FTYPE FVALUE
8979 0 : return false;
8980 3 : if (!ifReturnMethodIsDefined.emitEnd())
8981 0 : return false;
8982 :
8983 3 : if (!ifGeneratorClosing.emitEnd())
8984 0 : return false;
8985 :
8986 3 : if (!tryCatch.emitEnd())
8987 0 : return false;
8988 :
8989 : // After the try-catch-finally block: send the received value to the iterator.
8990 : // result = iter.next(received) // ITER RECEIVED
8991 3 : if (!emit1(JSOP_SWAP)) // RECEIVED ITER
8992 0 : return false;
8993 3 : if (!emit1(JSOP_DUP)) // RECEIVED ITER ITER
8994 0 : return false;
8995 3 : if (!emit1(JSOP_DUP)) // RECEIVED ITER ITER ITER
8996 0 : return false;
8997 3 : if (!emitAtomOp(cx->names().next, JSOP_CALLPROP)) // RECEIVED ITER ITER NEXT
8998 0 : return false;
8999 3 : if (!emit1(JSOP_SWAP)) // RECEIVED ITER NEXT ITER
9000 0 : return false;
9001 3 : if (!emit2(JSOP_PICK, 3)) // ITER NEXT ITER RECEIVED
9002 0 : return false;
9003 3 : if (!emitCall(JSOP_CALL, 1, iter)) // ITER RESULT
9004 0 : return false;
9005 3 : checkTypeSet(JSOP_CALL);
9006 :
9007 3 : if (isAsyncGenerator) {
9008 0 : if (!emitAwait()) // ITER RESULT RESULT
9009 0 : return false;
9010 : }
9011 :
9012 3 : if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ITER RESULT
9013 0 : return false;
9014 3 : MOZ_ASSERT(this->stackDepth == startDepth);
9015 :
9016 3 : if (!emitJumpTargetAndPatch(checkResult)) // checkResult:
9017 0 : return false;
9018 :
9019 : // if (!result.done) goto tryStart; // ITER RESULT
9020 3 : if (!emit1(JSOP_DUP)) // ITER RESULT RESULT
9021 0 : return false;
9022 3 : if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE
9023 0 : return false;
9024 : // if (!DONE) goto tryStart;
9025 : {
9026 3 : JumpList beq;
9027 3 : JumpTarget breakTarget{ -1 };
9028 3 : if (!emitBackwardJump(JSOP_IFEQ, tryStart, &beq, &breakTarget)) // ITER RESULT
9029 0 : return false;
9030 : }
9031 :
9032 : // result.value
9033 3 : if (!emit1(JSOP_SWAP)) // RESULT ITER
9034 0 : return false;
9035 3 : if (!emit1(JSOP_POP)) // RESULT
9036 0 : return false;
9037 3 : if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // VALUE
9038 0 : return false;
9039 :
9040 3 : if (isAsyncGenerator) {
9041 0 : if (!emitAwait()) // VALUE
9042 0 : return false;
9043 : }
9044 :
9045 3 : MOZ_ASSERT(this->stackDepth == startDepth - 1);
9046 :
9047 3 : return true;
9048 : }
9049 :
9050 : bool
9051 12756 : BytecodeEmitter::emitStatementList(ParseNode* pn)
9052 : {
9053 12756 : MOZ_ASSERT(pn->isArity(PN_LIST));
9054 50148 : for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
9055 37390 : if (!emitTree(pn2))
9056 0 : return false;
9057 : }
9058 12758 : return true;
9059 : }
9060 :
9061 : bool
9062 14318 : BytecodeEmitter::emitStatement(ParseNode* pn)
9063 : {
9064 14318 : MOZ_ASSERT(pn->isKind(PNK_SEMI));
9065 :
9066 14318 : ParseNode* pn2 = pn->pn_kid;
9067 14318 : if (!pn2)
9068 11 : return true;
9069 :
9070 14307 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
9071 0 : return false;
9072 :
9073 : /*
9074 : * Top-level or called-from-a-native JS_Execute/EvaluateScript,
9075 : * debugger, and eval frames may need the value of the ultimate
9076 : * expression statement as the script's result, despite the fact
9077 : * that it appears useless to the compiler.
9078 : *
9079 : * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
9080 : * calling JS_Compile* to suppress JSOP_SETRVAL.
9081 : */
9082 14307 : bool wantval = false;
9083 14307 : bool useful = false;
9084 14307 : if (sc->isFunctionBox())
9085 12413 : MOZ_ASSERT(!script->noScriptRval());
9086 : else
9087 1894 : useful = wantval = !script->noScriptRval();
9088 :
9089 : /* Don't eliminate expressions with side effects. */
9090 14307 : if (!useful) {
9091 14024 : if (!checkSideEffects(pn2, &useful))
9092 0 : return false;
9093 :
9094 : /*
9095 : * Don't eliminate apparently useless expressions if they are labeled
9096 : * expression statements. The startOffset() test catches the case
9097 : * where we are nesting in emitTree for a labeled compound statement.
9098 : */
9099 31746 : if (innermostNestableControl &&
9100 14024 : innermostNestableControl->is<LabelControl>() &&
9101 0 : innermostNestableControl->as<LabelControl>().startOffset() >= offset())
9102 : {
9103 0 : useful = true;
9104 : }
9105 : }
9106 :
9107 14307 : if (useful) {
9108 14200 : JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
9109 14200 : ValueUsage valueUsage = wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
9110 14200 : MOZ_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
9111 14200 : if (!emitTree(pn2, valueUsage))
9112 0 : return false;
9113 14200 : if (!emit1(op))
9114 0 : return false;
9115 107 : } else if (pn->isDirectivePrologueMember()) {
9116 : // Don't complain about directive prologue members; just don't emit
9117 : // their code.
9118 : } else {
9119 0 : if (JSAtom* atom = pn->isStringExprStatement()) {
9120 : // Warn if encountering a non-directive prologue member string
9121 : // expression statement, that is inconsistent with the current
9122 : // directive prologue. That is, a script *not* starting with
9123 : // "use strict" should warn for any "use strict" statements seen
9124 : // later in the script, because such statements are misleading.
9125 0 : const char* directive = nullptr;
9126 0 : if (atom == cx->names().useStrict) {
9127 0 : if (!sc->strictScript)
9128 0 : directive = js_useStrict_str;
9129 0 : } else if (atom == cx->names().useAsm) {
9130 0 : if (sc->isFunctionBox()) {
9131 0 : if (IsAsmJSModule(sc->asFunctionBox()->function()))
9132 0 : directive = js_useAsm_str;
9133 : }
9134 : }
9135 :
9136 0 : if (directive) {
9137 0 : if (!reportExtraWarning(pn2, JSMSG_CONTRARY_NONDIRECTIVE, directive))
9138 0 : return false;
9139 : }
9140 : } else {
9141 0 : if (!reportExtraWarning(pn2, JSMSG_USELESS_EXPR))
9142 0 : return false;
9143 : }
9144 : }
9145 :
9146 14307 : return true;
9147 : }
9148 :
9149 : bool
9150 0 : BytecodeEmitter::emitDeleteName(ParseNode* node)
9151 : {
9152 0 : MOZ_ASSERT(node->isKind(PNK_DELETENAME));
9153 0 : MOZ_ASSERT(node->isArity(PN_UNARY));
9154 :
9155 0 : ParseNode* nameExpr = node->pn_kid;
9156 0 : MOZ_ASSERT(nameExpr->isKind(PNK_NAME));
9157 :
9158 0 : return emitAtomOp(nameExpr, JSOP_DELNAME);
9159 : }
9160 :
9161 : bool
9162 52 : BytecodeEmitter::emitDeleteProperty(ParseNode* node)
9163 : {
9164 52 : MOZ_ASSERT(node->isKind(PNK_DELETEPROP));
9165 52 : MOZ_ASSERT(node->isArity(PN_UNARY));
9166 :
9167 52 : ParseNode* propExpr = node->pn_kid;
9168 52 : MOZ_ASSERT(propExpr->isKind(PNK_DOT));
9169 :
9170 52 : if (propExpr->as<PropertyAccess>().isSuper()) {
9171 : // Still have to calculate the base, even though we are are going
9172 : // to throw unconditionally, as calculating the base could also
9173 : // throw.
9174 0 : if (!emit1(JSOP_SUPERBASE))
9175 0 : return false;
9176 :
9177 0 : return emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER);
9178 : }
9179 :
9180 52 : JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
9181 52 : return emitPropOp(propExpr, delOp);
9182 : }
9183 :
9184 : bool
9185 30 : BytecodeEmitter::emitDeleteElement(ParseNode* node)
9186 : {
9187 30 : MOZ_ASSERT(node->isKind(PNK_DELETEELEM));
9188 30 : MOZ_ASSERT(node->isArity(PN_UNARY));
9189 :
9190 30 : ParseNode* elemExpr = node->pn_kid;
9191 30 : MOZ_ASSERT(elemExpr->isKind(PNK_ELEM));
9192 :
9193 30 : if (elemExpr->as<PropertyByValue>().isSuper()) {
9194 : // Still have to calculate everything, even though we're gonna throw
9195 : // since it may have side effects
9196 0 : if (!emitTree(elemExpr->pn_right))
9197 0 : return false;
9198 :
9199 0 : if (!emit1(JSOP_SUPERBASE))
9200 0 : return false;
9201 0 : if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
9202 0 : return false;
9203 :
9204 : // Another wrinkle: Balance the stack from the emitter's point of view.
9205 : // Execution will not reach here, as the last bytecode threw.
9206 0 : return emit1(JSOP_POP);
9207 : }
9208 :
9209 30 : JSOp delOp = sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
9210 30 : return emitElemOp(elemExpr, delOp);
9211 : }
9212 :
9213 : bool
9214 0 : BytecodeEmitter::emitDeleteExpression(ParseNode* node)
9215 : {
9216 0 : MOZ_ASSERT(node->isKind(PNK_DELETEEXPR));
9217 0 : MOZ_ASSERT(node->isArity(PN_UNARY));
9218 :
9219 0 : ParseNode* expression = node->pn_kid;
9220 :
9221 : // If useless, just emit JSOP_TRUE; otherwise convert |delete <expr>| to
9222 : // effectively |<expr>, true|.
9223 0 : bool useful = false;
9224 0 : if (!checkSideEffects(expression, &useful))
9225 0 : return false;
9226 :
9227 0 : if (useful) {
9228 0 : if (!emitTree(expression))
9229 0 : return false;
9230 0 : if (!emit1(JSOP_POP))
9231 0 : return false;
9232 : }
9233 :
9234 0 : return emit1(JSOP_TRUE);
9235 : }
9236 :
9237 : static const char *
9238 1326 : SelfHostedCallFunctionName(JSAtom* name, JSContext* cx)
9239 : {
9240 1326 : if (name == cx->names().callFunction)
9241 978 : return "callFunction";
9242 348 : if (name == cx->names().callContentFunction)
9243 219 : return "callContentFunction";
9244 129 : if (name == cx->names().constructContentFunction)
9245 129 : return "constructContentFunction";
9246 :
9247 0 : MOZ_CRASH("Unknown self-hosted call function name");
9248 : }
9249 :
9250 : bool
9251 1326 : BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn)
9252 : {
9253 : // Special-casing of callFunction to emit bytecode that directly
9254 : // invokes the callee with the correct |this| object and arguments.
9255 : // callFunction(fun, thisArg, arg0, arg1) thus becomes:
9256 : // - emit lookup for fun
9257 : // - emit lookup for thisArg
9258 : // - emit lookups for arg0, arg1
9259 : //
9260 : // argc is set to the amount of actually emitted args and the
9261 : // emitting of args below is disabled by setting emitArgs to false.
9262 1326 : ParseNode* pn2 = pn->pn_head;
9263 1326 : const char* errorName = SelfHostedCallFunctionName(pn2->name(), cx);
9264 :
9265 1326 : if (pn->pn_count < 3) {
9266 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, "2", "s");
9267 0 : return false;
9268 : }
9269 :
9270 1326 : JSOp callOp = pn->getOp();
9271 1326 : if (callOp != JSOP_CALL) {
9272 0 : reportError(pn, JSMSG_NOT_CONSTRUCTOR, errorName);
9273 0 : return false;
9274 : }
9275 :
9276 1326 : bool constructing = pn2->name() == cx->names().constructContentFunction;
9277 1326 : ParseNode* funNode = pn2->pn_next;
9278 1326 : if (constructing)
9279 129 : callOp = JSOP_NEW;
9280 1197 : else if (funNode->getKind() == PNK_NAME && funNode->name() == cx->names().std_Function_apply)
9281 60 : callOp = JSOP_FUNAPPLY;
9282 :
9283 1326 : if (!emitTree(funNode))
9284 0 : return false;
9285 :
9286 : #ifdef DEBUG
9287 2652 : if (emitterMode == BytecodeEmitter::SelfHosting &&
9288 1326 : pn2->name() == cx->names().callFunction)
9289 : {
9290 978 : if (!emit1(JSOP_DEBUGCHECKSELFHOSTED))
9291 0 : return false;
9292 : }
9293 : #endif
9294 :
9295 1326 : ParseNode* thisOrNewTarget = funNode->pn_next;
9296 1326 : if (constructing) {
9297 : // Save off the new.target value, but here emit a proper |this| for a
9298 : // constructing call.
9299 129 : if (!emit1(JSOP_IS_CONSTRUCTING))
9300 0 : return false;
9301 : } else {
9302 : // It's |this|, emit it.
9303 1197 : if (!emitTree(thisOrNewTarget))
9304 0 : return false;
9305 : }
9306 :
9307 4038 : for (ParseNode* argpn = thisOrNewTarget->pn_next; argpn; argpn = argpn->pn_next) {
9308 2712 : if (!emitTree(argpn))
9309 0 : return false;
9310 : }
9311 :
9312 1326 : if (constructing) {
9313 129 : if (!emitTree(thisOrNewTarget))
9314 0 : return false;
9315 : }
9316 :
9317 1326 : uint32_t argc = pn->pn_count - 3;
9318 1326 : if (!emitCall(callOp, argc))
9319 0 : return false;
9320 :
9321 1326 : checkTypeSet(callOp);
9322 1326 : return true;
9323 : }
9324 :
9325 : bool
9326 27 : BytecodeEmitter::emitSelfHostedResumeGenerator(ParseNode* pn)
9327 : {
9328 : // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'close')
9329 27 : if (pn->pn_count != 4) {
9330 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, "resumeGenerator", "1", "s");
9331 0 : return false;
9332 : }
9333 :
9334 27 : ParseNode* funNode = pn->pn_head; // The resumeGenerator node.
9335 :
9336 27 : ParseNode* genNode = funNode->pn_next;
9337 27 : if (!emitTree(genNode))
9338 0 : return false;
9339 :
9340 27 : ParseNode* valNode = genNode->pn_next;
9341 27 : if (!emitTree(valNode))
9342 0 : return false;
9343 :
9344 27 : ParseNode* kindNode = valNode->pn_next;
9345 27 : MOZ_ASSERT(kindNode->isKind(PNK_STRING));
9346 27 : uint16_t operand = GeneratorObject::getResumeKind(cx, kindNode->pn_atom);
9347 27 : MOZ_ASSERT(!kindNode->pn_next);
9348 :
9349 27 : if (!emitCall(JSOP_RESUME, operand))
9350 0 : return false;
9351 :
9352 27 : return true;
9353 : }
9354 :
9355 : bool
9356 3 : BytecodeEmitter::emitSelfHostedForceInterpreter(ParseNode* pn)
9357 : {
9358 3 : if (!emit1(JSOP_FORCEINTERPRETER))
9359 0 : return false;
9360 3 : if (!emit1(JSOP_UNDEFINED))
9361 0 : return false;
9362 3 : return true;
9363 : }
9364 :
9365 : bool
9366 21 : BytecodeEmitter::emitSelfHostedAllowContentIter(ParseNode* pn)
9367 : {
9368 21 : if (pn->pn_count != 2) {
9369 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, "allowContentIter", "1", "");
9370 0 : return false;
9371 : }
9372 :
9373 : // We're just here as a sentinel. Pass the value through directly.
9374 21 : return emitTree(pn->pn_head->pn_next);
9375 : }
9376 :
9377 : bool
9378 183 : BytecodeEmitter::emitSelfHostedDefineDataProperty(ParseNode* pn)
9379 : {
9380 : // Only optimize when 3 arguments are passed (we use 4 to include |this|).
9381 183 : MOZ_ASSERT(pn->pn_count == 4);
9382 :
9383 183 : ParseNode* funNode = pn->pn_head; // The _DefineDataProperty node.
9384 :
9385 183 : ParseNode* objNode = funNode->pn_next;
9386 183 : if (!emitTree(objNode))
9387 0 : return false;
9388 :
9389 183 : ParseNode* idNode = objNode->pn_next;
9390 183 : if (!emitTree(idNode))
9391 0 : return false;
9392 :
9393 183 : ParseNode* valNode = idNode->pn_next;
9394 183 : if (!emitTree(valNode))
9395 0 : return false;
9396 :
9397 : // This will leave the object on the stack instead of pushing |undefined|,
9398 : // but that's fine because the self-hosted code doesn't use the return
9399 : // value.
9400 183 : return emit1(JSOP_INITELEM);
9401 : }
9402 :
9403 : bool
9404 51 : BytecodeEmitter::emitSelfHostedHasOwn(ParseNode* pn)
9405 : {
9406 51 : if (pn->pn_count != 3) {
9407 0 : reportError(pn, JSMSG_MORE_ARGS_NEEDED, "hasOwn", "2", "");
9408 0 : return false;
9409 : }
9410 :
9411 51 : ParseNode* funNode = pn->pn_head; // The hasOwn node.
9412 :
9413 51 : ParseNode* idNode = funNode->pn_next;
9414 51 : if (!emitTree(idNode))
9415 0 : return false;
9416 :
9417 51 : ParseNode* objNode = idNode->pn_next;
9418 51 : if (!emitTree(objNode))
9419 0 : return false;
9420 :
9421 51 : return emit1(JSOP_HASOWN);
9422 : }
9423 :
9424 : bool
9425 31 : BytecodeEmitter::isRestParameter(ParseNode* pn)
9426 : {
9427 31 : if (!sc->isFunctionBox())
9428 0 : return false;
9429 :
9430 31 : FunctionBox* funbox = sc->asFunctionBox();
9431 62 : RootedFunction fun(cx, funbox->function());
9432 31 : if (!funbox->hasRest())
9433 13 : return false;
9434 :
9435 18 : if (!pn->isKind(PNK_NAME)) {
9436 3 : if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(PNK_CALL)) {
9437 3 : ParseNode* pn2 = pn->pn_head;
9438 3 : if (pn2->getKind() == PNK_NAME && pn2->name() == cx->names().allowContentIter)
9439 3 : return isRestParameter(pn2->pn_next);
9440 : }
9441 0 : return false;
9442 : }
9443 :
9444 15 : JSAtom* name = pn->name();
9445 30 : Maybe<NameLocation> paramLoc = locationOfNameBoundInFunctionScope(name);
9446 15 : if (paramLoc && lookupName(name) == *paramLoc) {
9447 15 : FunctionScope::Data* bindings = funbox->functionScopeBindings();
9448 15 : if (bindings->nonPositionalFormalStart > 0) {
9449 : // |paramName| can be nullptr when the rest destructuring syntax is
9450 : // used: `function f(...[]) {}`.
9451 15 : JSAtom* paramName = bindings->names[bindings->nonPositionalFormalStart - 1].name();
9452 15 : return paramName && name == paramName;
9453 : }
9454 : }
9455 :
9456 0 : return false;
9457 : }
9458 :
9459 : bool
9460 22220 : BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
9461 : {
9462 22220 : bool callop = pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE);
9463 : /*
9464 : * Emit callable invocation or operator new (constructor call) code.
9465 : * First, emit code for the left operand to evaluate the callable or
9466 : * constructable object expression.
9467 : *
9468 : * For operator new, we emit JSOP_GETPROP instead of JSOP_CALLPROP, etc.
9469 : * This is necessary to interpose the lambda-initialized method read
9470 : * barrier -- see the code in jsinterp.cpp for JSOP_LAMBDA followed by
9471 : * JSOP_{SET,INIT}PROP.
9472 : *
9473 : * Then (or in a call case that has no explicit reference-base
9474 : * object) we emit JSOP_UNDEFINED to produce the undefined |this|
9475 : * value required for calls (which non-strict mode functions
9476 : * will box into the global object).
9477 : */
9478 22220 : uint32_t argc = pn->pn_count - 1;
9479 :
9480 22220 : if (argc >= ARGC_LIMIT) {
9481 0 : parser.reportError(callop ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
9482 0 : return false;
9483 : }
9484 :
9485 22220 : ParseNode* pn2 = pn->pn_head;
9486 22220 : bool spread = JOF_OPTYPE(pn->getOp()) == JOF_BYTE;
9487 22220 : switch (pn2->getKind()) {
9488 : case PNK_NAME:
9489 11039 : if (emitterMode == BytecodeEmitter::SelfHosting && !spread) {
9490 : // Calls to "forceInterpreter", "callFunction",
9491 : // "callContentFunction", or "resumeGenerator" in self-hosted
9492 : // code generate inline bytecode.
9493 25347 : if (pn2->name() == cx->names().callFunction ||
9494 16353 : pn2->name() == cx->names().callContentFunction ||
9495 7578 : pn2->name() == cx->names().constructContentFunction)
9496 : {
9497 1326 : return emitSelfHostedCallFunction(pn);
9498 : }
9499 7449 : if (pn2->name() == cx->names().resumeGenerator)
9500 27 : return emitSelfHostedResumeGenerator(pn);
9501 7422 : if (pn2->name() == cx->names().forceInterpreter)
9502 3 : return emitSelfHostedForceInterpreter(pn);
9503 7419 : if (pn2->name() == cx->names().allowContentIter)
9504 21 : return emitSelfHostedAllowContentIter(pn);
9505 7398 : if (pn2->name() == cx->names().defineDataPropertyIntrinsic && pn->pn_count == 4)
9506 183 : return emitSelfHostedDefineDataProperty(pn);
9507 7215 : if (pn2->name() == cx->names().hasOwn)
9508 51 : return emitSelfHostedHasOwn(pn);
9509 : // Fall through.
9510 : }
9511 9428 : if (!emitGetName(pn2, callop))
9512 0 : return false;
9513 9428 : break;
9514 : case PNK_DOT:
9515 11110 : MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
9516 11110 : if (pn2->as<PropertyAccess>().isSuper()) {
9517 13 : if (!emitSuperPropOp(pn2, JSOP_GETPROP_SUPER, /* isCall = */ callop))
9518 0 : return false;
9519 : } else {
9520 11097 : if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
9521 0 : return false;
9522 : }
9523 :
9524 11111 : break;
9525 : case PNK_ELEM:
9526 8 : MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
9527 8 : if (pn2->as<PropertyByValue>().isSuper()) {
9528 0 : if (!emitSuperElemOp(pn2, JSOP_GETELEM_SUPER, /* isCall = */ callop))
9529 0 : return false;
9530 : } else {
9531 8 : if (!emitElemOp(pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM))
9532 0 : return false;
9533 8 : if (callop) {
9534 8 : if (!emit1(JSOP_SWAP))
9535 0 : return false;
9536 : }
9537 : }
9538 :
9539 8 : break;
9540 : case PNK_FUNCTION:
9541 : /*
9542 : * Top level lambdas which are immediately invoked should be
9543 : * treated as only running once. Every time they execute we will
9544 : * create new types and scripts for their contents, to increase
9545 : * the quality of type information within them and enable more
9546 : * backend optimizations. Note that this does not depend on the
9547 : * lambda being invoked at most once (it may be named or be
9548 : * accessed via foo.caller indirection), as multiple executions
9549 : * will just cause the inner scripts to be repeatedly cloned.
9550 : */
9551 49 : MOZ_ASSERT(!emittingRunOnceLambda);
9552 49 : if (checkRunOnceContext()) {
9553 10 : emittingRunOnceLambda = true;
9554 10 : if (!emitTree(pn2))
9555 0 : return false;
9556 10 : emittingRunOnceLambda = false;
9557 : } else {
9558 39 : if (!emitTree(pn2))
9559 0 : return false;
9560 : }
9561 49 : callop = false;
9562 49 : break;
9563 : case PNK_SUPERBASE:
9564 13 : MOZ_ASSERT(pn->isKind(PNK_SUPERCALL));
9565 13 : MOZ_ASSERT(parser.isSuperBase(pn2));
9566 13 : if (!emit1(JSOP_SUPERFUN))
9567 0 : return false;
9568 13 : break;
9569 : default:
9570 1 : if (!emitTree(pn2))
9571 0 : return false;
9572 1 : callop = false; /* trigger JSOP_UNDEFINED after */
9573 1 : break;
9574 : }
9575 :
9576 59858 : bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
9577 59848 : pn->getOp() == JSOP_SUPERCALL || pn->getOp() == JSOP_SPREADSUPERCALL;
9578 :
9579 :
9580 : // Emit room for |this|.
9581 20610 : if (!callop) {
9582 1046 : if (isNewOp) {
9583 999 : if (!emit1(JSOP_IS_CONSTRUCTING))
9584 0 : return false;
9585 : } else {
9586 47 : if (!emit1(JSOP_UNDEFINED))
9587 0 : return false;
9588 : }
9589 : }
9590 :
9591 : /*
9592 : * Emit code for each argument in order, then emit the JSOP_*CALL or
9593 : * JSOP_NEW bytecode with a two-byte immediate telling how many args
9594 : * were pushed on the operand stack.
9595 : */
9596 20610 : if (!spread) {
9597 51265 : for (ParseNode* pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
9598 30702 : if (!emitTree(pn3))
9599 0 : return false;
9600 : }
9601 :
9602 20563 : if (isNewOp) {
9603 996 : if (pn->isKind(PNK_SUPERCALL)) {
9604 10 : if (!emit1(JSOP_NEWTARGET))
9605 0 : return false;
9606 : } else {
9607 : // Repush the callee as new.target
9608 986 : if (!emitDupAt(argc + 1))
9609 0 : return false;
9610 : }
9611 : }
9612 : } else {
9613 47 : ParseNode* args = pn2->pn_next;
9614 47 : bool emitOptCode = (argc == 1) && isRestParameter(args->pn_kid);
9615 94 : IfThenElseEmitter ifNotOptimizable(this);
9616 :
9617 47 : if (emitOptCode) {
9618 : // Emit a preparation code to optimize the spread call with a rest
9619 : // parameter:
9620 : //
9621 : // function f(...args) {
9622 : // g(...args);
9623 : // }
9624 : //
9625 : // If the spread operand is a rest parameter and it's optimizable
9626 : // array, skip spread operation and pass it directly to spread call
9627 : // operation. See the comment in OptimizeSpreadCall in
9628 : // Interpreter.cpp for the optimizable conditons.
9629 :
9630 15 : if (!emitTree(args->pn_kid))
9631 0 : return false;
9632 :
9633 15 : if (!emit1(JSOP_OPTIMIZE_SPREADCALL))
9634 0 : return false;
9635 :
9636 15 : if (!emit1(JSOP_NOT))
9637 0 : return false;
9638 :
9639 15 : if (!ifNotOptimizable.emitIf())
9640 0 : return false;
9641 :
9642 15 : if (!emit1(JSOP_POP))
9643 0 : return false;
9644 : }
9645 :
9646 47 : if (!emitArray(args, argc, JSOP_SPREADCALLARRAY))
9647 0 : return false;
9648 :
9649 47 : if (emitOptCode) {
9650 15 : if (!ifNotOptimizable.emitEnd())
9651 0 : return false;
9652 : }
9653 :
9654 47 : if (isNewOp) {
9655 3 : if (pn->isKind(PNK_SUPERCALL)) {
9656 3 : if (!emit1(JSOP_NEWTARGET))
9657 0 : return false;
9658 : } else {
9659 0 : if (!emitDupAt(2))
9660 0 : return false;
9661 : }
9662 : }
9663 : }
9664 :
9665 20610 : if (!spread) {
9666 20563 : if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
9667 7760 : if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
9668 0 : return false;
9669 7760 : checkTypeSet(JSOP_CALL_IGNORES_RV);
9670 : } else {
9671 12803 : if (!emitCall(pn->getOp(), argc, pn))
9672 0 : return false;
9673 12803 : checkTypeSet(pn->getOp());
9674 : }
9675 : } else {
9676 47 : if (!emit1(pn->getOp()))
9677 0 : return false;
9678 47 : checkTypeSet(pn->getOp());
9679 : }
9680 61828 : if (pn->isOp(JSOP_EVAL) ||
9681 41216 : pn->isOp(JSOP_STRICTEVAL) ||
9682 61826 : pn->isOp(JSOP_SPREADEVAL) ||
9683 20608 : pn->isOp(JSOP_STRICTSPREADEVAL))
9684 : {
9685 2 : uint32_t lineNum = parser.tokenStream().srcCoords.lineNum(pn->pn_pos.begin);
9686 2 : if (!emitUint32Operand(JSOP_LINENO, lineNum))
9687 0 : return false;
9688 : }
9689 :
9690 20610 : return true;
9691 : }
9692 :
9693 : bool
9694 0 : BytecodeEmitter::emitRightAssociative(ParseNode* pn)
9695 : {
9696 : // ** is the only right-associative operator.
9697 0 : MOZ_ASSERT(pn->isKind(PNK_POW));
9698 0 : MOZ_ASSERT(pn->isArity(PN_LIST));
9699 :
9700 : // Right-associative operator chain.
9701 0 : for (ParseNode* subexpr = pn->pn_head; subexpr; subexpr = subexpr->pn_next) {
9702 0 : if (!emitTree(subexpr))
9703 0 : return false;
9704 : }
9705 0 : for (uint32_t i = 0; i < pn->pn_count - 1; i++) {
9706 0 : if (!emit1(JSOP_POW))
9707 0 : return false;
9708 : }
9709 0 : return true;
9710 : }
9711 :
9712 : bool
9713 8175 : BytecodeEmitter::emitLeftAssociative(ParseNode* pn)
9714 : {
9715 8175 : MOZ_ASSERT(pn->isArity(PN_LIST));
9716 :
9717 : // Left-associative operator chain.
9718 8175 : if (!emitTree(pn->pn_head))
9719 0 : return false;
9720 8175 : JSOp op = pn->getOp();
9721 8175 : ParseNode* nextExpr = pn->pn_head->pn_next;
9722 8989 : do {
9723 8989 : if (!emitTree(nextExpr))
9724 0 : return false;
9725 8989 : if (!emit1(op))
9726 0 : return false;
9727 8989 : } while ((nextExpr = nextExpr->pn_next));
9728 8175 : return true;
9729 : }
9730 :
9731 : bool
9732 2022 : BytecodeEmitter::emitLogical(ParseNode* pn)
9733 : {
9734 2022 : MOZ_ASSERT(pn->isArity(PN_LIST));
9735 :
9736 : /*
9737 : * JSOP_OR converts the operand on the stack to boolean, leaves the original
9738 : * value on the stack and jumps if true; otherwise it falls into the next
9739 : * bytecode, which pops the left operand and then evaluates the right operand.
9740 : * The jump goes around the right operand evaluation.
9741 : *
9742 : * JSOP_AND converts the operand on the stack to boolean and jumps if false;
9743 : * otherwise it falls into the right operand's bytecode.
9744 : */
9745 :
9746 4045 : TDZCheckCache tdzCache(this);
9747 :
9748 : /* Left-associative operator chain: avoid too much recursion. */
9749 2022 : ParseNode* pn2 = pn->pn_head;
9750 2022 : if (!emitTree(pn2))
9751 0 : return false;
9752 2023 : JSOp op = pn->getOp();
9753 2023 : JumpList jump;
9754 2023 : if (!emitJump(op, &jump))
9755 0 : return false;
9756 2023 : if (!emit1(JSOP_POP))
9757 0 : return false;
9758 :
9759 : /* Emit nodes between the head and the tail. */
9760 2745 : while ((pn2 = pn2->pn_next)->pn_next) {
9761 361 : if (!emitTree(pn2))
9762 0 : return false;
9763 361 : if (!emitJump(op, &jump))
9764 0 : return false;
9765 361 : if (!emit1(JSOP_POP))
9766 0 : return false;
9767 : }
9768 2023 : if (!emitTree(pn2))
9769 0 : return false;
9770 :
9771 2023 : if (!emitJumpTargetAndPatch(jump))
9772 0 : return false;
9773 2023 : return true;
9774 : }
9775 :
9776 : bool
9777 10 : BytecodeEmitter::emitSequenceExpr(ParseNode* pn,
9778 : ValueUsage valueUsage /* = ValueUsage::WantValue */)
9779 : {
9780 23 : for (ParseNode* child = pn->pn_head; ; child = child->pn_next) {
9781 36 : if (!updateSourceCoordNotes(child->pn_pos.begin))
9782 0 : return false;
9783 23 : if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage))
9784 0 : return false;
9785 23 : if (!child->pn_next)
9786 10 : break;
9787 13 : if (!emit1(JSOP_POP))
9788 0 : return false;
9789 : }
9790 10 : return true;
9791 : }
9792 :
9793 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
9794 : // the comment on emitSwitch.
9795 : MOZ_NEVER_INLINE bool
9796 705 : BytecodeEmitter::emitIncOrDec(ParseNode* pn)
9797 : {
9798 705 : switch (pn->pn_kid->getKind()) {
9799 : case PNK_DOT:
9800 19 : return emitPropIncDec(pn);
9801 : case PNK_ELEM:
9802 12 : return emitElemIncDec(pn);
9803 : case PNK_CALL:
9804 0 : return emitCallIncDec(pn);
9805 : default:
9806 674 : return emitNameIncDec(pn);
9807 : }
9808 :
9809 : return true;
9810 : }
9811 :
9812 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
9813 : // the comment on emitSwitch.
9814 : MOZ_NEVER_INLINE bool
9815 0 : BytecodeEmitter::emitLabeledStatement(const LabeledStatement* pn)
9816 : {
9817 : /*
9818 : * Emit a JSOP_LABEL instruction. The argument is the offset to the statement
9819 : * following the labeled statement.
9820 : */
9821 : uint32_t index;
9822 0 : if (!makeAtomIndex(pn->label(), &index))
9823 0 : return false;
9824 :
9825 0 : JumpList top;
9826 0 : if (!emitJump(JSOP_LABEL, &top))
9827 0 : return false;
9828 :
9829 : /* Emit code for the labeled statement. */
9830 0 : LabelControl controlInfo(this, pn->label(), offset());
9831 :
9832 0 : if (!emitTree(pn->statement()))
9833 0 : return false;
9834 :
9835 : /* Patch the JSOP_LABEL offset. */
9836 0 : JumpTarget brk{ lastNonJumpTargetOffset() };
9837 0 : patchJumpsToTarget(top, brk);
9838 :
9839 0 : if (!controlInfo.patchBreaks(this))
9840 0 : return false;
9841 :
9842 0 : return true;
9843 : }
9844 :
9845 : bool
9846 657 : BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional,
9847 : ValueUsage valueUsage /* = ValueUsage::WantValue */)
9848 : {
9849 : /* Emit the condition, then branch if false to the else part. */
9850 657 : if (!emitTree(&conditional.condition()))
9851 0 : return false;
9852 :
9853 1314 : IfThenElseEmitter ifThenElse(this);
9854 657 : if (!ifThenElse.emitCond())
9855 0 : return false;
9856 :
9857 657 : if (!emitTreeInBranch(&conditional.thenExpression(), valueUsage))
9858 0 : return false;
9859 :
9860 657 : if (!ifThenElse.emitElse())
9861 0 : return false;
9862 :
9863 657 : if (!emitTreeInBranch(&conditional.elseExpression(), valueUsage))
9864 0 : return false;
9865 :
9866 657 : if (!ifThenElse.emitEnd())
9867 0 : return false;
9868 657 : MOZ_ASSERT(ifThenElse.pushed() == 1);
9869 :
9870 657 : return true;
9871 : }
9872 :
9873 : bool
9874 1672 : BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, PropListType type)
9875 : {
9876 7891 : for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) {
9877 6218 : if (!updateSourceCoordNotes(propdef->pn_pos.begin))
9878 0 : return false;
9879 :
9880 : // Handle __proto__: v specially because *only* this form, and no other
9881 : // involving "__proto__", performs [[Prototype]] mutation.
9882 6218 : if (propdef->isKind(PNK_MUTATEPROTO)) {
9883 38 : MOZ_ASSERT(type == ObjectLiteral);
9884 38 : if (!emitTree(propdef->pn_kid))
9885 0 : return false;
9886 38 : objp.set(nullptr);
9887 38 : if (!emit1(JSOP_MUTATEPROTO))
9888 0 : return false;
9889 38 : continue;
9890 : }
9891 :
9892 6180 : if (propdef->isKind(PNK_SPREAD)) {
9893 0 : MOZ_ASSERT(type == ObjectLiteral);
9894 :
9895 0 : if (!emit1(JSOP_DUP))
9896 0 : return false;
9897 :
9898 0 : if (!emitTree(propdef->pn_kid))
9899 0 : return false;
9900 :
9901 0 : if (!emitCopyDataProperties(CopyOption::Unfiltered))
9902 0 : return false;
9903 :
9904 0 : objp.set(nullptr);
9905 0 : continue;
9906 : }
9907 :
9908 6180 : bool extraPop = false;
9909 6180 : if (type == ClassBody && propdef->as<ClassMethod>().isStatic()) {
9910 4 : extraPop = true;
9911 4 : if (!emit1(JSOP_DUP2))
9912 0 : return false;
9913 4 : if (!emit1(JSOP_POP))
9914 0 : return false;
9915 : }
9916 :
9917 : /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
9918 6180 : ParseNode* key = propdef->pn_left;
9919 6180 : bool isIndex = false;
9920 6180 : if (key->isKind(PNK_NUMBER)) {
9921 26 : if (!emitNumberOp(key->pn_dval))
9922 0 : return false;
9923 26 : isIndex = true;
9924 6154 : } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) {
9925 : // EmitClass took care of constructor already.
9926 6180 : if (type == ClassBody && key->pn_atom == cx->names().constructor &&
9927 31 : !propdef->as<ClassMethod>().isStatic())
9928 : {
9929 31 : continue;
9930 : }
9931 : } else {
9932 5 : if (!emitComputedPropertyName(key))
9933 0 : return false;
9934 5 : isIndex = true;
9935 : }
9936 :
9937 : /* Emit code for the property initializer. */
9938 6149 : if (!emitTree(propdef->pn_right))
9939 0 : return false;
9940 :
9941 6150 : JSOp op = propdef->getOp();
9942 6150 : MOZ_ASSERT(op == JSOP_INITPROP ||
9943 : op == JSOP_INITPROP_GETTER ||
9944 : op == JSOP_INITPROP_SETTER);
9945 :
9946 11992 : FunctionPrefixKind prefixKind = op == JSOP_INITPROP_GETTER ? FunctionPrefixKind::Get
9947 5842 : : op == JSOP_INITPROP_SETTER ? FunctionPrefixKind::Set
9948 6150 : : FunctionPrefixKind::None;
9949 :
9950 6150 : if (op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER)
9951 350 : objp.set(nullptr);
9952 :
9953 8975 : if (propdef->pn_right->isKind(PNK_FUNCTION) &&
9954 2825 : propdef->pn_right->pn_funbox->needsHomeObject())
9955 : {
9956 7 : MOZ_ASSERT(propdef->pn_right->pn_funbox->function()->allowSuperProperty());
9957 7 : bool isAsync = propdef->pn_right->pn_funbox->isAsync();
9958 7 : if (isAsync) {
9959 0 : if (!emit1(JSOP_SWAP))
9960 0 : return false;
9961 : }
9962 7 : if (!emit2(JSOP_INITHOMEOBJECT, isIndex + isAsync))
9963 0 : return false;
9964 7 : if (isAsync) {
9965 0 : if (!emit1(JSOP_POP))
9966 0 : return false;
9967 : }
9968 : }
9969 :
9970 : // Class methods are not enumerable.
9971 6150 : if (type == ClassBody) {
9972 125 : switch (op) {
9973 111 : case JSOP_INITPROP: op = JSOP_INITHIDDENPROP; break;
9974 13 : case JSOP_INITPROP_GETTER: op = JSOP_INITHIDDENPROP_GETTER; break;
9975 1 : case JSOP_INITPROP_SETTER: op = JSOP_INITHIDDENPROP_SETTER; break;
9976 0 : default: MOZ_CRASH("Invalid op");
9977 : }
9978 : }
9979 :
9980 6150 : if (isIndex) {
9981 31 : objp.set(nullptr);
9982 31 : switch (op) {
9983 31 : case JSOP_INITPROP: op = JSOP_INITELEM; break;
9984 0 : case JSOP_INITHIDDENPROP: op = JSOP_INITHIDDENELEM; break;
9985 0 : case JSOP_INITPROP_GETTER: op = JSOP_INITELEM_GETTER; break;
9986 0 : case JSOP_INITHIDDENPROP_GETTER: op = JSOP_INITHIDDENELEM_GETTER; break;
9987 0 : case JSOP_INITPROP_SETTER: op = JSOP_INITELEM_SETTER; break;
9988 0 : case JSOP_INITHIDDENPROP_SETTER: op = JSOP_INITHIDDENELEM_SETTER; break;
9989 0 : default: MOZ_CRASH("Invalid op");
9990 : }
9991 31 : if (propdef->pn_right->isDirectRHSAnonFunction()) {
9992 0 : if (!emitDupAt(1))
9993 0 : return false;
9994 0 : if (!emit2(JSOP_SETFUNNAME, uint8_t(prefixKind)))
9995 0 : return false;
9996 : }
9997 31 : if (!emit1(op))
9998 0 : return false;
9999 : } else {
10000 6119 : MOZ_ASSERT(key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING));
10001 :
10002 : uint32_t index;
10003 6119 : if (!makeAtomIndex(key->pn_atom, &index))
10004 0 : return false;
10005 :
10006 6119 : if (objp) {
10007 4600 : MOZ_ASSERT(type == ObjectLiteral);
10008 4600 : MOZ_ASSERT(!IsHiddenInitOp(op));
10009 4600 : MOZ_ASSERT(!objp->inDictionaryMode());
10010 9200 : Rooted<jsid> id(cx, AtomToId(key->pn_atom));
10011 4600 : if (!NativeDefineProperty(cx, objp, id, UndefinedHandleValue, nullptr, nullptr,
10012 : JSPROP_ENUMERATE))
10013 : {
10014 0 : return false;
10015 : }
10016 4600 : if (objp->inDictionaryMode())
10017 0 : objp.set(nullptr);
10018 : }
10019 :
10020 6119 : if (propdef->pn_right->isDirectRHSAnonFunction()) {
10021 510 : RootedAtom keyName(cx, key->pn_atom);
10022 255 : if (!setOrEmitSetFunName(propdef->pn_right, keyName, prefixKind))
10023 0 : return false;
10024 : }
10025 6119 : if (!emitIndex32(op, index))
10026 0 : return false;
10027 : }
10028 :
10029 6150 : if (extraPop) {
10030 4 : if (!emit1(JSOP_POP))
10031 0 : return false;
10032 : }
10033 : }
10034 1673 : return true;
10035 : }
10036 :
10037 : // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
10038 : // the comment on emitSwitch.
10039 : MOZ_NEVER_INLINE bool
10040 1669 : BytecodeEmitter::emitObject(ParseNode* pn)
10041 : {
10042 1669 : if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && checkSingletonContext())
10043 29 : return emitSingletonInitialiser(pn);
10044 :
10045 : /*
10046 : * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
10047 : * a new object and defining (in source order) each property on the object
10048 : * (or mutating the object's [[Prototype]], in the case of __proto__).
10049 : */
10050 1640 : ptrdiff_t offset = this->offset();
10051 1640 : if (!emitNewInit(JSProto_Object))
10052 0 : return false;
10053 :
10054 : // Try to construct the shape of the object as we go, so we can emit a
10055 : // JSOP_NEWOBJECT with the final shape instead.
10056 : // In the case of computed property names and indices, we cannot fix the
10057 : // shape at bytecode compile time. When the shape cannot be determined,
10058 : // |obj| is nulled out.
10059 :
10060 : // No need to do any guessing for the object kind, since we know the upper
10061 : // bound of how many properties we plan to have.
10062 1640 : gc::AllocKind kind = gc::GetGCObjectKind(pn->pn_count);
10063 3281 : RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
10064 1640 : if (!obj)
10065 0 : return false;
10066 :
10067 1640 : if (!emitPropertyList(pn, &obj, ObjectLiteral))
10068 0 : return false;
10069 :
10070 1641 : if (obj) {
10071 : // The object survived and has a predictable shape: update the original
10072 : // bytecode.
10073 1487 : if (!replaceNewInitWithNewObject(obj, offset))
10074 0 : return false;
10075 : }
10076 :
10077 1641 : return true;
10078 : }
10079 :
10080 : bool
10081 1487 : BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset)
10082 : {
10083 1487 : ObjectBox* objbox = parser.newObjectBox(obj);
10084 1487 : if (!objbox)
10085 0 : return false;
10086 :
10087 : static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
10088 : "newinit and newobject must have equal length to edit in-place");
10089 :
10090 1487 : uint32_t index = objectList.add(objbox);
10091 1487 : jsbytecode* code = this->code(offset);
10092 :
10093 1487 : MOZ_ASSERT(code[0] == JSOP_NEWINIT);
10094 1487 : code[0] = JSOP_NEWOBJECT;
10095 1487 : code[1] = jsbytecode(index >> 24);
10096 1487 : code[2] = jsbytecode(index >> 16);
10097 1487 : code[3] = jsbytecode(index >> 8);
10098 1487 : code[4] = jsbytecode(index);
10099 :
10100 1487 : return true;
10101 : }
10102 :
10103 : bool
10104 0 : BytecodeEmitter::emitArrayComp(ParseNode* pn)
10105 : {
10106 0 : if (!emitNewInit(JSProto_Array))
10107 0 : return false;
10108 :
10109 : /*
10110 : * Pass the new array's stack index to the PNK_ARRAYPUSH case via
10111 : * arrayCompDepth, then simply traverse the PNK_FOR node and
10112 : * its kids under pn2 to generate this comprehension.
10113 : */
10114 0 : MOZ_ASSERT(stackDepth > 0);
10115 0 : uint32_t saveDepth = arrayCompDepth;
10116 0 : arrayCompDepth = (uint32_t) (stackDepth - 1);
10117 0 : if (!emitTree(pn->pn_head))
10118 0 : return false;
10119 0 : arrayCompDepth = saveDepth;
10120 :
10121 0 : return true;
10122 : }
10123 :
10124 : bool
10125 1212 : BytecodeEmitter::emitArrayLiteral(ParseNode* pn)
10126 : {
10127 1212 : if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head) {
10128 557 : if (checkSingletonContext()) {
10129 : // Bake in the object entirely if it will only be created once.
10130 12 : return emitSingletonInitialiser(pn);
10131 : }
10132 :
10133 : // If the array consists entirely of primitive values, make a
10134 : // template object with copy on write elements that can be reused
10135 : // every time the initializer executes.
10136 545 : if (emitterMode != BytecodeEmitter::SelfHosting && pn->pn_count != 0) {
10137 459 : RootedValue value(cx);
10138 452 : if (!pn->getConstantValue(cx, ParseNode::ForCopyOnWriteArray, &value))
10139 0 : return false;
10140 453 : if (!value.isMagic(JS_GENERIC_MAGIC)) {
10141 : // Note: the group of the template object might not yet reflect
10142 : // that the object has copy on write elements. When the
10143 : // interpreter or JIT compiler fetches the template, it should
10144 : // use ObjectGroup::getOrFixupCopyOnWriteObject to make sure the
10145 : // group for the template is accurate. We don't do this here as we
10146 : // want to use ObjectGroup::allocationSiteGroup, which requires a
10147 : // finished script.
10148 446 : JSObject* obj = &value.toObject();
10149 446 : MOZ_ASSERT(obj->is<ArrayObject>() &&
10150 : obj->as<ArrayObject>().denseElementsAreCopyOnWrite());
10151 :
10152 446 : ObjectBox* objbox = parser.newObjectBox(obj);
10153 446 : if (!objbox)
10154 0 : return false;
10155 :
10156 446 : return emitObjectOp(objbox, JSOP_NEWARRAY_COPYONWRITE);
10157 : }
10158 : }
10159 : }
10160 :
10161 755 : return emitArray(pn->pn_head, pn->pn_count, JSOP_NEWARRAY);
10162 : }
10163 :
10164 : bool
10165 802 : BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
10166 : {
10167 :
10168 : /*
10169 : * Emit code for [a, b, c] that is equivalent to constructing a new
10170 : * array and in source order evaluating each element value and adding
10171 : * it to the array, without invoking latent setters. We use the
10172 : * JSOP_NEWINIT and JSOP_INITELEM_ARRAY bytecodes to ignore setters and
10173 : * to avoid dup'ing and popping the array as each element is added, as
10174 : * JSOP_SETELEM/JSOP_SETPROP would do.
10175 : */
10176 802 : MOZ_ASSERT(op == JSOP_NEWARRAY || op == JSOP_SPREADCALLARRAY);
10177 :
10178 802 : uint32_t nspread = 0;
10179 2182 : for (ParseNode* elt = pn; elt; elt = elt->pn_next) {
10180 1380 : if (elt->isKind(PNK_SPREAD))
10181 58 : nspread++;
10182 : }
10183 :
10184 : // Array literal's length is limited to NELEMENTS_LIMIT in parser.
10185 : static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT <= INT32_MAX,
10186 : "array literals' maximum length must not exceed limits "
10187 : "required by BaselineCompiler::emit_JSOP_NEWARRAY, "
10188 : "BaselineCompiler::emit_JSOP_INITELEM_ARRAY, "
10189 : "and DoSetElemFallback's handling of JSOP_INITELEM_ARRAY");
10190 802 : MOZ_ASSERT(count >= nspread);
10191 802 : MOZ_ASSERT(count <= NativeObject::MAX_DENSE_ELEMENTS_COUNT,
10192 : "the parser must throw an error if the array exceeds maximum "
10193 : "length");
10194 :
10195 : // For arrays with spread, this is a very pessimistic allocation, the
10196 : // minimum possible final size.
10197 802 : if (!emitUint32Operand(op, count - nspread)) // ARRAY
10198 0 : return false;
10199 :
10200 802 : ParseNode* pn2 = pn;
10201 : uint32_t index;
10202 802 : bool afterSpread = false;
10203 2182 : for (index = 0; pn2; index++, pn2 = pn2->pn_next) {
10204 1380 : if (!afterSpread && pn2->isKind(PNK_SPREAD)) {
10205 56 : afterSpread = true;
10206 56 : if (!emitNumberOp(index)) // ARRAY INDEX
10207 0 : return false;
10208 : }
10209 1380 : if (!updateSourceCoordNotes(pn2->pn_pos.begin))
10210 0 : return false;
10211 :
10212 1380 : bool allowSelfHostedIter = false;
10213 1380 : if (pn2->isKind(PNK_ELISION)) {
10214 0 : if (!emit1(JSOP_HOLE))
10215 0 : return false;
10216 : } else {
10217 : ParseNode* expr;
10218 1380 : if (pn2->isKind(PNK_SPREAD)) {
10219 58 : expr = pn2->pn_kid;
10220 :
10221 119 : if (emitterMode == BytecodeEmitter::SelfHosting &&
10222 61 : expr->isKind(PNK_CALL) &&
10223 3 : expr->pn_head->name() == cx->names().allowContentIter)
10224 : {
10225 3 : allowSelfHostedIter = true;
10226 : }
10227 : } else {
10228 1322 : expr = pn2;
10229 : }
10230 1380 : if (!emitTree(expr)) // ARRAY INDEX? VALUE
10231 0 : return false;
10232 : }
10233 1380 : if (pn2->isKind(PNK_SPREAD)) {
10234 58 : if (!emitIterator()) // ARRAY INDEX ITER
10235 0 : return false;
10236 58 : if (!emit2(JSOP_PICK, 2)) // INDEX ITER ARRAY
10237 0 : return false;
10238 58 : if (!emit2(JSOP_PICK, 2)) // ITER ARRAY INDEX
10239 0 : return false;
10240 58 : if (!emitSpread(allowSelfHostedIter)) // ARRAY INDEX
10241 0 : return false;
10242 1322 : } else if (afterSpread) {
10243 2 : if (!emit1(JSOP_INITELEM_INC))
10244 0 : return false;
10245 : } else {
10246 1320 : if (!emitUint32Operand(JSOP_INITELEM_ARRAY, index))
10247 0 : return false;
10248 : }
10249 : }
10250 802 : MOZ_ASSERT(index == count);
10251 802 : if (afterSpread) {
10252 56 : if (!emit1(JSOP_POP)) // ARRAY
10253 0 : return false;
10254 : }
10255 802 : return true;
10256 : }
10257 :
10258 : bool
10259 3393 : BytecodeEmitter::emitUnary(ParseNode* pn)
10260 : {
10261 3393 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
10262 0 : return false;
10263 :
10264 : /* Unary op, including unary +/-. */
10265 3393 : JSOp op = pn->getOp();
10266 3393 : ParseNode* pn2 = pn->pn_kid;
10267 :
10268 3393 : if (!emitTree(pn2))
10269 0 : return false;
10270 :
10271 3394 : return emit1(op);
10272 : }
10273 :
10274 : bool
10275 502 : BytecodeEmitter::emitTypeof(ParseNode* node, JSOp op)
10276 : {
10277 502 : MOZ_ASSERT(op == JSOP_TYPEOF || op == JSOP_TYPEOFEXPR);
10278 :
10279 502 : if (!updateSourceCoordNotes(node->pn_pos.begin))
10280 0 : return false;
10281 :
10282 502 : if (!emitTree(node->pn_kid))
10283 0 : return false;
10284 :
10285 502 : return emit1(op);
10286 : }
10287 :
10288 : bool
10289 5404 : BytecodeEmitter::emitFunctionFormalParametersAndBody(ParseNode *pn)
10290 : {
10291 5404 : MOZ_ASSERT(pn->isKind(PNK_PARAMSBODY));
10292 :
10293 5404 : ParseNode* funBody = pn->last();
10294 5404 : FunctionBox* funbox = sc->asFunctionBox();
10295 :
10296 10809 : TDZCheckCache tdzCache(this);
10297 :
10298 5404 : if (funbox->hasParameterExprs) {
10299 366 : EmitterScope funEmitterScope(this);
10300 183 : if (!funEmitterScope.enterFunction(this, funbox))
10301 0 : return false;
10302 :
10303 183 : if (!emitInitializeFunctionSpecialNames())
10304 0 : return false;
10305 :
10306 183 : if (!emitFunctionFormalParameters(pn))
10307 0 : return false;
10308 :
10309 : {
10310 366 : Maybe<EmitterScope> extraVarEmitterScope;
10311 :
10312 183 : if (funbox->hasExtraBodyVarScope()) {
10313 104 : extraVarEmitterScope.emplace(this);
10314 104 : if (!extraVarEmitterScope->enterFunctionExtraBodyVar(this, funbox))
10315 0 : return false;
10316 :
10317 : // After emitting expressions for all parameters, copy over any
10318 : // formal parameters which have been redeclared as vars. For
10319 : // example, in the following, the var y in the body scope is 42:
10320 : //
10321 : // function f(x, y = 42) { var y; }
10322 : //
10323 208 : RootedAtom name(cx);
10324 104 : if (funbox->extraVarScopeBindings() && funbox->functionScopeBindings()) {
10325 445 : for (BindingIter bi(*funbox->functionScopeBindings(), true); bi; bi++) {
10326 341 : name = bi.name();
10327 :
10328 : // There may not be a var binding of the same name.
10329 341 : if (!locationOfNameBoundInScope(name, extraVarEmitterScope.ptr()))
10330 341 : continue;
10331 :
10332 : // The '.this' and '.generator' function special
10333 : // bindings should never appear in the extra var
10334 : // scope. 'arguments', however, may.
10335 0 : MOZ_ASSERT(name != cx->names().dotThis &&
10336 : name != cx->names().dotGenerator);
10337 :
10338 0 : NameLocation paramLoc = *locationOfNameBoundInScope(name, &funEmitterScope);
10339 : auto emitRhs = [&name, ¶mLoc](BytecodeEmitter* bce,
10340 0 : const NameLocation&, bool)
10341 0 : {
10342 0 : return bce->emitGetNameAtLocation(name, paramLoc);
10343 0 : };
10344 :
10345 0 : if (!emitInitializeName(name, emitRhs))
10346 0 : return false;
10347 0 : if (!emit1(JSOP_POP))
10348 0 : return false;
10349 : }
10350 : }
10351 : }
10352 :
10353 183 : if (!emitFunctionBody(funBody))
10354 0 : return false;
10355 :
10356 183 : if (extraVarEmitterScope && !extraVarEmitterScope->leave(this))
10357 0 : return false;
10358 : }
10359 :
10360 183 : return funEmitterScope.leave(this);
10361 : }
10362 :
10363 : // No parameter expressions. Enter the function body scope and emit
10364 : // everything.
10365 : //
10366 : // One caveat is that Debugger considers ops in the prologue to be
10367 : // unreachable (i.e. cannot set a breakpoint on it). If there are no
10368 : // parameter exprs, any unobservable environment ops (like pushing the
10369 : // call object, setting '.this', etc) need to go in the prologue, else it
10370 : // messes up breakpoint tests.
10371 10443 : EmitterScope emitterScope(this);
10372 :
10373 5221 : switchToPrologue();
10374 5221 : if (!emitterScope.enterFunction(this, funbox))
10375 0 : return false;
10376 :
10377 5221 : if (!emitInitializeFunctionSpecialNames())
10378 0 : return false;
10379 5221 : switchToMain();
10380 :
10381 5221 : if (!emitFunctionFormalParameters(pn))
10382 0 : return false;
10383 :
10384 5221 : if (!emitFunctionBody(funBody))
10385 0 : return false;
10386 :
10387 5222 : return emitterScope.leave(this);
10388 : }
10389 :
10390 : bool
10391 5404 : BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
10392 : {
10393 5404 : ParseNode* funBody = pn->last();
10394 5404 : FunctionBox* funbox = sc->asFunctionBox();
10395 5404 : EmitterScope* funScope = innermostEmitterScope;
10396 :
10397 5404 : bool hasParameterExprs = funbox->hasParameterExprs;
10398 5404 : bool hasRest = funbox->hasRest();
10399 :
10400 5404 : uint16_t argSlot = 0;
10401 11799 : for (ParseNode* arg = pn->pn_head; arg != funBody; arg = arg->pn_next, argSlot++) {
10402 6395 : ParseNode* bindingElement = arg;
10403 6395 : ParseNode* initializer = nullptr;
10404 6395 : if (arg->isKind(PNK_ASSIGN)) {
10405 213 : bindingElement = arg->pn_left;
10406 213 : initializer = arg->pn_right;
10407 : }
10408 :
10409 : // Left-hand sides are either simple names or destructuring patterns.
10410 6395 : MOZ_ASSERT(bindingElement->isKind(PNK_NAME) ||
10411 : bindingElement->isKind(PNK_ARRAY) ||
10412 : bindingElement->isKind(PNK_ARRAYCOMP) ||
10413 : bindingElement->isKind(PNK_OBJECT));
10414 :
10415 : // The rest parameter doesn't have an initializer.
10416 6395 : bool isRest = hasRest && arg->pn_next == funBody;
10417 6395 : MOZ_ASSERT_IF(isRest, !initializer);
10418 :
10419 6395 : bool isDestructuring = !bindingElement->isKind(PNK_NAME);
10420 :
10421 : // ES 14.1.19 says if BindingElement contains an expression in the
10422 : // production FormalParameter : BindingElement, it is evaluated in a
10423 : // new var environment. This is needed to prevent vars from escaping
10424 : // direct eval in parameter expressions.
10425 12790 : Maybe<EmitterScope> paramExprVarScope;
10426 6395 : if (funbox->hasDirectEvalInParameterExpr && (isDestructuring || initializer)) {
10427 0 : paramExprVarScope.emplace(this);
10428 0 : if (!paramExprVarScope->enterParameterExpressionVar(this))
10429 0 : return false;
10430 : }
10431 :
10432 : // First push the RHS if there is a default expression or if it is
10433 : // rest.
10434 :
10435 6395 : if (initializer) {
10436 : // If we have an initializer, emit the initializer and assign it
10437 : // to the argument slot. TDZ is taken care of afterwards.
10438 213 : MOZ_ASSERT(hasParameterExprs);
10439 213 : if (!emitArgOp(JSOP_GETARG, argSlot))
10440 0 : return false;
10441 213 : if (!emit1(JSOP_DUP))
10442 0 : return false;
10443 213 : if (!emit1(JSOP_UNDEFINED))
10444 0 : return false;
10445 213 : if (!emit1(JSOP_STRICTEQ))
10446 0 : return false;
10447 : // Emit source note to enable Ion compilation.
10448 213 : if (!newSrcNote(SRC_IF))
10449 0 : return false;
10450 213 : JumpList jump;
10451 213 : if (!emitJump(JSOP_IFEQ, &jump))
10452 0 : return false;
10453 213 : if (!emit1(JSOP_POP))
10454 0 : return false;
10455 213 : if (!emitInitializerInBranch(initializer, bindingElement))
10456 0 : return false;
10457 213 : if (!emitJumpTargetAndPatch(jump))
10458 0 : return false;
10459 6182 : } else if (isRest) {
10460 62 : if (!emit1(JSOP_REST))
10461 0 : return false;
10462 62 : checkTypeSet(JSOP_REST);
10463 : }
10464 :
10465 : // Initialize the parameter name.
10466 :
10467 6395 : if (isDestructuring) {
10468 : // If we had an initializer or the rest parameter, the value is
10469 : // already on the stack.
10470 42 : if (!initializer && !isRest && !emitArgOp(JSOP_GETARG, argSlot))
10471 0 : return false;
10472 :
10473 : // If there's an parameter expression var scope, the destructuring
10474 : // declaration needs to initialize the name in the function scope,
10475 : // which is not the innermost scope.
10476 42 : if (!emitDestructuringOps(bindingElement,
10477 : paramExprVarScope
10478 : ? DestructuringFormalParameterInVarScope
10479 42 : : DestructuringDeclaration))
10480 : {
10481 0 : return false;
10482 : }
10483 :
10484 42 : if (!emit1(JSOP_POP))
10485 0 : return false;
10486 : } else {
10487 12706 : RootedAtom paramName(cx, bindingElement->name());
10488 6353 : NameLocation paramLoc = *locationOfNameBoundInScope(paramName, funScope);
10489 :
10490 6353 : if (hasParameterExprs) {
10491 : auto emitRhs = [argSlot, initializer, isRest](BytecodeEmitter* bce,
10492 430 : const NameLocation&, bool)
10493 864 : {
10494 : // If we had an initializer or a rest parameter, the value is
10495 : // already on the stack.
10496 647 : if (!initializer && !isRest)
10497 217 : return bce->emitArgOp(JSOP_GETARG, argSlot);
10498 213 : return true;
10499 430 : };
10500 :
10501 430 : if (!emitSetOrInitializeNameAtLocation(paramName, paramLoc, emitRhs, true))
10502 0 : return false;
10503 430 : if (!emit1(JSOP_POP))
10504 0 : return false;
10505 5923 : } else if (isRest) {
10506 : // The rest value is already on top of the stack.
10507 62 : auto nop = [](BytecodeEmitter*, const NameLocation&, bool) {
10508 : return true;
10509 62 : };
10510 :
10511 62 : if (!emitSetOrInitializeNameAtLocation(paramName, paramLoc, nop, true))
10512 0 : return false;
10513 62 : if (!emit1(JSOP_POP))
10514 0 : return false;
10515 : }
10516 : }
10517 :
10518 6395 : if (paramExprVarScope) {
10519 0 : if (!paramExprVarScope->leave(this))
10520 0 : return false;
10521 : }
10522 : }
10523 :
10524 5404 : return true;
10525 : }
10526 :
10527 : bool
10528 5404 : BytecodeEmitter::emitInitializeFunctionSpecialNames()
10529 : {
10530 5404 : FunctionBox* funbox = sc->asFunctionBox();
10531 :
10532 : auto emitInitializeFunctionSpecialName = [](BytecodeEmitter* bce, HandlePropertyName name,
10533 2498 : JSOp op)
10534 : {
10535 : // A special name must be slotful, either on the frame or on the
10536 : // call environment.
10537 2498 : MOZ_ASSERT(bce->lookupName(name).hasKnownSlot());
10538 :
10539 2498 : auto emitInitial = [op](BytecodeEmitter* bce, const NameLocation&, bool) {
10540 : return bce->emit1(op);
10541 4996 : };
10542 :
10543 2498 : if (!bce->emitInitializeName(name, emitInitial))
10544 0 : return false;
10545 2498 : if (!bce->emit1(JSOP_POP))
10546 0 : return false;
10547 :
10548 2498 : return true;
10549 : };
10550 :
10551 : // Do nothing if the function doesn't have an arguments binding.
10552 5404 : if (funbox->argumentsHasLocalBinding()) {
10553 264 : if (!emitInitializeFunctionSpecialName(this, cx->names().arguments, JSOP_ARGUMENTS))
10554 0 : return false;
10555 : }
10556 :
10557 : // Do nothing if the function doesn't have a this-binding (this
10558 : // happens for instance if it doesn't use this/eval or if it's an
10559 : // arrow function).
10560 5404 : if (funbox->hasThisBinding()) {
10561 2234 : if (!emitInitializeFunctionSpecialName(this, cx->names().dotThis, JSOP_FUNCTIONTHIS))
10562 0 : return false;
10563 : }
10564 :
10565 5404 : return true;
10566 : }
10567 :
10568 : bool
10569 5404 : BytecodeEmitter::emitFunctionBody(ParseNode* funBody)
10570 : {
10571 5404 : FunctionBox* funbox = sc->asFunctionBox();
10572 :
10573 5404 : if (!emitTree(funBody))
10574 0 : return false;
10575 :
10576 5405 : if (funbox->needsFinalYield()) {
10577 : // If we fall off the end of a generator, do a final yield.
10578 127 : bool needsIteratorResult = funbox->needsIteratorResult();
10579 127 : if (needsIteratorResult) {
10580 15 : if (!emitPrepareIteratorResult())
10581 0 : return false;
10582 : }
10583 :
10584 127 : if (!emit1(JSOP_UNDEFINED))
10585 0 : return false;
10586 :
10587 127 : if (needsIteratorResult) {
10588 15 : if (!emitFinishIteratorResult(true))
10589 0 : return false;
10590 : }
10591 :
10592 127 : if (!emit1(JSOP_SETRVAL))
10593 0 : return false;
10594 :
10595 127 : if (!emitGetDotGenerator())
10596 0 : return false;
10597 :
10598 : // No need to check for finally blocks, etc as in EmitReturn.
10599 127 : if (!emitYieldOp(JSOP_FINALYIELDRVAL))
10600 0 : return false;
10601 : } else {
10602 : // Non-generator functions just return |undefined|. The
10603 : // JSOP_RETRVAL emitted below will do that, except if the
10604 : // script has a finally block: there can be a non-undefined
10605 : // value in the return value slot. Make sure the return value
10606 : // is |undefined|.
10607 5278 : if (hasTryFinally) {
10608 23 : if (!emit1(JSOP_UNDEFINED))
10609 0 : return false;
10610 23 : if (!emit1(JSOP_SETRVAL))
10611 0 : return false;
10612 : }
10613 : }
10614 :
10615 5405 : if (funbox->isDerivedClassConstructor()) {
10616 13 : if (!emitCheckDerivedClassConstructorReturn())
10617 0 : return false;
10618 : }
10619 :
10620 5405 : return true;
10621 : }
10622 :
10623 : bool
10624 519 : BytecodeEmitter::emitLexicalInitialization(ParseNode* pn)
10625 : {
10626 : // The caller has pushed the RHS to the top of the stack. Assert that the
10627 : // name is lexical and no BIND[G]NAME ops were emitted.
10628 519 : auto assertLexical = [](BytecodeEmitter*, const NameLocation& loc, bool emittedBindOp) {
10629 519 : MOZ_ASSERT(loc.isLexical());
10630 519 : MOZ_ASSERT(!emittedBindOp);
10631 519 : return true;
10632 : };
10633 519 : return emitInitializeName(pn, assertLexical);
10634 : }
10635 :
10636 : // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
10637 : // (BindingClassDeclarationEvaluation).
10638 : bool
10639 32 : BytecodeEmitter::emitClass(ParseNode* pn)
10640 : {
10641 32 : ClassNode& classNode = pn->as<ClassNode>();
10642 :
10643 32 : ClassNames* names = classNode.names();
10644 :
10645 32 : ParseNode* heritageExpression = classNode.heritage();
10646 :
10647 32 : ParseNode* classMethods = classNode.methodList();
10648 32 : ParseNode* constructor = nullptr;
10649 32 : for (ParseNode* mn = classMethods->pn_head; mn; mn = mn->pn_next) {
10650 31 : ClassMethod& method = mn->as<ClassMethod>();
10651 31 : ParseNode& methodName = method.name();
10652 93 : if (!method.isStatic() &&
10653 62 : (methodName.isKind(PNK_OBJECT_PROPERTY_NAME) || methodName.isKind(PNK_STRING)) &&
10654 31 : methodName.pn_atom == cx->names().constructor)
10655 : {
10656 31 : constructor = &method.method();
10657 31 : break;
10658 : }
10659 : }
10660 :
10661 32 : bool savedStrictness = sc->setLocalStrictMode(true);
10662 :
10663 64 : Maybe<TDZCheckCache> tdzCache;
10664 64 : Maybe<EmitterScope> emitterScope;
10665 32 : if (names) {
10666 26 : tdzCache.emplace(this);
10667 26 : emitterScope.emplace(this);
10668 26 : if (!emitterScope->enterLexical(this, ScopeKind::Lexical, classNode.scopeBindings()))
10669 0 : return false;
10670 : }
10671 :
10672 : // Pseudocode for class declarations:
10673 : //
10674 : // class extends BaseExpression {
10675 : // constructor() { ... }
10676 : // ...
10677 : // }
10678 : //
10679 : //
10680 : // if defined <BaseExpression> {
10681 : // let heritage = BaseExpression;
10682 : //
10683 : // if (heritage !== null) {
10684 : // funProto = heritage;
10685 : // objProto = heritage.prototype;
10686 : // } else {
10687 : // funProto = %FunctionPrototype%;
10688 : // objProto = null;
10689 : // }
10690 : // } else {
10691 : // objProto = %ObjectPrototype%;
10692 : // }
10693 : //
10694 : // let homeObject = ObjectCreate(objProto);
10695 : //
10696 : // if defined <constructor> {
10697 : // if defined <BaseExpression> {
10698 : // cons = DefineMethod(<constructor>, proto=homeObject, funProto=funProto);
10699 : // } else {
10700 : // cons = DefineMethod(<constructor>, proto=homeObject);
10701 : // }
10702 : // } else {
10703 : // if defined <BaseExpression> {
10704 : // cons = DefaultDerivedConstructor(proto=homeObject, funProto=funProto);
10705 : // } else {
10706 : // cons = DefaultConstructor(proto=homeObject);
10707 : // }
10708 : // }
10709 : //
10710 : // cons.prototype = homeObject;
10711 : // homeObject.constructor = cons;
10712 : //
10713 : // EmitPropertyList(...)
10714 :
10715 : // This is kind of silly. In order to the get the home object defined on
10716 : // the constructor, we have to make it second, but we want the prototype
10717 : // on top for EmitPropertyList, because we expect static properties to be
10718 : // rarer. The result is a few more swaps than we would like. Such is life.
10719 32 : if (heritageExpression) {
10720 32 : IfThenElseEmitter ifThenElse(this);
10721 :
10722 16 : if (!emitTree(heritageExpression)) // ... HERITAGE
10723 0 : return false;
10724 :
10725 : // Heritage must be null or a non-generator constructor
10726 16 : if (!emit1(JSOP_CHECKCLASSHERITAGE)) // ... HERITAGE
10727 0 : return false;
10728 :
10729 : // [IF] (heritage !== null)
10730 16 : if (!emit1(JSOP_DUP)) // ... HERITAGE HERITAGE
10731 0 : return false;
10732 16 : if (!emit1(JSOP_NULL)) // ... HERITAGE HERITAGE NULL
10733 0 : return false;
10734 16 : if (!emit1(JSOP_STRICTNE)) // ... HERITAGE NE
10735 0 : return false;
10736 :
10737 : // [THEN] funProto = heritage, objProto = heritage.prototype
10738 16 : if (!ifThenElse.emitIfElse())
10739 0 : return false;
10740 16 : if (!emit1(JSOP_DUP)) // ... HERITAGE HERITAGE
10741 0 : return false;
10742 16 : if (!emitAtomOp(cx->names().prototype, JSOP_GETPROP)) // ... HERITAGE PROTO
10743 0 : return false;
10744 :
10745 : // [ELSE] funProto = %FunctionPrototype%, objProto = null
10746 16 : if (!ifThenElse.emitElse())
10747 0 : return false;
10748 16 : if (!emit1(JSOP_POP)) // ...
10749 0 : return false;
10750 16 : if (!emit2(JSOP_BUILTINPROTO, JSProto_Function)) // ... PROTO
10751 0 : return false;
10752 16 : if (!emit1(JSOP_NULL)) // ... PROTO NULL
10753 0 : return false;
10754 :
10755 : // [ENDIF]
10756 16 : if (!ifThenElse.emitEnd())
10757 0 : return false;
10758 :
10759 16 : if (!emit1(JSOP_OBJWITHPROTO)) // ... HERITAGE HOMEOBJ
10760 0 : return false;
10761 16 : if (!emit1(JSOP_SWAP)) // ... HOMEOBJ HERITAGE
10762 0 : return false;
10763 : } else {
10764 16 : if (!emitNewInit(JSProto_Object)) // ... HOMEOBJ
10765 0 : return false;
10766 : }
10767 :
10768 : // Stack currently has HOMEOBJ followed by optional HERITAGE. When HERITAGE
10769 : // is not used, an implicit value of %FunctionPrototype% is implied.
10770 :
10771 32 : if (constructor) {
10772 31 : if (!emitFunction(constructor, !!heritageExpression)) // ... HOMEOBJ CONSTRUCTOR
10773 0 : return false;
10774 31 : if (constructor->pn_funbox->needsHomeObject()) {
10775 0 : if (!emit2(JSOP_INITHOMEOBJECT, 0)) // ... HOMEOBJ CONSTRUCTOR
10776 0 : return false;
10777 : }
10778 : } else {
10779 : // In the case of default class constructors, emit the start and end
10780 : // offsets in the source buffer as source notes so that when we
10781 : // actually make the constructor during execution, we can give it the
10782 : // correct toString output.
10783 : //
10784 : // Token positions are already offset from the start column. Since
10785 : // toString offsets are absolute offsets into the ScriptSource,
10786 : // de-offset from the starting column.
10787 1 : ptrdiff_t classStart = ptrdiff_t(pn->pn_pos.begin) -
10788 1 : tokenStream().options().sourceStartColumn;
10789 1 : ptrdiff_t classEnd = ptrdiff_t(pn->pn_pos.end) -
10790 1 : tokenStream().options().sourceStartColumn;
10791 1 : if (!newSrcNote3(SRC_CLASS_SPAN, classStart, classEnd))
10792 0 : return false;
10793 :
10794 1 : JSAtom *name = names ? names->innerBinding()->pn_atom : cx->names().empty;
10795 1 : if (heritageExpression) {
10796 1 : if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR)) // ... HOMEOBJ CONSTRUCTOR
10797 0 : return false;
10798 : } else {
10799 0 : if (!emitAtomOp(name, JSOP_CLASSCONSTRUCTOR)) // ... HOMEOBJ CONSTRUCTOR
10800 0 : return false;
10801 : }
10802 : }
10803 :
10804 32 : if (!emit1(JSOP_SWAP)) // ... CONSTRUCTOR HOMEOBJ
10805 0 : return false;
10806 :
10807 32 : if (!emit1(JSOP_DUP2)) // ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR HOMEOBJ
10808 0 : return false;
10809 32 : if (!emitAtomOp(cx->names().prototype, JSOP_INITLOCKEDPROP)) // ... CONSTRUCTOR HOMEOBJ CONSTRUCTOR
10810 0 : return false;
10811 32 : if (!emitAtomOp(cx->names().constructor, JSOP_INITHIDDENPROP)) // ... CONSTRUCTOR HOMEOBJ
10812 0 : return false;
10813 :
10814 64 : RootedPlainObject obj(cx);
10815 32 : if (!emitPropertyList(classMethods, &obj, ClassBody)) // ... CONSTRUCTOR HOMEOBJ
10816 0 : return false;
10817 :
10818 32 : if (!emit1(JSOP_POP)) // ... CONSTRUCTOR
10819 0 : return false;
10820 :
10821 32 : if (names) {
10822 26 : ParseNode* innerName = names->innerBinding();
10823 26 : if (!emitLexicalInitialization(innerName)) // ... CONSTRUCTOR
10824 0 : return false;
10825 :
10826 : // Pop the inner scope.
10827 26 : if (!emitterScope->leave(this))
10828 0 : return false;
10829 26 : emitterScope.reset();
10830 :
10831 26 : ParseNode* outerName = names->outerBinding();
10832 26 : if (outerName) {
10833 26 : if (!emitLexicalInitialization(outerName)) // ... CONSTRUCTOR
10834 0 : return false;
10835 : // Only class statements make outer bindings, and they do not leave
10836 : // themselves on the stack.
10837 26 : if (!emit1(JSOP_POP)) // ...
10838 0 : return false;
10839 : }
10840 : }
10841 :
10842 : // The CONSTRUCTOR is left on stack if this is an expression.
10843 :
10844 32 : MOZ_ALWAYS_TRUE(sc->setLocalStrictMode(savedStrictness));
10845 :
10846 32 : return true;
10847 : }
10848 :
10849 : bool
10850 227349 : BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
10851 : EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */)
10852 : {
10853 227349 : if (!CheckRecursionLimit(cx))
10854 0 : return false;
10855 :
10856 454710 : EmitLevelManager elm(this);
10857 :
10858 : /* Emit notes to tell the current bytecode's source line number.
10859 : However, a couple trees require special treatment; see the
10860 : relevant emitter functions for details. */
10861 227349 : if (emitLineNote == EMIT_LINENOTE && !ParseNodeRequiresSpecialLineNumberNotes(pn)) {
10862 224002 : if (!updateLineNumberNotes(pn->pn_pos.begin))
10863 0 : return false;
10864 : }
10865 :
10866 227349 : switch (pn->getKind()) {
10867 : case PNK_FUNCTION:
10868 5830 : if (!emitFunction(pn))
10869 0 : return false;
10870 5831 : break;
10871 :
10872 : case PNK_PARAMSBODY:
10873 5404 : if (!emitFunctionFormalParametersAndBody(pn))
10874 0 : return false;
10875 5405 : break;
10876 :
10877 : case PNK_IF:
10878 6761 : if (!emitIf(pn))
10879 0 : return false;
10880 6762 : break;
10881 :
10882 : case PNK_SWITCH:
10883 210 : if (!emitSwitch(pn))
10884 0 : return false;
10885 210 : break;
10886 :
10887 : case PNK_WHILE:
10888 183 : if (!emitWhile(pn))
10889 0 : return false;
10890 183 : break;
10891 :
10892 : case PNK_DOWHILE:
10893 20 : if (!emitDo(pn))
10894 0 : return false;
10895 20 : break;
10896 :
10897 : case PNK_FOR:
10898 322 : if (!emitFor(pn))
10899 0 : return false;
10900 322 : break;
10901 :
10902 : case PNK_COMPREHENSIONFOR:
10903 0 : if (!emitComprehensionFor(pn))
10904 0 : return false;
10905 0 : break;
10906 :
10907 : case PNK_BREAK:
10908 479 : if (!emitBreak(pn->as<BreakStatement>().label()))
10909 0 : return false;
10910 479 : break;
10911 :
10912 : case PNK_CONTINUE:
10913 121 : if (!emitContinue(pn->as<ContinueStatement>().label()))
10914 0 : return false;
10915 121 : break;
10916 :
10917 : case PNK_WITH:
10918 0 : if (!emitWith(pn))
10919 0 : return false;
10920 0 : break;
10921 :
10922 : case PNK_TRY:
10923 489 : if (!emitTry(pn))
10924 0 : return false;
10925 489 : break;
10926 :
10927 : case PNK_CATCH:
10928 467 : if (!emitCatch(pn))
10929 0 : return false;
10930 467 : break;
10931 :
10932 : case PNK_VAR:
10933 4836 : if (!emitDeclarationList(pn))
10934 0 : return false;
10935 4836 : break;
10936 :
10937 : case PNK_RETURN:
10938 6164 : if (!emitReturn(pn))
10939 0 : return false;
10940 6164 : break;
10941 :
10942 : case PNK_YIELD_STAR:
10943 3 : if (!emitYieldStar(pn->pn_kid))
10944 0 : return false;
10945 3 : break;
10946 :
10947 : case PNK_GENERATOR:
10948 127 : if (!emit1(JSOP_GENERATOR))
10949 0 : return false;
10950 127 : break;
10951 :
10952 : case PNK_INITIALYIELD:
10953 127 : if (!emitInitialYield(pn))
10954 0 : return false;
10955 127 : break;
10956 :
10957 : case PNK_YIELD:
10958 15 : if (!emitYield(pn))
10959 0 : return false;
10960 15 : break;
10961 :
10962 : case PNK_AWAIT:
10963 235 : if (!emitAwait(pn))
10964 0 : return false;
10965 235 : break;
10966 :
10967 : case PNK_STATEMENTLIST:
10968 12756 : if (!emitStatementList(pn))
10969 0 : return false;
10970 12758 : break;
10971 :
10972 : case PNK_SEMI:
10973 14318 : if (!emitStatement(pn))
10974 0 : return false;
10975 14318 : break;
10976 :
10977 : case PNK_LABEL:
10978 0 : if (!emitLabeledStatement(&pn->as<LabeledStatement>()))
10979 0 : return false;
10980 0 : break;
10981 :
10982 : case PNK_COMMA:
10983 10 : if (!emitSequenceExpr(pn, valueUsage))
10984 0 : return false;
10985 10 : break;
10986 :
10987 : case PNK_ASSIGN:
10988 : case PNK_ADDASSIGN:
10989 : case PNK_SUBASSIGN:
10990 : case PNK_BITORASSIGN:
10991 : case PNK_BITXORASSIGN:
10992 : case PNK_BITANDASSIGN:
10993 : case PNK_LSHASSIGN:
10994 : case PNK_RSHASSIGN:
10995 : case PNK_URSHASSIGN:
10996 : case PNK_MULASSIGN:
10997 : case PNK_DIVASSIGN:
10998 : case PNK_MODASSIGN:
10999 : case PNK_POWASSIGN:
11000 5736 : if (!emitAssignment(pn->pn_left, pn->getOp(), pn->pn_right))
11001 0 : return false;
11002 5736 : break;
11003 :
11004 : case PNK_CONDITIONAL:
11005 657 : if (!emitConditionalExpression(pn->as<ConditionalExpression>(), valueUsage))
11006 0 : return false;
11007 657 : break;
11008 :
11009 : case PNK_OR:
11010 : case PNK_AND:
11011 2022 : if (!emitLogical(pn))
11012 0 : return false;
11013 2023 : break;
11014 :
11015 : case PNK_ADD:
11016 : case PNK_SUB:
11017 : case PNK_BITOR:
11018 : case PNK_BITXOR:
11019 : case PNK_BITAND:
11020 : case PNK_STRICTEQ:
11021 : case PNK_EQ:
11022 : case PNK_STRICTNE:
11023 : case PNK_NE:
11024 : case PNK_LT:
11025 : case PNK_LE:
11026 : case PNK_GT:
11027 : case PNK_GE:
11028 : case PNK_IN:
11029 : case PNK_INSTANCEOF:
11030 : case PNK_LSH:
11031 : case PNK_RSH:
11032 : case PNK_URSH:
11033 : case PNK_STAR:
11034 : case PNK_DIV:
11035 : case PNK_MOD:
11036 8175 : if (!emitLeftAssociative(pn))
11037 0 : return false;
11038 8175 : break;
11039 :
11040 : case PNK_POW:
11041 0 : if (!emitRightAssociative(pn))
11042 0 : return false;
11043 0 : break;
11044 :
11045 : case PNK_TYPEOFNAME:
11046 437 : if (!emitTypeof(pn, JSOP_TYPEOF))
11047 0 : return false;
11048 437 : break;
11049 :
11050 : case PNK_TYPEOFEXPR:
11051 65 : if (!emitTypeof(pn, JSOP_TYPEOFEXPR))
11052 0 : return false;
11053 65 : break;
11054 :
11055 : case PNK_THROW:
11056 : case PNK_VOID:
11057 : case PNK_NOT:
11058 : case PNK_BITNOT:
11059 : case PNK_POS:
11060 : case PNK_NEG:
11061 3393 : if (!emitUnary(pn))
11062 0 : return false;
11063 3394 : break;
11064 :
11065 : case PNK_PREINCREMENT:
11066 : case PNK_PREDECREMENT:
11067 : case PNK_POSTINCREMENT:
11068 : case PNK_POSTDECREMENT:
11069 705 : if (!emitIncOrDec(pn))
11070 0 : return false;
11071 705 : break;
11072 :
11073 : case PNK_DELETENAME:
11074 0 : if (!emitDeleteName(pn))
11075 0 : return false;
11076 0 : break;
11077 :
11078 : case PNK_DELETEPROP:
11079 52 : if (!emitDeleteProperty(pn))
11080 0 : return false;
11081 52 : break;
11082 :
11083 : case PNK_DELETEELEM:
11084 30 : if (!emitDeleteElement(pn))
11085 0 : return false;
11086 30 : break;
11087 :
11088 : case PNK_DELETEEXPR:
11089 0 : if (!emitDeleteExpression(pn))
11090 0 : return false;
11091 0 : break;
11092 :
11093 : case PNK_DOT:
11094 10563 : if (pn->as<PropertyAccess>().isSuper()) {
11095 0 : if (!emitSuperPropOp(pn, JSOP_GETPROP_SUPER))
11096 0 : return false;
11097 : } else {
11098 10563 : if (!emitPropOp(pn, JSOP_GETPROP))
11099 0 : return false;
11100 : }
11101 10563 : break;
11102 :
11103 : case PNK_ELEM:
11104 2431 : if (pn->as<PropertyByValue>().isSuper()) {
11105 0 : if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
11106 0 : return false;
11107 : } else {
11108 2431 : if (!emitElemOp(pn, JSOP_GETELEM))
11109 0 : return false;
11110 : }
11111 2431 : break;
11112 :
11113 : case PNK_NEW:
11114 : case PNK_TAGGED_TEMPLATE:
11115 : case PNK_CALL:
11116 : case PNK_GENEXP:
11117 : case PNK_SUPERCALL:
11118 22220 : if (!emitCallOrNew(pn, valueUsage))
11119 0 : return false;
11120 22221 : break;
11121 :
11122 : case PNK_LEXICALSCOPE:
11123 12679 : if (!emitLexicalScope(pn))
11124 0 : return false;
11125 12680 : break;
11126 :
11127 : case PNK_CONST:
11128 : case PNK_LET:
11129 4720 : if (!emitDeclarationList(pn))
11130 0 : return false;
11131 4721 : break;
11132 :
11133 : case PNK_IMPORT:
11134 0 : MOZ_ASSERT(sc->isModuleContext());
11135 0 : break;
11136 :
11137 : case PNK_EXPORT:
11138 0 : MOZ_ASSERT(sc->isModuleContext());
11139 0 : if (pn->pn_kid->getKind() != PNK_EXPORT_SPEC_LIST) {
11140 0 : if (!emitTree(pn->pn_kid))
11141 0 : return false;
11142 : }
11143 0 : break;
11144 :
11145 : case PNK_EXPORT_DEFAULT:
11146 0 : MOZ_ASSERT(sc->isModuleContext());
11147 0 : if (!emitTree(pn->pn_kid))
11148 0 : return false;
11149 0 : if (pn->pn_right) {
11150 0 : if (!emitLexicalInitialization(pn->pn_right))
11151 0 : return false;
11152 0 : if (!emit1(JSOP_POP))
11153 0 : return false;
11154 : }
11155 0 : break;
11156 :
11157 : case PNK_EXPORT_FROM:
11158 0 : MOZ_ASSERT(sc->isModuleContext());
11159 0 : break;
11160 :
11161 : case PNK_ARRAYPUSH:
11162 : /*
11163 : * The array object's stack index is in arrayCompDepth. See below
11164 : * under the array initialiser code generator for array comprehension
11165 : * special casing.
11166 : */
11167 0 : if (!emitTree(pn->pn_kid))
11168 0 : return false;
11169 0 : if (!emitDupAt(this->stackDepth - 1 - arrayCompDepth))
11170 0 : return false;
11171 0 : if (!emit1(JSOP_ARRAYPUSH))
11172 0 : return false;
11173 0 : break;
11174 :
11175 : case PNK_CALLSITEOBJ:
11176 1 : if (!emitCallSiteObject(pn))
11177 0 : return false;
11178 1 : break;
11179 :
11180 : case PNK_ARRAY:
11181 1212 : if (!emitArrayLiteral(pn))
11182 0 : return false;
11183 1213 : break;
11184 :
11185 : case PNK_ARRAYCOMP:
11186 0 : if (!emitArrayComp(pn))
11187 0 : return false;
11188 0 : break;
11189 :
11190 : case PNK_OBJECT:
11191 1669 : if (!emitObject(pn))
11192 0 : return false;
11193 1670 : break;
11194 :
11195 : case PNK_NAME:
11196 59721 : if (!emitGetName(pn))
11197 0 : return false;
11198 59721 : break;
11199 :
11200 : case PNK_TEMPLATE_STRING_LIST:
11201 252 : if (!emitTemplateString(pn))
11202 0 : return false;
11203 252 : break;
11204 :
11205 : case PNK_TEMPLATE_STRING:
11206 : case PNK_STRING:
11207 11718 : if (!emitAtomOp(pn, JSOP_STRING))
11208 0 : return false;
11209 11718 : break;
11210 :
11211 : case PNK_NUMBER:
11212 7997 : if (!emitNumberOp(pn->pn_dval))
11213 0 : return false;
11214 7997 : break;
11215 :
11216 : case PNK_REGEXP:
11217 172 : if (!emitRegExp(objectList.add(pn->as<RegExpLiteral>().objbox())))
11218 0 : return false;
11219 172 : break;
11220 :
11221 : case PNK_TRUE:
11222 : case PNK_FALSE:
11223 : case PNK_NULL:
11224 : case PNK_RAW_UNDEFINED:
11225 4088 : if (!emit1(pn->getOp()))
11226 0 : return false;
11227 4088 : break;
11228 :
11229 : case PNK_THIS:
11230 7700 : if (!emitThisLiteral(pn))
11231 0 : return false;
11232 7700 : break;
11233 :
11234 : case PNK_DEBUGGER:
11235 0 : if (!updateSourceCoordNotes(pn->pn_pos.begin))
11236 0 : return false;
11237 0 : if (!emit1(JSOP_DEBUGGER))
11238 0 : return false;
11239 0 : break;
11240 :
11241 : case PNK_NOP:
11242 0 : MOZ_ASSERT(pn->getArity() == PN_NULLARY);
11243 0 : break;
11244 :
11245 : case PNK_CLASS:
11246 32 : if (!emitClass(pn))
11247 0 : return false;
11248 32 : break;
11249 :
11250 : case PNK_NEWTARGET:
11251 12 : if (!emit1(JSOP_NEWTARGET))
11252 0 : return false;
11253 12 : break;
11254 :
11255 : case PNK_SETTHIS:
11256 13 : if (!emitSetThis(pn))
11257 0 : return false;
11258 13 : break;
11259 :
11260 : case PNK_POSHOLDER:
11261 0 : MOZ_FALLTHROUGH_ASSERT("Should never try to emit PNK_POSHOLDER");
11262 :
11263 : default:
11264 0 : MOZ_ASSERT(0);
11265 : }
11266 :
11267 : /* bce->emitLevel == 1 means we're last on the stack, so finish up. */
11268 227361 : if (emitLevel == 1) {
11269 5674 : if (!updateSourceCoordNotes(pn->pn_pos.end))
11270 0 : return false;
11271 : }
11272 227361 : return true;
11273 : }
11274 :
11275 : bool
11276 17034 : BytecodeEmitter::emitTreeInBranch(ParseNode* pn,
11277 : ValueUsage valueUsage /* = ValueUsage::WantValue */)
11278 : {
11279 : // Code that may be conditionally executed always need their own TDZ
11280 : // cache.
11281 34069 : TDZCheckCache tdzCache(this);
11282 34069 : return emitTree(pn, valueUsage);
11283 : }
11284 :
11285 : static bool
11286 304593 : AllocSrcNote(JSContext* cx, SrcNotesVector& notes, unsigned* index)
11287 : {
11288 : // Start it off moderately large to avoid repeated resizings early on.
11289 : // ~99% of cases fit within 256 bytes.
11290 304593 : if (notes.capacity() == 0 && !notes.reserve(256))
11291 0 : return false;
11292 :
11293 304593 : if (!notes.growBy(1)) {
11294 0 : ReportOutOfMemory(cx);
11295 0 : return false;
11296 : }
11297 :
11298 304593 : *index = notes.length() - 1;
11299 304593 : return true;
11300 : }
11301 :
11302 : bool
11303 248558 : BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp)
11304 : {
11305 248558 : SrcNotesVector& notes = this->notes();
11306 : unsigned index;
11307 248558 : if (!AllocSrcNote(cx, notes, &index))
11308 0 : return false;
11309 :
11310 : /*
11311 : * Compute delta from the last annotated bytecode's offset. If it's too
11312 : * big to fit in sn, allocate one or more xdelta notes and reset sn.
11313 : */
11314 248558 : ptrdiff_t offset = this->offset();
11315 248558 : ptrdiff_t delta = offset - lastNoteOffset();
11316 248558 : current->lastNoteOffset = offset;
11317 248558 : if (delta >= SN_DELTA_LIMIT) {
11318 92 : do {
11319 56035 : ptrdiff_t xdelta = Min(delta, SN_XDELTA_MASK);
11320 56035 : SN_MAKE_XDELTA(¬es[index], xdelta);
11321 56035 : delta -= xdelta;
11322 56035 : if (!AllocSrcNote(cx, notes, &index))
11323 0 : return false;
11324 56035 : } while (delta >= SN_DELTA_LIMIT);
11325 : }
11326 :
11327 : /*
11328 : * Initialize type and delta, then allocate the minimum number of notes
11329 : * needed for type's arity. Usually, we won't need more, but if an offset
11330 : * does take two bytes, setSrcNoteOffset will grow notes.
11331 : */
11332 248558 : SN_MAKE_NOTE(¬es[index], type, delta);
11333 339051 : for (int n = (int)js_SrcNoteSpec[type].arity; n > 0; n--) {
11334 90493 : if (!newSrcNote(SRC_NULL))
11335 0 : return false;
11336 : }
11337 :
11338 248558 : if (indexp)
11339 96304 : *indexp = index;
11340 248558 : return true;
11341 : }
11342 :
11343 : bool
11344 84698 : BytecodeEmitter::newSrcNote2(SrcNoteType type, ptrdiff_t offset, unsigned* indexp)
11345 : {
11346 : unsigned index;
11347 84698 : if (!newSrcNote(type, &index))
11348 0 : return false;
11349 84698 : if (!setSrcNoteOffset(index, 0, offset))
11350 0 : return false;
11351 84698 : if (indexp)
11352 586 : *indexp = index;
11353 84698 : return true;
11354 : }
11355 :
11356 : bool
11357 133 : BytecodeEmitter::newSrcNote3(SrcNoteType type, ptrdiff_t offset1, ptrdiff_t offset2,
11358 : unsigned* indexp)
11359 : {
11360 : unsigned index;
11361 133 : if (!newSrcNote(type, &index))
11362 0 : return false;
11363 133 : if (!setSrcNoteOffset(index, 0, offset1))
11364 0 : return false;
11365 133 : if (!setSrcNoteOffset(index, 1, offset2))
11366 0 : return false;
11367 133 : if (indexp)
11368 132 : *indexp = index;
11369 133 : return true;
11370 : }
11371 :
11372 : bool
11373 2545 : BytecodeEmitter::addToSrcNoteDelta(jssrcnote* sn, ptrdiff_t delta)
11374 : {
11375 : /*
11376 : * Called only from finishTakingSrcNotes to add to main script note
11377 : * deltas, and only by a small positive amount.
11378 : */
11379 2545 : MOZ_ASSERT(current == &main);
11380 2545 : MOZ_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT);
11381 :
11382 2545 : ptrdiff_t base = SN_DELTA(sn);
11383 2545 : ptrdiff_t limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
11384 2545 : ptrdiff_t newdelta = base + delta;
11385 2545 : if (newdelta < limit) {
11386 2340 : SN_SET_DELTA(sn, newdelta);
11387 : } else {
11388 : jssrcnote xdelta;
11389 205 : SN_MAKE_XDELTA(&xdelta, delta);
11390 205 : if (!main.notes.insert(sn, xdelta))
11391 0 : return false;
11392 : }
11393 2545 : return true;
11394 : }
11395 :
11396 : bool
11397 91343 : BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offset)
11398 : {
11399 91343 : if (!SN_REPRESENTABLE_OFFSET(offset)) {
11400 0 : parser.reportError(JSMSG_NEED_DIET, js_script_str);
11401 0 : return false;
11402 : }
11403 :
11404 91343 : SrcNotesVector& notes = this->notes();
11405 :
11406 : /* Find the offset numbered which (i.e., skip exactly which offsets). */
11407 91343 : jssrcnote* sn = ¬es[index];
11408 91343 : MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
11409 91343 : MOZ_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
11410 92931 : for (sn++; which; sn++, which--) {
11411 1588 : if (*sn & SN_4BYTE_OFFSET_FLAG)
11412 265 : sn += 3;
11413 : }
11414 :
11415 : /*
11416 : * See if the new offset requires four bytes either by being too big or if
11417 : * the offset has already been inflated (in which case, we need to stay big
11418 : * to not break the srcnote encoding if this isn't the last srcnote).
11419 : */
11420 91343 : if (offset > (ptrdiff_t)SN_4BYTE_OFFSET_MASK || (*sn & SN_4BYTE_OFFSET_FLAG)) {
11421 : /* Maybe this offset was already set to a four-byte value. */
11422 18287 : if (!(*sn & SN_4BYTE_OFFSET_FLAG)) {
11423 : /* Insert three dummy bytes that will be overwritten shortly. */
11424 18287 : jssrcnote dummy = 0;
11425 36574 : if (!(sn = notes.insert(sn, dummy)) ||
11426 36574 : !(sn = notes.insert(sn, dummy)) ||
11427 : !(sn = notes.insert(sn, dummy)))
11428 : {
11429 0 : ReportOutOfMemory(cx);
11430 0 : return false;
11431 : }
11432 : }
11433 18287 : *sn++ = (jssrcnote)(SN_4BYTE_OFFSET_FLAG | (offset >> 24));
11434 18287 : *sn++ = (jssrcnote)(offset >> 16);
11435 18287 : *sn++ = (jssrcnote)(offset >> 8);
11436 : }
11437 91343 : *sn = (jssrcnote)offset;
11438 91343 : return true;
11439 : }
11440 :
11441 : bool
11442 5674 : BytecodeEmitter::finishTakingSrcNotes(uint32_t* out)
11443 : {
11444 5674 : MOZ_ASSERT(current == &main);
11445 :
11446 5674 : unsigned prologueCount = prologue.notes.length();
11447 5674 : if (prologueCount && prologue.currentLine != firstLine) {
11448 95 : switchToPrologue();
11449 95 : if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(firstLine)))
11450 0 : return false;
11451 95 : switchToMain();
11452 : } else {
11453 : /*
11454 : * Either no prologue srcnotes, or no line number change over prologue.
11455 : * We don't need a SRC_SETLINE, but we may need to adjust the offset
11456 : * of the first main note, by adding to its delta and possibly even
11457 : * prepending SRC_XDELTA notes to it to account for prologue bytecodes
11458 : * that came at and after the last annotated bytecode.
11459 : */
11460 5579 : ptrdiff_t offset = prologueOffset() - prologue.lastNoteOffset;
11461 5579 : MOZ_ASSERT(offset >= 0);
11462 5579 : if (offset > 0 && main.notes.length() != 0) {
11463 : /* NB: Use as much of the first main note's delta as we can. */
11464 2340 : jssrcnote* sn = main.notes.begin();
11465 2340 : ptrdiff_t delta = SN_IS_XDELTA(sn)
11466 4661 : ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
11467 4661 : : SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
11468 2340 : if (offset < delta)
11469 1971 : delta = offset;
11470 : for (;;) {
11471 2750 : if (!addToSrcNoteDelta(sn, delta))
11472 0 : return false;
11473 2545 : offset -= delta;
11474 2545 : if (offset == 0)
11475 2340 : break;
11476 205 : delta = Min(offset, SN_XDELTA_MASK);
11477 205 : sn = main.notes.begin();
11478 : }
11479 : }
11480 : }
11481 :
11482 : // The prologue count might have changed, so we can't reuse prologueCount.
11483 : // The + 1 is to account for the final SN_MAKE_TERMINATOR that is appended
11484 : // when the notes are copied to their final destination by CopySrcNotes.
11485 5674 : *out = prologue.notes.length() + main.notes.length() + 1;
11486 5674 : return true;
11487 : }
11488 :
11489 : void
11490 5674 : BytecodeEmitter::copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes)
11491 : {
11492 5674 : unsigned prologueCount = prologue.notes.length();
11493 5674 : unsigned mainCount = main.notes.length();
11494 5674 : unsigned totalCount = prologueCount + mainCount;
11495 5674 : MOZ_ASSERT(totalCount == nsrcnotes - 1);
11496 5674 : if (prologueCount)
11497 95 : PodCopy(destination, prologue.notes.begin(), prologueCount);
11498 5674 : PodCopy(destination + prologueCount, main.notes.begin(), mainCount);
11499 5674 : SN_MAKE_TERMINATOR(&destination[totalCount]);
11500 5674 : }
11501 :
11502 : void
11503 38 : CGConstList::finish(ConstArray* array)
11504 : {
11505 38 : MOZ_ASSERT(length() == array->length);
11506 :
11507 90 : for (unsigned i = 0; i < length(); i++)
11508 52 : array->vector[i] = list[i];
11509 38 : }
11510 :
11511 : /*
11512 : * Find the index of the given object for code generator.
11513 : *
11514 : * Since the emitter refers to each parsed object only once, for the index we
11515 : * use the number of already indexed objects. We also add the object to a list
11516 : * to convert the list to a fixed-size array when we complete code generation,
11517 : * see js::CGObjectList::finish below.
11518 : */
11519 : unsigned
11520 7975 : CGObjectList::add(ObjectBox* objbox)
11521 : {
11522 7975 : MOZ_ASSERT(!objbox->emitLink);
11523 7975 : objbox->emitLink = lastbox;
11524 7975 : lastbox = objbox;
11525 7975 : return length++;
11526 : }
11527 :
11528 : unsigned
11529 0 : CGObjectList::indexOf(JSObject* obj)
11530 : {
11531 0 : MOZ_ASSERT(length > 0);
11532 0 : unsigned index = length - 1;
11533 0 : for (ObjectBox* box = lastbox; box->object != obj; box = box->emitLink)
11534 0 : index--;
11535 0 : return index;
11536 : }
11537 :
11538 : void
11539 1381 : CGObjectList::finish(ObjectArray* array)
11540 : {
11541 1381 : MOZ_ASSERT(length <= INDEX_LIMIT);
11542 1381 : MOZ_ASSERT(length == array->length);
11543 :
11544 1381 : js::GCPtrObject* cursor = array->vector + array->length;
11545 1381 : ObjectBox* objbox = lastbox;
11546 7995 : do {
11547 7995 : --cursor;
11548 7995 : MOZ_ASSERT(!*cursor);
11549 7995 : MOZ_ASSERT(objbox->object->isTenured());
11550 7995 : *cursor = objbox->object;
11551 7995 : } while ((objbox = objbox->emitLink) != nullptr);
11552 1381 : MOZ_ASSERT(cursor == array->vector);
11553 1381 : }
11554 :
11555 : ObjectBox*
11556 0 : CGObjectList::find(uint32_t index)
11557 : {
11558 0 : MOZ_ASSERT(index < length);
11559 0 : ObjectBox* box = lastbox;
11560 0 : for (unsigned n = length - 1; n > index; n--)
11561 0 : box = box->emitLink;
11562 0 : return box;
11563 : }
11564 :
11565 : void
11566 5674 : CGScopeList::finish(ScopeArray* array)
11567 : {
11568 5674 : MOZ_ASSERT(length() <= INDEX_LIMIT);
11569 5674 : MOZ_ASSERT(length() == array->length);
11570 14787 : for (uint32_t i = 0; i < length(); i++)
11571 9113 : array->vector[i].init(vector[i]);
11572 5674 : }
11573 :
11574 : bool
11575 2844 : CGTryNoteList::append(JSTryNoteKind kind, uint32_t stackDepth, size_t start, size_t end)
11576 : {
11577 2844 : MOZ_ASSERT(start <= end);
11578 2844 : MOZ_ASSERT(size_t(uint32_t(start)) == start);
11579 2844 : MOZ_ASSERT(size_t(uint32_t(end)) == end);
11580 :
11581 : JSTryNote note;
11582 2844 : note.kind = kind;
11583 2844 : note.stackDepth = stackDepth;
11584 2844 : note.start = uint32_t(start);
11585 2844 : note.length = uint32_t(end - start);
11586 :
11587 2844 : return list.append(note);
11588 : }
11589 :
11590 : void
11591 1074 : CGTryNoteList::finish(TryNoteArray* array)
11592 : {
11593 1074 : MOZ_ASSERT(length() == array->length);
11594 :
11595 3919 : for (unsigned i = 0; i < length(); i++)
11596 2845 : array->vector[i] = list[i];
11597 1074 : }
11598 :
11599 : bool
11600 5100 : CGScopeNoteList::append(uint32_t scopeIndex, uint32_t offset, bool inPrologue,
11601 : uint32_t parent)
11602 : {
11603 : CGScopeNote note;
11604 5100 : mozilla::PodZero(¬e);
11605 :
11606 5100 : note.index = scopeIndex;
11607 5100 : note.start = offset;
11608 5100 : note.parent = parent;
11609 5100 : note.startInPrologue = inPrologue;
11610 :
11611 5100 : return list.append(note);
11612 : }
11613 :
11614 : void
11615 5101 : CGScopeNoteList::recordEnd(uint32_t index, uint32_t offset, bool inPrologue)
11616 : {
11617 5101 : MOZ_ASSERT(index < length());
11618 5101 : MOZ_ASSERT(list[index].length == 0);
11619 5101 : list[index].end = offset;
11620 5101 : list[index].endInPrologue = inPrologue;
11621 5101 : }
11622 :
11623 : void
11624 1656 : CGScopeNoteList::finish(ScopeNoteArray* array, uint32_t prologueLength)
11625 : {
11626 1656 : MOZ_ASSERT(length() == array->length);
11627 :
11628 6759 : for (unsigned i = 0; i < length(); i++) {
11629 5103 : if (!list[i].startInPrologue)
11630 5103 : list[i].start += prologueLength;
11631 5103 : if (!list[i].endInPrologue && list[i].end != UINT32_MAX)
11632 4999 : list[i].end += prologueLength;
11633 5103 : MOZ_ASSERT(list[i].end >= list[i].start);
11634 5103 : list[i].length = list[i].end - list[i].start;
11635 5103 : array->vector[i] = list[i];
11636 : }
11637 1656 : }
11638 :
11639 : void
11640 127 : CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength)
11641 : {
11642 127 : MOZ_ASSERT(length() == array.length());
11643 :
11644 507 : for (unsigned i = 0; i < length(); i++)
11645 380 : array[i] = prologueLength + list[i];
11646 127 : }
11647 :
11648 : /*
11649 : * We should try to get rid of offsetBias (always 0 or 1, where 1 is
11650 : * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR.
11651 : */
11652 : const JSSrcNoteSpec js_SrcNoteSpec[] = {
11653 : #define DEFINE_SRC_NOTE_SPEC(sym, name, arity) { name, arity },
11654 : FOR_EACH_SRC_NOTE_TYPE(DEFINE_SRC_NOTE_SPEC)
11655 : #undef DEFINE_SRC_NOTE_SPEC
11656 : };
11657 :
11658 : static int
11659 130942 : SrcNoteArity(jssrcnote* sn)
11660 : {
11661 : MOZ_ASSERT(SN_TYPE(sn) < SRC_LAST);
11662 130942 : return js_SrcNoteSpec[SN_TYPE(sn)].arity;
11663 : }
11664 :
11665 : JS_FRIEND_API(unsigned)
11666 98573 : js::SrcNoteLength(jssrcnote* sn)
11667 : {
11668 : unsigned arity;
11669 : jssrcnote* base;
11670 :
11671 98573 : arity = SrcNoteArity(sn);
11672 198437 : for (base = sn++; arity; sn++, arity--) {
11673 99861 : if (*sn & SN_4BYTE_OFFSET_FLAG)
11674 19466 : sn += 3;
11675 : }
11676 98576 : return sn - base;
11677 : }
11678 :
11679 : JS_FRIEND_API(ptrdiff_t)
11680 32379 : js::GetSrcNoteOffset(jssrcnote* sn, unsigned which)
11681 : {
11682 : /* Find the offset numbered which (i.e., skip exactly which offsets). */
11683 32379 : MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
11684 32379 : MOZ_ASSERT((int) which < SrcNoteArity(sn));
11685 32697 : for (sn++; which; sn++, which--) {
11686 318 : if (*sn & SN_4BYTE_OFFSET_FLAG)
11687 9 : sn += 3;
11688 : }
11689 32379 : if (*sn & SN_4BYTE_OFFSET_FLAG) {
11690 4749 : return (ptrdiff_t)(((uint32_t)(sn[0] & SN_4BYTE_OFFSET_MASK) << 24)
11691 4749 : | (sn[1] << 16)
11692 4749 : | (sn[2] << 8)
11693 4749 : | sn[3]);
11694 : }
11695 27630 : return (ptrdiff_t)*sn;
11696 : }
|