1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 #include "frontend/EmitterScope.h"
8 
9 #include "frontend/AbstractScopePtr.h"
10 #include "frontend/BytecodeEmitter.h"
11 #include "frontend/ModuleSharedContext.h"
12 #include "frontend/TDZCheckCache.h"
13 #include "vm/GlobalObject.h"
14 
15 using namespace js;
16 using namespace js::frontend;
17 
18 using mozilla::DebugOnly;
19 using mozilla::Maybe;
20 using mozilla::Nothing;
21 using mozilla::Some;
22 
EmitterScope(BytecodeEmitter * bce)23 EmitterScope::EmitterScope(BytecodeEmitter* bce)
24     : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
25       nameCache_(bce->cx->frontendCollectionPool()),
26       hasEnvironment_(false),
27       environmentChainLength_(0),
28       nextFrameSlot_(0),
29       scopeIndex_(ScopeNote::NoScopeIndex),
30       noteIndex_(ScopeNote::NoScopeNoteIndex) {}
31 
ensureCache(BytecodeEmitter * bce)32 bool EmitterScope::ensureCache(BytecodeEmitter* bce) {
33   return nameCache_.acquire(bce->cx);
34 }
35 
checkSlotLimits(BytecodeEmitter * bce,const BindingIter & bi)36 bool EmitterScope::checkSlotLimits(BytecodeEmitter* bce,
37                                    const BindingIter& bi) {
38   if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
39       bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT) {
40     bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
41     return false;
42   }
43   return true;
44 }
45 
checkEnvironmentChainLength(BytecodeEmitter * bce)46 bool EmitterScope::checkEnvironmentChainLength(BytecodeEmitter* bce) {
47   uint32_t hops;
48   if (EmitterScope* emitterScope = enclosing(&bce)) {
49     hops = emitterScope->environmentChainLength_;
50   } else {
51     hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
52   }
53 
54   if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
55     bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
56     return false;
57   }
58 
59   environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
60   return true;
61 }
62 
updateFrameFixedSlots(BytecodeEmitter * bce,const BindingIter & bi)63 void EmitterScope::updateFrameFixedSlots(BytecodeEmitter* bce,
64                                          const BindingIter& bi) {
65   nextFrameSlot_ = bi.nextFrameSlot();
66   if (nextFrameSlot_ > bce->maxFixedSlots) {
67     bce->maxFixedSlots = nextFrameSlot_;
68   }
69   MOZ_ASSERT_IF(
70       bce->sc->isFunctionBox() && (bce->sc->asFunctionBox()->isGenerator() ||
71                                    bce->sc->asFunctionBox()->isAsync()),
72       bce->maxFixedSlots == 0);
73 }
74 
putNameInCache(BytecodeEmitter * bce,JSAtom * name,NameLocation loc)75 bool EmitterScope::putNameInCache(BytecodeEmitter* bce, JSAtom* name,
76                                   NameLocation loc) {
77   NameLocationMap& cache = *nameCache_;
78   NameLocationMap::AddPtr p = cache.lookupForAdd(name);
79   MOZ_ASSERT(!p);
80   if (!cache.add(p, name, loc)) {
81     ReportOutOfMemory(bce->cx);
82     return false;
83   }
84   return true;
85 }
86 
lookupInCache(BytecodeEmitter * bce,JSAtom * name)87 Maybe<NameLocation> EmitterScope::lookupInCache(BytecodeEmitter* bce,
88                                                 JSAtom* name) {
89   if (NameLocationMap::Ptr p = nameCache_->lookup(name)) {
90     return Some(p->value().wrapped);
91   }
92   if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name)) {
93     return fallbackFreeNameLocation_;
94   }
95   return Nothing();
96 }
97 
enclosing(BytecodeEmitter ** bce) const98 EmitterScope* EmitterScope::enclosing(BytecodeEmitter** bce) const {
99   // There is an enclosing scope with access to the same frame.
100   if (EmitterScope* inFrame = enclosingInFrame()) {
101     return inFrame;
102   }
103 
104   // We are currently compiling the enclosing script, look in the
105   // enclosing BCE.
106   if ((*bce)->parent) {
107     *bce = (*bce)->parent;
108     return (*bce)->innermostEmitterScopeNoCheck();
109   }
110 
111   return nullptr;
112 }
113 
enclosingScope(BytecodeEmitter * bce) const114 AbstractScopePtr EmitterScope::enclosingScope(BytecodeEmitter* bce) const {
115   if (EmitterScope* es = enclosing(&bce)) {
116     return es->scope(bce);
117   }
118 
119   // The enclosing script is already compiled or the current script is the
120   // global script.
121   return AbstractScopePtr(bce->sc->compilationEnclosingScope());
122 }
123 
124 /* static */
nameCanBeFree(BytecodeEmitter * bce,JSAtom * name)125 bool EmitterScope::nameCanBeFree(BytecodeEmitter* bce, JSAtom* name) {
126   // '.generator' cannot be accessed by name.
127   return name != bce->cx->names().dotGenerator;
128 }
129 
130 #ifdef DEBUG
NameIsOnEnvironment(Scope * scope,JSAtom * name)131 static bool NameIsOnEnvironment(Scope* scope, JSAtom* name) {
132   for (BindingIter bi(scope); bi; bi++) {
133     // If found, the name must already be on the environment or an import,
134     // or else there is a bug in the closed-over name analysis in the
135     // Parser.
136     if (bi.name() == name) {
137       BindingLocation::Kind kind = bi.location().kind();
138 
139       if (bi.hasArgumentSlot()) {
140         JSScript* script = scope->as<FunctionScope>().script();
141         if (script->functionAllowsParameterRedeclaration()) {
142           // Check for duplicate positional formal parameters.
143           for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
144             if (bi2.name() == name) {
145               kind = bi2.location().kind();
146             }
147           }
148         }
149       }
150 
151       return kind == BindingLocation::Kind::Global ||
152              kind == BindingLocation::Kind::Environment ||
153              kind == BindingLocation::Kind::Import;
154     }
155   }
156 
157   // If not found, assume it's on the global or dynamically accessed.
158   return true;
159 }
160 #endif
161 
162 /* static */
searchInEnclosingScope(JSAtom * name,Scope * scope,uint8_t hops)163 NameLocation EmitterScope::searchInEnclosingScope(JSAtom* name, Scope* scope,
164                                                   uint8_t hops) {
165   for (ScopeIter si(scope); si; si++) {
166     MOZ_ASSERT(NameIsOnEnvironment(si.scope(), name));
167 
168     bool hasEnv = si.hasSyntacticEnvironment();
169 
170     switch (si.kind()) {
171       case ScopeKind::Function:
172         if (hasEnv) {
173           JSScript* script = si.scope()->as<FunctionScope>().script();
174           if (script->funHasExtensibleScope()) {
175             return NameLocation::Dynamic();
176           }
177 
178           for (BindingIter bi(si.scope()); bi; bi++) {
179             if (bi.name() != name) {
180               continue;
181             }
182 
183             BindingLocation bindLoc = bi.location();
184             if (bi.hasArgumentSlot() &&
185                 script->functionAllowsParameterRedeclaration()) {
186               // Check for duplicate positional formal parameters.
187               for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
188                 if (bi2.name() == name) {
189                   bindLoc = bi2.location();
190                 }
191               }
192             }
193 
194             MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
195             return NameLocation::EnvironmentCoordinate(bi.kind(), hops,
196                                                        bindLoc.slot());
197           }
198         }
199         break;
200 
201       case ScopeKind::FunctionBodyVar:
202       case ScopeKind::Lexical:
203       case ScopeKind::NamedLambda:
204       case ScopeKind::StrictNamedLambda:
205       case ScopeKind::SimpleCatch:
206       case ScopeKind::Catch:
207       case ScopeKind::FunctionLexical:
208         if (hasEnv) {
209           for (BindingIter bi(si.scope()); bi; bi++) {
210             if (bi.name() != name) {
211               continue;
212             }
213 
214             // The name must already have been marked as closed
215             // over. If this assertion is hit, there is a bug in the
216             // name analysis.
217             BindingLocation bindLoc = bi.location();
218             MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
219             return NameLocation::EnvironmentCoordinate(bi.kind(), hops,
220                                                        bindLoc.slot());
221           }
222         }
223         break;
224 
225       case ScopeKind::Module:
226         if (hasEnv) {
227           for (BindingIter bi(si.scope()); bi; bi++) {
228             if (bi.name() != name) {
229               continue;
230             }
231 
232             BindingLocation bindLoc = bi.location();
233 
234             // Imports are on the environment but are indirect
235             // bindings and must be accessed dynamically instead of
236             // using an EnvironmentCoordinate.
237             if (bindLoc.kind() == BindingLocation::Kind::Import) {
238               MOZ_ASSERT(si.kind() == ScopeKind::Module);
239               return NameLocation::Import();
240             }
241 
242             MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment);
243             return NameLocation::EnvironmentCoordinate(bi.kind(), hops,
244                                                        bindLoc.slot());
245           }
246         }
247         break;
248 
249       case ScopeKind::Eval:
250       case ScopeKind::StrictEval:
251         // As an optimization, if the eval doesn't have its own var
252         // environment and its immediate enclosing scope is a global
253         // scope, all accesses are global.
254         if (!hasEnv && si.scope()->enclosing()->is<GlobalScope>()) {
255           return NameLocation::Global(BindingKind::Var);
256         }
257         return NameLocation::Dynamic();
258 
259       case ScopeKind::Global:
260         return NameLocation::Global(BindingKind::Var);
261 
262       case ScopeKind::With:
263       case ScopeKind::NonSyntactic:
264         return NameLocation::Dynamic();
265 
266       case ScopeKind::WasmInstance:
267       case ScopeKind::WasmFunction:
268         MOZ_CRASH("No direct eval inside wasm functions");
269     }
270 
271     if (hasEnv) {
272       MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1);
273       hops++;
274     }
275   }
276 
277   MOZ_CRASH("Malformed scope chain");
278 }
279 
searchAndCache(BytecodeEmitter * bce,JSAtom * name)280 NameLocation EmitterScope::searchAndCache(BytecodeEmitter* bce, JSAtom* name) {
281   Maybe<NameLocation> loc;
282   uint8_t hops = hasEnvironment() ? 1 : 0;
283   DebugOnly<bool> inCurrentScript = enclosingInFrame();
284 
285   // Start searching in the current compilation.
286   for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) {
287     loc = es->lookupInCache(bce, name);
288     if (loc) {
289       if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate) {
290         *loc = loc->addHops(hops);
291       }
292       break;
293     }
294 
295     if (es->hasEnvironment()) {
296       hops++;
297     }
298 
299 #ifdef DEBUG
300     if (!es->enclosingInFrame()) {
301       inCurrentScript = false;
302     }
303 #endif
304   }
305 
306   // If the name is not found in the current compilation, walk the Scope
307   // chain encompassing the compilation.
308   if (!loc) {
309     inCurrentScript = false;
310     loc = Some(searchInEnclosingScope(
311         name, bce->sc->compilationEnclosingScope(), hops));
312   }
313 
314   // Each script has its own frame. A free name that is accessed
315   // from an inner script must not be a frame slot access. If this
316   // assertion is hit, it is a bug in the free name analysis in the
317   // parser.
318   MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot);
319 
320   // It is always correct to not cache the location. Ignore OOMs to make
321   // lookups infallible.
322   if (!putNameInCache(bce, name, *loc)) {
323     bce->cx->recoverFromOutOfMemory();
324   }
325 
326   return *loc;
327 }
328 
internEmptyGlobalScopeAsBody(BytecodeEmitter * bce)329 bool EmitterScope::internEmptyGlobalScopeAsBody(BytecodeEmitter* bce) {
330   Scope* scope = &bce->cx->global()->emptyGlobalScope();
331   hasEnvironment_ = scope->hasEnvironment();
332 
333   bce->bodyScopeIndex = bce->perScriptData().gcThingList().length();
334   return bce->perScriptData().gcThingList().appendEmptyGlobalScope(
335       &scopeIndex_);
336 }
337 
338 template <typename ScopeCreator>
internScopeCreationData(BytecodeEmitter * bce,ScopeCreator createScope)339 bool EmitterScope::internScopeCreationData(BytecodeEmitter* bce,
340                                            ScopeCreator createScope) {
341   Rooted<AbstractScopePtr> enclosing(bce->cx, enclosingScope(bce));
342   ScopeIndex index;
343   if (!createScope(bce->cx, enclosing, &index)) {
344     return false;
345   }
346   auto scope = bce->compilationInfo.scopeCreationData[index.index];
347   hasEnvironment_ = scope.get().hasEnvironment();
348   return bce->perScriptData().gcThingList().append(index, &scopeIndex_);
349 }
350 
351 template <typename ScopeCreator>
internBodyScopeCreationData(BytecodeEmitter * bce,ScopeCreator createScope)352 bool EmitterScope::internBodyScopeCreationData(BytecodeEmitter* bce,
353                                                ScopeCreator createScope) {
354   MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX,
355              "There can be only one body scope");
356   bce->bodyScopeIndex = bce->perScriptData().gcThingList().length();
357   return internScopeCreationData(bce, createScope);
358 }
359 
appendScopeNote(BytecodeEmitter * bce)360 bool EmitterScope::appendScopeNote(BytecodeEmitter* bce) {
361   MOZ_ASSERT(ScopeKindIsInBody(scope(bce).kind()) && enclosingInFrame(),
362              "Scope notes are not needed for body-level scopes.");
363   noteIndex_ = bce->bytecodeSection().scopeNoteList().length();
364   return bce->bytecodeSection().scopeNoteList().append(
365       index(), bce->bytecodeSection().offset(),
366       enclosingInFrame() ? enclosingInFrame()->noteIndex()
367                          : ScopeNote::NoScopeNoteIndex);
368 }
369 
deadZoneFrameSlotRange(BytecodeEmitter * bce,uint32_t slotStart,uint32_t slotEnd) const370 bool EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce,
371                                           uint32_t slotStart,
372                                           uint32_t slotEnd) const {
373   // Lexical bindings throw ReferenceErrors if they are used before
374   // initialization. See ES6 8.1.1.1.6.
375   //
376   // For completeness, lexical bindings are initialized in ES6 by calling
377   // InitializeBinding, after which touching the binding will no longer
378   // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
379   // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
380   if (slotStart != slotEnd) {
381     if (!bce->emit1(JSOp::Uninitialized)) {
382       return false;
383     }
384     for (uint32_t slot = slotStart; slot < slotEnd; slot++) {
385       if (!bce->emitLocalOp(JSOp::InitLexical, slot)) {
386         return false;
387       }
388     }
389     if (!bce->emit1(JSOp::Pop)) {
390       return false;
391     }
392   }
393 
394   return true;
395 }
396 
dump(BytecodeEmitter * bce)397 void EmitterScope::dump(BytecodeEmitter* bce) {
398   fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce).kind()),
399           this);
400 
401   for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
402     const NameLocation& l = r.front().value();
403 
404     UniqueChars bytes = AtomToPrintableString(bce->cx, r.front().key());
405     if (!bytes) {
406       return;
407     }
408     if (l.kind() != NameLocation::Kind::Dynamic) {
409       fprintf(stdout, "  %s %s ", BindingKindString(l.bindingKind()),
410               bytes.get());
411     } else {
412       fprintf(stdout, "  %s ", bytes.get());
413     }
414 
415     switch (l.kind()) {
416       case NameLocation::Kind::Dynamic:
417         fprintf(stdout, "dynamic\n");
418         break;
419       case NameLocation::Kind::Global:
420         fprintf(stdout, "global\n");
421         break;
422       case NameLocation::Kind::Intrinsic:
423         fprintf(stdout, "intrinsic\n");
424         break;
425       case NameLocation::Kind::NamedLambdaCallee:
426         fprintf(stdout, "named lambda callee\n");
427         break;
428       case NameLocation::Kind::Import:
429         fprintf(stdout, "import\n");
430         break;
431       case NameLocation::Kind::ArgumentSlot:
432         fprintf(stdout, "arg slot=%u\n", l.argumentSlot());
433         break;
434       case NameLocation::Kind::FrameSlot:
435         fprintf(stdout, "frame slot=%u\n", l.frameSlot());
436         break;
437       case NameLocation::Kind::EnvironmentCoordinate:
438         fprintf(stdout, "environment hops=%u slot=%u\n",
439                 l.environmentCoordinate().hops(),
440                 l.environmentCoordinate().slot());
441         break;
442       case NameLocation::Kind::DynamicAnnexBVar:
443         fprintf(stdout, "dynamic annex b var\n");
444         break;
445     }
446   }
447 
448   fprintf(stdout, "\n");
449 }
450 
enterLexical(BytecodeEmitter * bce,ScopeKind kind,Handle<LexicalScope::Data * > bindings)451 bool EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
452                                 Handle<LexicalScope::Data*> bindings) {
453   MOZ_ASSERT(kind != ScopeKind::NamedLambda &&
454              kind != ScopeKind::StrictNamedLambda);
455   MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
456 
457   if (!ensureCache(bce)) {
458     return false;
459   }
460 
461   // Resolve bindings.
462   TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
463   uint32_t firstFrameSlot = frameSlotStart();
464   BindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false);
465   for (; bi; bi++) {
466     if (!checkSlotLimits(bce, bi)) {
467       return false;
468     }
469 
470     NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
471     if (!putNameInCache(bce, bi.name(), loc)) {
472       return false;
473     }
474 
475     if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ)) {
476       return false;
477     }
478   }
479 
480   updateFrameFixedSlots(bce, bi);
481 
482   auto createScope = [kind, bindings, firstFrameSlot, bce](
483                          JSContext* cx, Handle<AbstractScopePtr> enclosing,
484                          ScopeIndex* index) {
485     return ScopeCreationData::create(cx, bce->compilationInfo, kind, bindings,
486                                      firstFrameSlot, enclosing, index);
487   };
488   if (!internScopeCreationData(bce, createScope)) {
489     return false;
490   }
491 
492   if (ScopeKindIsInBody(kind) && hasEnvironment()) {
493     // After interning the VM scope we can get the scope index.
494     if (!bce->emitInternedScopeOp(index(), JSOp::PushLexicalEnv)) {
495       return false;
496     }
497   }
498 
499   // Lexical scopes need notes to be mapped from a pc.
500   if (!appendScopeNote(bce)) {
501     return false;
502   }
503 
504   // Put frame slots in TDZ. Environment slots are poisoned during
505   // environment creation.
506   //
507   // This must be done after appendScopeNote to be considered in the extent
508   // of the scope.
509   if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd())) {
510     return false;
511   }
512 
513   return checkEnvironmentChainLength(bce);
514 }
515 
enterNamedLambda(BytecodeEmitter * bce,FunctionBox * funbox)516 bool EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox) {
517   MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
518   MOZ_ASSERT(funbox->namedLambdaBindings());
519 
520   if (!ensureCache(bce)) {
521     return false;
522   }
523 
524   BindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT,
525                  /* isNamedLambda = */ true);
526   MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee);
527 
528   // The lambda name, if not closed over, is accessed via JSOp::Callee and
529   // not a frame slot. Do not update frame slot information.
530   NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
531   if (!putNameInCache(bce, bi.name(), loc)) {
532     return false;
533   }
534 
535   bi++;
536   MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope");
537 
538   ScopeKind scopeKind =
539       funbox->strict() ? ScopeKind::StrictNamedLambda : ScopeKind::NamedLambda;
540 
541   auto createScope = [funbox, scopeKind, bce](
542                          JSContext* cx, Handle<AbstractScopePtr> enclosing,
543                          ScopeIndex* index) {
544     return ScopeCreationData::create(cx, bce->compilationInfo, scopeKind,
545                                      funbox->namedLambdaBindings(),
546                                      LOCALNO_LIMIT, enclosing, index);
547   };
548   if (!internScopeCreationData(bce, createScope)) {
549     return false;
550   }
551 
552   return checkEnvironmentChainLength(bce);
553 }
554 
enterFunction(BytecodeEmitter * bce,FunctionBox * funbox)555 bool EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox) {
556   MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
557 
558   // If there are parameter expressions, there is an extra var scope.
559   if (!funbox->functionHasExtraBodyVarScope()) {
560     bce->setVarEmitterScope(this);
561   }
562 
563   if (!ensureCache(bce)) {
564     return false;
565   }
566 
567   // Resolve body-level bindings, if there are any.
568   auto bindings = funbox->functionScopeBindings();
569   if (bindings) {
570     NameLocationMap& cache = *nameCache_;
571 
572     BindingIter bi(*bindings, funbox->hasParameterExprs);
573     for (; bi; bi++) {
574       if (!checkSlotLimits(bce, bi)) {
575         return false;
576       }
577 
578       NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
579       NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
580 
581       // The only duplicate bindings that occur are simple formal
582       // parameters, in which case the last position counts, so update the
583       // location.
584       if (p) {
585         MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
586         MOZ_ASSERT(!funbox->hasDestructuringArgs);
587         MOZ_ASSERT(!funbox->hasRest());
588         p->value() = loc;
589         continue;
590       }
591 
592       if (!cache.add(p, bi.name(), loc)) {
593         ReportOutOfMemory(bce->cx);
594         return false;
595       }
596     }
597 
598     updateFrameFixedSlots(bce, bi);
599   } else {
600     nextFrameSlot_ = 0;
601   }
602 
603   // If the function's scope may be extended at runtime due to sloppy direct
604   // eval, any names beyond the function scope must be accessed dynamically as
605   // we don't know if the name will become a 'var' binding due to direct eval.
606   if (funbox->funHasExtensibleScope()) {
607     fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
608   }
609 
610   // In case of parameter expressions, the parameters are lexical
611   // bindings and have TDZ.
612   if (funbox->hasParameterExprs && nextFrameSlot_) {
613     uint32_t paramFrameSlotEnd = 0;
614     for (BindingIter bi(*bindings, true); bi; bi++) {
615       if (!BindingKindIsLexical(bi.kind())) {
616         break;
617       }
618 
619       NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
620       if (loc.kind() == NameLocation::Kind::FrameSlot) {
621         MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot());
622         paramFrameSlotEnd = loc.frameSlot() + 1;
623       }
624     }
625 
626     if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd)) {
627       return false;
628     }
629   }
630 
631   auto createScope = [funbox, bce](JSContext* cx,
632                                    Handle<AbstractScopePtr> enclosing,
633                                    ScopeIndex* index) {
634     return ScopeCreationData::create(
635         cx, bce->compilationInfo, funbox->functionScopeBindings(),
636         funbox->hasParameterExprs,
637         funbox->needsCallObjectRegardlessOfBindings(), funbox, enclosing,
638         index);
639   };
640   if (!internBodyScopeCreationData(bce, createScope)) {
641     return false;
642   }
643 
644   return checkEnvironmentChainLength(bce);
645 }
646 
enterFunctionExtraBodyVar(BytecodeEmitter * bce,FunctionBox * funbox)647 bool EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce,
648                                              FunctionBox* funbox) {
649   MOZ_ASSERT(funbox->hasParameterExprs);
650   MOZ_ASSERT(funbox->extraVarScopeBindings() ||
651              funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
652   MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
653 
654   // The extra var scope is never popped once it's entered. It replaces the
655   // function scope as the var emitter scope.
656   bce->setVarEmitterScope(this);
657 
658   if (!ensureCache(bce)) {
659     return false;
660   }
661 
662   // Resolve body-level bindings, if there are any.
663   uint32_t firstFrameSlot = frameSlotStart();
664   if (auto bindings = funbox->extraVarScopeBindings()) {
665     BindingIter bi(*bindings, firstFrameSlot);
666     for (; bi; bi++) {
667       if (!checkSlotLimits(bce, bi)) {
668         return false;
669       }
670 
671       NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
672       if (!putNameInCache(bce, bi.name(), loc)) {
673         return false;
674       }
675     }
676 
677     updateFrameFixedSlots(bce, bi);
678   } else {
679     nextFrameSlot_ = firstFrameSlot;
680   }
681 
682   // If the extra var scope may be extended at runtime due to sloppy
683   // direct eval, any names beyond the var scope must be accessed
684   // dynamically as we don't know if the name will become a 'var' binding
685   // due to direct eval.
686   if (funbox->funHasExtensibleScope()) {
687     fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
688   }
689 
690   // Create and intern the VM scope.
691   auto createScope = [funbox, firstFrameSlot, bce](
692                          JSContext* cx, Handle<AbstractScopePtr> enclosing,
693                          ScopeIndex* index) {
694     return ScopeCreationData::create(
695         cx, bce->compilationInfo, ScopeKind::FunctionBodyVar,
696         funbox->extraVarScopeBindings(), firstFrameSlot,
697         funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(), enclosing,
698         index);
699   };
700   if (!internScopeCreationData(bce, createScope)) {
701     return false;
702   }
703 
704   if (hasEnvironment()) {
705     if (!bce->emitInternedScopeOp(index(), JSOp::PushVarEnv)) {
706       return false;
707     }
708   }
709 
710   // The extra var scope needs a note to be mapped from a pc.
711   if (!appendScopeNote(bce)) {
712     return false;
713   }
714 
715   return checkEnvironmentChainLength(bce);
716 }
717 
718 class DynamicBindingIter : public BindingIter {
719  public:
DynamicBindingIter(GlobalSharedContext * sc)720   explicit DynamicBindingIter(GlobalSharedContext* sc)
721       : BindingIter(*sc->bindings) {}
722 
DynamicBindingIter(EvalSharedContext * sc)723   explicit DynamicBindingIter(EvalSharedContext* sc)
724       : BindingIter(*sc->bindings, /* strict = */ false) {
725     MOZ_ASSERT(!sc->strict());
726   }
727 
bindingOp() const728   JSOp bindingOp() const {
729     switch (kind()) {
730       case BindingKind::Var:
731         return JSOp::DefVar;
732       case BindingKind::Let:
733         return JSOp::DefLet;
734       case BindingKind::Const:
735         return JSOp::DefConst;
736       default:
737         MOZ_CRASH("Bad BindingKind");
738     }
739   }
740 };
741 
enterGlobal(BytecodeEmitter * bce,GlobalSharedContext * globalsc)742 bool EmitterScope::enterGlobal(BytecodeEmitter* bce,
743                                GlobalSharedContext* globalsc) {
744   MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
745 
746   bce->setVarEmitterScope(this);
747 
748   if (!ensureCache(bce)) {
749     return false;
750   }
751 
752   if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
753     // In self-hosting, it is incorrect to consult the global scope because
754     // self-hosted scripts are cloned into their target compartments before
755     // they are run. Instead of Global, Intrinsic is used for all names.
756     //
757     // Intrinsic lookups are redirected to the special intrinsics holder
758     // in the global object, into which any missing values are cloned
759     // lazily upon first access.
760     fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic());
761 
762     return internEmptyGlobalScopeAsBody(bce);
763   }
764 
765   auto createScope = [globalsc, bce](JSContext* cx,
766                                      Handle<AbstractScopePtr> enclosing,
767                                      ScopeIndex* index) {
768     MOZ_ASSERT(!enclosing.get());
769     return ScopeCreationData::create(cx, bce->compilationInfo,
770                                      globalsc->scopeKind(), globalsc->bindings,
771                                      index);
772   };
773   if (!internBodyScopeCreationData(bce, createScope)) {
774     return false;
775   }
776 
777   // See: JSScript::outermostScope.
778   MOZ_ASSERT(bce->bodyScopeIndex == 0, "Global scope must be index 0");
779 
780   // Resolve binding names and emit Def{Var,Let,Const} prologue ops.
781   if (globalsc->bindings) {
782     // Check for declaration conflicts before the Def* ops.
783     if (!bce->emit1(JSOp::CheckGlobalOrEvalDecl)) {
784       return false;
785     }
786 
787     for (DynamicBindingIter bi(globalsc); bi; bi++) {
788       NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
789       JSAtom* name = bi.name();
790       if (!putNameInCache(bce, name, loc)) {
791         return false;
792       }
793 
794       // Define the name in the prologue. Do not emit DefVar for
795       // functions that we'll emit DefFun for.
796       if (bi.isTopLevelFunction()) {
797         continue;
798       }
799 
800       if (!bce->emitAtomOp(bi.bindingOp(), name)) {
801         return false;
802       }
803     }
804   }
805 
806   // Note that to save space, we don't add free names to the cache for
807   // global scopes. They are assumed to be global vars in the syntactic
808   // global scope, dynamic accesses under non-syntactic global scope.
809   if (globalsc->scopeKind() == ScopeKind::Global) {
810     fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
811   } else {
812     fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
813   }
814 
815   return true;
816 }
817 
enterEval(BytecodeEmitter * bce,EvalSharedContext * evalsc)818 bool EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc) {
819   MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
820 
821   bce->setVarEmitterScope(this);
822 
823   if (!ensureCache(bce)) {
824     return false;
825   }
826 
827   // For simplicity, treat all free name lookups in eval scripts as dynamic.
828   fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
829 
830   // Create the `var` scope. Note that there is also a lexical scope, created
831   // separately in emitScript().
832   auto createScope = [evalsc, bce](JSContext* cx,
833                                    Handle<AbstractScopePtr> enclosing,
834                                    ScopeIndex* index) {
835     ScopeKind scopeKind =
836         evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval;
837     return ScopeCreationData::create(cx, bce->compilationInfo, scopeKind,
838                                      evalsc->bindings, enclosing, index);
839   };
840   if (!internBodyScopeCreationData(bce, createScope)) {
841     return false;
842   }
843 
844   if (hasEnvironment()) {
845     if (!bce->emitInternedScopeOp(index(), JSOp::PushVarEnv)) {
846       return false;
847     }
848   } else {
849     // Resolve binding names and emit DefVar prologue ops if we don't have
850     // an environment (i.e., a sloppy eval).
851     // Eval scripts always have their own lexical scope, but non-strict
852     // scopes may introduce 'var' bindings to the nearest var scope.
853     //
854     // TODO: We may optimize strict eval bindings in the future to be on
855     // the frame. For now, handle everything dynamically.
856     if (!hasEnvironment() && evalsc->bindings) {
857       // Check for declaration conflicts before the DefVar ops.
858       if (!bce->emit1(JSOp::CheckGlobalOrEvalDecl)) {
859         return false;
860       }
861 
862       for (DynamicBindingIter bi(evalsc); bi; bi++) {
863         MOZ_ASSERT(bi.bindingOp() == JSOp::DefVar);
864 
865         if (bi.isTopLevelFunction()) {
866           continue;
867         }
868 
869         if (!bce->emitAtomOp(JSOp::DefVar, bi.name())) {
870           return false;
871         }
872       }
873     }
874 
875     // As an optimization, if the eval does not have its own var
876     // environment and is directly enclosed in a global scope, then all
877     // free name lookups are global.
878     if (scope(bce).enclosing().is<GlobalScope>()) {
879       fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
880     }
881   }
882 
883   return true;
884 }
885 
enterModule(BytecodeEmitter * bce,ModuleSharedContext * modulesc)886 bool EmitterScope::enterModule(BytecodeEmitter* bce,
887                                ModuleSharedContext* modulesc) {
888   MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
889 
890   bce->setVarEmitterScope(this);
891 
892   if (!ensureCache(bce)) {
893     return false;
894   }
895 
896   // Resolve body-level bindings, if there are any.
897   TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
898   Maybe<uint32_t> firstLexicalFrameSlot;
899   if (ModuleScope::Data* bindings = modulesc->bindings) {
900     BindingIter bi(*bindings);
901     for (; bi; bi++) {
902       if (!checkSlotLimits(bce, bi)) {
903         return false;
904       }
905 
906       NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
907       if (!putNameInCache(bce, bi.name(), loc)) {
908         return false;
909       }
910 
911       if (BindingKindIsLexical(bi.kind())) {
912         if (loc.kind() == NameLocation::Kind::FrameSlot &&
913             !firstLexicalFrameSlot) {
914           firstLexicalFrameSlot = Some(loc.frameSlot());
915         }
916 
917         if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ)) {
918           return false;
919         }
920       }
921     }
922 
923     updateFrameFixedSlots(bce, bi);
924   } else {
925     nextFrameSlot_ = 0;
926   }
927 
928   // Modules are toplevel, so any free names are global.
929   fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
930 
931   // Put lexical frame slots in TDZ. Environment slots are poisoned during
932   // environment creation.
933   if (firstLexicalFrameSlot) {
934     if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd())) {
935       return false;
936     }
937   }
938 
939   // Create and intern the VM scope creation data.
940   auto createScope = [modulesc, bce](JSContext* cx,
941                                      Handle<AbstractScopePtr> enclosing,
942                                      ScopeIndex* index) {
943     return ScopeCreationData::create(cx, bce->compilationInfo,
944                                      modulesc->bindings, modulesc->module(),
945                                      enclosing, index);
946   };
947   if (!internBodyScopeCreationData(bce, createScope)) {
948     return false;
949   }
950 
951   return checkEnvironmentChainLength(bce);
952 }
953 
enterWith(BytecodeEmitter * bce)954 bool EmitterScope::enterWith(BytecodeEmitter* bce) {
955   MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
956 
957   if (!ensureCache(bce)) {
958     return false;
959   }
960 
961   // 'with' make all accesses dynamic and unanalyzable.
962   fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
963 
964   auto createScope = [bce](JSContext* cx, Handle<AbstractScopePtr> enclosing,
965                            ScopeIndex* index) {
966     return ScopeCreationData::create(cx, bce->compilationInfo, enclosing,
967                                      index);
968   };
969   if (!internScopeCreationData(bce, createScope)) {
970     return false;
971   }
972 
973   if (!bce->emitInternedScopeOp(index(), JSOp::EnterWith)) {
974     return false;
975   }
976 
977   if (!appendScopeNote(bce)) {
978     return false;
979   }
980 
981   return checkEnvironmentChainLength(bce);
982 }
983 
deadZoneFrameSlots(BytecodeEmitter * bce) const984 bool EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce) const {
985   return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
986 }
987 
leave(BytecodeEmitter * bce,bool nonLocal)988 bool EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal) {
989   // If we aren't leaving the scope due to a non-local jump (e.g., break),
990   // we must be the innermost scope.
991   MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
992 
993   ScopeKind kind = scope(bce).kind();
994   switch (kind) {
995     case ScopeKind::Lexical:
996     case ScopeKind::SimpleCatch:
997     case ScopeKind::Catch:
998     case ScopeKind::FunctionLexical:
999       if (!bce->emit1(hasEnvironment() ? JSOp::PopLexicalEnv
1000                                        : JSOp::DebugLeaveLexicalEnv)) {
1001         return false;
1002       }
1003       break;
1004 
1005     case ScopeKind::With:
1006       if (!bce->emit1(JSOp::LeaveWith)) {
1007         return false;
1008       }
1009       break;
1010 
1011     case ScopeKind::Function:
1012     case ScopeKind::FunctionBodyVar:
1013     case ScopeKind::NamedLambda:
1014     case ScopeKind::StrictNamedLambda:
1015     case ScopeKind::Eval:
1016     case ScopeKind::StrictEval:
1017     case ScopeKind::Global:
1018     case ScopeKind::NonSyntactic:
1019     case ScopeKind::Module:
1020       break;
1021 
1022     case ScopeKind::WasmInstance:
1023     case ScopeKind::WasmFunction:
1024       MOZ_CRASH("No wasm function scopes in JS");
1025   }
1026 
1027   // Finish up the scope if we are leaving it in LIFO fashion.
1028   if (!nonLocal) {
1029     // Popping scopes due to non-local jumps generate additional scope
1030     // notes. See NonLocalExitControl::prepareForNonLocalJump.
1031     if (ScopeKindIsInBody(kind)) {
1032       if (kind == ScopeKind::FunctionBodyVar) {
1033         // The extra function var scope is never popped once it's pushed,
1034         // so its scope note extends until the end of any possible code.
1035         bce->bytecodeSection().scopeNoteList().recordEndFunctionBodyVar(
1036             noteIndex_);
1037       } else {
1038         bce->bytecodeSection().scopeNoteList().recordEnd(
1039             noteIndex_, bce->bytecodeSection().offset());
1040       }
1041     }
1042   }
1043 
1044   return true;
1045 }
1046 
scope(const BytecodeEmitter * bce) const1047 AbstractScopePtr EmitterScope::scope(const BytecodeEmitter* bce) const {
1048   return bce->perScriptData().gcThingList().getScope(index());
1049 }
1050 
lookup(BytecodeEmitter * bce,JSAtom * name)1051 NameLocation EmitterScope::lookup(BytecodeEmitter* bce, JSAtom* name) {
1052   if (Maybe<NameLocation> loc = lookupInCache(bce, name)) {
1053     return *loc;
1054   }
1055   return searchAndCache(bce, name);
1056 }
1057 
locationBoundInScope(JSAtom * name,EmitterScope * target)1058 Maybe<NameLocation> EmitterScope::locationBoundInScope(JSAtom* name,
1059                                                        EmitterScope* target) {
1060   // The target scope must be an intra-frame enclosing scope of this
1061   // one. Count the number of extra hops to reach it.
1062   uint8_t extraHops = 0;
1063   for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
1064     if (es->hasEnvironment()) {
1065       extraHops++;
1066     }
1067   }
1068 
1069   // Caches are prepopulated with bound names. So if the name is bound in a
1070   // particular scope, it must already be in the cache. Furthermore, don't
1071   // consult the fallback location as we only care about binding names.
1072   Maybe<NameLocation> loc;
1073   if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) {
1074     NameLocation l = p->value().wrapped;
1075     if (l.kind() == NameLocation::Kind::EnvironmentCoordinate) {
1076       loc = Some(l.addHops(extraHops));
1077     } else {
1078       loc = Some(l);
1079     }
1080   }
1081   return loc;
1082 }
1083