Bug Summary

File:js/src/frontend/BytecodeEmitter.cpp
Warning:line 4486, column 9
Value stored to 'caseCount' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_js_src5.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -relaxed-aliasing -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -include /data/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /data/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/js-confdefs.h -I /data/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -D DEBUG=1 -D ENABLE_BINARYDATA -D ENABLE_SIMD -D ENABLE_WASM_SATURATING_TRUNC_OPS -D ENABLE_WASM_SIGNEXTEND_OPS -D ENABLE_WASM_THREAD_OPS -D ENABLE_WASM_GC -D ENABLE_WASM_GLOBAL -D WASM_HUGE_MEMORY -D JS_CACHEIR_SPEW -D ENABLE_SHARED_ARRAY_BUFFER -D EXPORT_JS_API -D JS_HAS_CTYPES -D DLL_PREFIX="lib" -D DLL_SUFFIX=".so" -D FFI_BUILDING -D MOZ_HAS_MOZGLUE -I /data/jenkins/workspace/firefox-scan-build/js/src -I /data/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src -I /data/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/ctypes/libffi/include -I /data/jenkins/workspace/firefox-scan-build/js/src/ctypes/libffi/src/x86 -I /data/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /data/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -D MOZILLA_CLIENT -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wwrite-strings -Wno-invalid-offsetof -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-shadow -fdeprecated-macro -fdebug-compilation-dir /data/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src -ferror-limit 19 -fmessage-length 0 -fno-rtti -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-04-16-165414-16038-1 -x c++ /data/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/Unified_cpp_js_src5.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7/*
8 * JS bytecode generation.
9 */
10
11#include "frontend/BytecodeEmitter.h"
12
13#include "mozilla/ArrayUtils.h"
14#include "mozilla/DebugOnly.h"
15#include "mozilla/FloatingPoint.h"
16#include "mozilla/Maybe.h"
17#include "mozilla/PodOperations.h"
18
19#include <string.h>
20
21#include "jsapi.h"
22#include "jsnum.h"
23#include "jstypes.h"
24#include "jsutil.h"
25
26#include "ds/Nestable.h"
27#include "frontend/Parser.h"
28#include "frontend/TokenStream.h"
29#include "vm/BytecodeUtil.h"
30#include "vm/Debugger.h"
31#include "vm/GeneratorObject.h"
32#include "vm/JSAtom.h"
33#include "vm/JSContext.h"
34#include "vm/JSFunction.h"
35#include "vm/JSScript.h"
36#include "vm/Stack.h"
37#include "wasm/AsmJS.h"
38
39#include "frontend/ParseNode-inl.h"
40#include "vm/EnvironmentObject-inl.h"
41#include "vm/JSAtom-inl.h"
42#include "vm/JSScript-inl.h"
43#include "vm/NativeObject-inl.h"
44
45using namespace js;
46using namespace js::gc;
47using namespace js::frontend;
48
49using mozilla::AssertedCast;
50using mozilla::DebugOnly;
51using mozilla::Maybe;
52using mozilla::Nothing;
53using mozilla::NumberIsInt32;
54using mozilla::PodCopy;
55using mozilla::Some;
56using mozilla::Unused;
57
58class BreakableControl;
59class LabelControl;
60class LoopControl;
61class ForOfLoopControl;
62class TryFinallyControl;
63
64static bool
65ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn)
66{
67 // The few node types listed below are exceptions to the usual
68 // location-source-note-emitting code in BytecodeEmitter::emitTree().
69 // Single-line `while` loops and C-style `for` loops require careful
70 // handling to avoid strange stepping behavior.
71 // Functions usually shouldn't have location information (bug 1431202).
72
73 ParseNodeKind kind = pn->getKind();
74 return kind == ParseNodeKind::While ||
75 kind == ParseNodeKind::For ||
76 kind == ParseNodeKind::Function;
77}
78
79// A cache that tracks superfluous TDZ checks.
80//
81// Each basic block should have a TDZCheckCache in scope. Some NestableControl
82// subclasses contain a TDZCheckCache.
83class BytecodeEmitter::TDZCheckCache : public Nestable<BytecodeEmitter::TDZCheckCache>
84{
85 PooledMapPtr<CheckTDZMap> cache_;
86
87 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool ensureCache(BytecodeEmitter* bce) {
88 return cache_ || cache_.acquire(bce->cx);
89 }
90
91 public:
92 explicit TDZCheckCache(BytecodeEmitter* bce)
93 : Nestable<TDZCheckCache>(&bce->innermostTDZCheckCache),
94 cache_(bce->cx->frontendCollectionPool())
95 { }
96
97 Maybe<MaybeCheckTDZ> needsTDZCheck(BytecodeEmitter* bce, JSAtom* name);
98 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool noteTDZCheck(BytecodeEmitter* bce, JSAtom* name, MaybeCheckTDZ check);
99};
100
101class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl>
102{
103 StatementKind kind_;
104
105 // The innermost scope when this was pushed.
106 EmitterScope* emitterScope_;
107
108 protected:
109 NestableControl(BytecodeEmitter* bce, StatementKind kind)
110 : Nestable<NestableControl>(&bce->innermostNestableControl),
111 kind_(kind),
112 emitterScope_(bce->innermostEmitterScope)
113 { }
114
115 public:
116 using Nestable<NestableControl>::enclosing;
117 using Nestable<NestableControl>::findNearest;
118
119 StatementKind kind() const {
120 return kind_;
121 }
122
123 EmitterScope* emitterScope() const {
124 return emitterScope_;
125 }
126
127 template <typename T>
128 bool is() const;
129
130 template <typename T>
131 T& as() {
132 MOZ_ASSERT(this->is<T>())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this->is<T>())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this->is<T>()))), 0
))) { MOZ_ReportAssertionFailure("this->is<T>()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 132); do { } while (false); do { *((volatile int*) __null) =
132; ::abort(); } while (false); } } while (false)
;
133 return static_cast<T&>(*this);
134 }
135};
136
137// Template specializations are disallowed in different namespaces; specialize
138// all the NestableControl subtypes up front.
139namespace js {
140namespace frontend {
141
142template <>
143bool
144BytecodeEmitter::NestableControl::is<BreakableControl>() const
145{
146 return StatementKindIsUnlabeledBreakTarget(kind_) || kind_ == StatementKind::Label;
147}
148
149template <>
150bool
151BytecodeEmitter::NestableControl::is<LabelControl>() const
152{
153 return kind_ == StatementKind::Label;
154}
155
156template <>
157bool
158BytecodeEmitter::NestableControl::is<LoopControl>() const
159{
160 return StatementKindIsLoop(kind_);
161}
162
163template <>
164bool
165BytecodeEmitter::NestableControl::is<ForOfLoopControl>() const
166{
167 return kind_ == StatementKind::ForOfLoop;
168}
169
170template <>
171bool
172BytecodeEmitter::NestableControl::is<TryFinallyControl>() const
173{
174 return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
175}
176
177} // namespace frontend
178} // namespace js
179
180class BreakableControl : public BytecodeEmitter::NestableControl
181{
182 public:
183 // Offset of the last break.
184 JumpList breaks;
185
186 BreakableControl(BytecodeEmitter* bce, StatementKind kind)
187 : NestableControl(bce, kind)
188 {
189 MOZ_ASSERT(is<BreakableControl>())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(is<BreakableControl>())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(is<BreakableControl>()
))), 0))) { MOZ_ReportAssertionFailure("is<BreakableControl>()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 189); do { } while (false); do { *((volatile int*) __null) =
189; ::abort(); } while (false); } } while (false)
;
190 }
191
192 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool patchBreaks(BytecodeEmitter* bce) {
193 return bce->emitJumpTargetAndPatch(breaks);
194 }
195};
196
197class LabelControl : public BreakableControl
198{
199 RootedAtom label_;
200
201 // The code offset when this was pushed. Used for effectfulness checking.
202 ptrdiff_t startOffset_;
203
204 public:
205 LabelControl(BytecodeEmitter* bce, JSAtom* label, ptrdiff_t startOffset)
206 : BreakableControl(bce, StatementKind::Label),
207 label_(bce->cx, label),
208 startOffset_(startOffset)
209 { }
210
211 HandleAtom label() const {
212 return label_;
213 }
214
215 ptrdiff_t startOffset() const {
216 return startOffset_;
217 }
218};
219
220class LoopControl : public BreakableControl
221{
222 // Loops' children are emitted in dominance order, so they can always
223 // have a TDZCheckCache.
224 BytecodeEmitter::TDZCheckCache tdzCache_;
225
226 // Stack depth when this loop was pushed on the control stack.
227 int32_t stackDepth_;
228
229 // The loop nesting depth. Used as a hint to Ion.
230 uint32_t loopDepth_;
231
232 // Can we OSR into Ion from here? True unless there is non-loop state on the stack.
233 bool canIonOsr_;
234
235 public:
236 // The target of continue statement jumps, e.g., the update portion of a
237 // for(;;) loop.
238 JumpTarget continueTarget;
239
240 // Offset of the last continue in the loop.
241 JumpList continues;
242
243 LoopControl(BytecodeEmitter* bce, StatementKind loopKind)
244 : BreakableControl(bce, loopKind),
245 tdzCache_(bce),
246 continueTarget({ -1 })
247 {
248 MOZ_ASSERT(is<LoopControl>())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(is<LoopControl>())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(is<LoopControl>()))), 0
))) { MOZ_ReportAssertionFailure("is<LoopControl>()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 248); do { } while (false); do { *((volatile int*) __null) =
248; ::abort(); } while (false); } } while (false)
;
249
250 LoopControl* enclosingLoop = findNearest<LoopControl>(enclosing());
251
252 stackDepth_ = bce->stackDepth;
253 loopDepth_ = enclosingLoop ? enclosingLoop->loopDepth_ + 1 : 1;
254
255 int loopSlots;
256 if (loopKind == StatementKind::Spread) {
257 // The iterator next method, the iterator, the result array, and
258 // the current array index are on the stack.
259 loopSlots = 4;
260 } else if (loopKind == StatementKind::ForOfLoop) {
261 // The iterator next method, the iterator, and the current value
262 // are on the stack.
263 loopSlots = 3;
264 } else if (loopKind == StatementKind::ForInLoop) {
265 // The iterator and the current value are on the stack.
266 loopSlots = 2;
267 } else {
268 // No additional loop values are on the stack.
269 loopSlots = 0;
270 }
271
272 MOZ_ASSERT(loopSlots <= stackDepth_)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(loopSlots <= stackDepth_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(loopSlots <= stackDepth_)
)), 0))) { MOZ_ReportAssertionFailure("loopSlots <= stackDepth_"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 272); do { } while (false); do { *((volatile int*) __null) =
272; ::abort(); } while (false); } } while (false)
;
273
274 if (enclosingLoop) {
275 canIonOsr_ = (enclosingLoop->canIonOsr_ &&
276 stackDepth_ == enclosingLoop->stackDepth_ + loopSlots);
277 } else {
278 canIonOsr_ = stackDepth_ == loopSlots;
279 }
280 }
281
282 uint32_t loopDepth() const {
283 return loopDepth_;
284 }
285
286 bool canIonOsr() const {
287 return canIonOsr_;
288 }
289
290 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool emitSpecialBreakForDone(BytecodeEmitter* bce) {
291 // This doesn't pop stack values, nor handle any other controls.
292 // Should be called on the toplevel of the loop.
293 MOZ_ASSERT(bce->stackDepth == stackDepth_)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bce->stackDepth == stackDepth_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce->stackDepth == stackDepth_
))), 0))) { MOZ_ReportAssertionFailure("bce->stackDepth == stackDepth_"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 293); do { } while (false); do { *((volatile int*) __null) =
293; ::abort(); } while (false); } } while (false)
;
294 MOZ_ASSERT(bce->innermostNestableControl == this)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bce->innermostNestableControl == this)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(bce->innermostNestableControl == this))), 0))) { MOZ_ReportAssertionFailure
("bce->innermostNestableControl == this", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 294); do { } while (false); do { *((volatile int*) __null) =
294; ::abort(); } while (false); } } while (false)
;
295
296 if (!bce->newSrcNote(SRC_BREAK))
297 return false;
298 if (!bce->emitJump(JSOP_GOTO, &breaks))
299 return false;
300
301 return true;
302 }
303
304 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool patchBreaksAndContinues(BytecodeEmitter* bce) {
305 MOZ_ASSERT(continueTarget.offset != -1)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(continueTarget.offset != -1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(continueTarget.offset != -1)
)), 0))) { MOZ_ReportAssertionFailure("continueTarget.offset != -1"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 305); do { } while (false); do { *((volatile int*) __null) =
305; ::abort(); } while (false); } } while (false)
;
306 if (!patchBreaks(bce))
307 return false;
308 bce->patchJumpsToTarget(continues, continueTarget);
309 return true;
310 }
311};
312
313class TryFinallyControl : public BytecodeEmitter::NestableControl
314{
315 bool emittingSubroutine_;
316
317 public:
318 // The subroutine when emitting a finally block.
319 JumpList gosubs;
320
321 TryFinallyControl(BytecodeEmitter* bce, StatementKind kind)
322 : NestableControl(bce, kind),
323 emittingSubroutine_(false)
324 {
325 MOZ_ASSERT(is<TryFinallyControl>())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(is<TryFinallyControl>())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(is<TryFinallyControl>(
)))), 0))) { MOZ_ReportAssertionFailure("is<TryFinallyControl>()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 325); do { } while (false); do { *((volatile int*) __null) =
325; ::abort(); } while (false); } } while (false)
;
326 }
327
328 void setEmittingSubroutine() {
329 emittingSubroutine_ = true;
330 }
331
332 bool emittingSubroutine() const {
333 return emittingSubroutine_;
334 }
335};
336
337static inline void
338MarkAllBindingsClosedOver(LexicalScope::Data& data)
339{
340 BindingName* names = data.names;
341 for (uint32_t i = 0; i < data.length; i++)
342 names[i] = BindingName(names[i].name(), true);
343}
344
345// A scope that introduces bindings.
346class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterScope>
347{
348 // The cache of bound names that may be looked up in the
349 // scope. Initially populated as the set of names this scope binds. As
350 // names are looked up in enclosing scopes, they are cached on the
351 // current scope.
352 PooledMapPtr<NameLocationMap> nameCache_;
353
354 // If this scope's cache does not include free names, such as the
355 // global scope, the NameLocation to return.
356 Maybe<NameLocation> fallbackFreeNameLocation_;
357
358 // True if there is a corresponding EnvironmentObject on the environment
359 // chain, false if all bindings are stored in frame slots on the stack.
360 bool hasEnvironment_;
361
362 // The number of enclosing environments. Used for error checking.
363 uint8_t environmentChainLength_;
364
365 // The next usable slot on the frame for not-closed over bindings.
366 //
367 // The initial frame slot when assigning slots to bindings is the
368 // enclosing scope's nextFrameSlot. For the first scope in a frame,
369 // the initial frame slot is 0.
370 uint32_t nextFrameSlot_;
371
372 // The index in the BytecodeEmitter's interned scope vector, otherwise
373 // ScopeNote::NoScopeIndex.
374 uint32_t scopeIndex_;
375
376 // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
377 // block scope note list. Otherwise ScopeNote::NoScopeNote.
378 uint32_t noteIndex_;
379
380 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool ensureCache(BytecodeEmitter* bce) {
381 return nameCache_.acquire(bce->cx);
382 }
383
384 template <typename BindingIter>
385 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool checkSlotLimits(BytecodeEmitter* bce, const BindingIter& bi) {
386 if (bi.nextFrameSlot() >= LOCALNO_LIMIT ||
387 bi.nextEnvironmentSlot() >= ENVCOORD_SLOT_LIMIT)
388 {
389 bce->reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
390 return false;
391 }
392 return true;
393 }
394
395 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool checkEnvironmentChainLength(BytecodeEmitter* bce) {
396 uint32_t hops;
397 if (EmitterScope* emitterScope = enclosing(&bce))
398 hops = emitterScope->environmentChainLength_;
399 else
400 hops = bce->sc->compilationEnclosingScope()->environmentChainLength();
401
402 if (hops >= ENVCOORD_HOPS_LIMIT - 1) {
403 bce->reportError(nullptr, JSMSG_TOO_DEEP, js_function_str);
404 return false;
405 }
406
407 environmentChainLength_ = mozilla::AssertedCast<uint8_t>(hops + 1);
408 return true;
409 }
410
411 void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi) {
412 nextFrameSlot_ = bi.nextFrameSlot();
413 if (nextFrameSlot_ > bce->maxFixedSlots)
414 bce->maxFixedSlots = nextFrameSlot_;
415 MOZ_ASSERT_IF(bce->sc->isFunctionBox() &&do { if (bce->sc->isFunctionBox() && (bce->sc
->asFunctionBox()->isGenerator() || bce->sc->asFunctionBox
()->isAsync())) { do { static_assert(mozilla::detail::AssertionConditionType
<decltype(bce->maxFixedSlots == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce->maxFixedSlots == 0))
), 0))) { MOZ_ReportAssertionFailure("bce->maxFixedSlots == 0"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 418); do { } while (false); do { *((volatile int*) __null) =
418; ::abort(); } while (false); } } while (false); } } while
(false)
416 (bce->sc->asFunctionBox()->isGenerator() ||do { if (bce->sc->isFunctionBox() && (bce->sc
->asFunctionBox()->isGenerator() || bce->sc->asFunctionBox
()->isAsync())) { do { static_assert(mozilla::detail::AssertionConditionType
<decltype(bce->maxFixedSlots == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce->maxFixedSlots == 0))
), 0))) { MOZ_ReportAssertionFailure("bce->maxFixedSlots == 0"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 418); do { } while (false); do { *((volatile int*) __null) =
418; ::abort(); } while (false); } } while (false); } } while
(false)
417 bce->sc->asFunctionBox()->isAsync()),do { if (bce->sc->isFunctionBox() && (bce->sc
->asFunctionBox()->isGenerator() || bce->sc->asFunctionBox
()->isAsync())) { do { static_assert(mozilla::detail::AssertionConditionType
<decltype(bce->maxFixedSlots == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce->maxFixedSlots == 0))
), 0))) { MOZ_ReportAssertionFailure("bce->maxFixedSlots == 0"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 418); do { } while (false); do { *((volatile int*) __null) =
418; ::abort(); } while (false); } } while (false); } } while
(false)
418 bce->maxFixedSlots == 0)do { if (bce->sc->isFunctionBox() && (bce->sc
->asFunctionBox()->isGenerator() || bce->sc->asFunctionBox
()->isAsync())) { do { static_assert(mozilla::detail::AssertionConditionType
<decltype(bce->maxFixedSlots == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce->maxFixedSlots == 0))
), 0))) { MOZ_ReportAssertionFailure("bce->maxFixedSlots == 0"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 418); do { } while (false); do { *((volatile int*) __null) =
418; ::abort(); } while (false); } } while (false); } } while
(false)
;
419 }
420
421 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool putNameInCache(BytecodeEmitter* bce, JSAtom* name, NameLocation loc) {
422 NameLocationMap& cache = *nameCache_;
423 NameLocationMap::AddPtr p = cache.lookupForAdd(name);
424 MOZ_ASSERT(!p)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!p)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!p))), 0))) { MOZ_ReportAssertionFailure
("!p", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 424); do { } while (false); do { *((volatile int*) __null) =
424; ::abort(); } while (false); } } while (false)
;
425 if (!cache.add(p, name, loc)) {
426 ReportOutOfMemory(bce->cx);
427 return false;
428 }
429 return true;
430 }
431
432 Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce, JSAtom* name) {
433 if (NameLocationMap::Ptr p = nameCache_->lookup(name))
434 return Some(p->value().wrapped);
435 if (fallbackFreeNameLocation_ && nameCanBeFree(bce, name))
436 return fallbackFreeNameLocation_;
437 return Nothing();
438 }
439
440 friend bool BytecodeEmitter::needsImplicitThis();
441
442 EmitterScope* enclosing(BytecodeEmitter** bce) const {
443 // There is an enclosing scope with access to the same frame.
444 if (EmitterScope* inFrame = enclosingInFrame())
445 return inFrame;
446
447 // We are currently compiling the enclosing script, look in the
448 // enclosing BCE.
449 if ((*bce)->parent) {
450 *bce = (*bce)->parent;
451 return (*bce)->innermostEmitterScope;
452 }
453
454 return nullptr;
455 }
456
457 Scope* enclosingScope(BytecodeEmitter* bce) const {
458 if (EmitterScope* es = enclosing(&bce))
459 return es->scope(bce);
460
461 // The enclosing script is already compiled or the current script is the
462 // global script.
463 return bce->sc->compilationEnclosingScope();
464 }
465
466 static bool nameCanBeFree(BytecodeEmitter* bce, JSAtom* name) {
467 // '.generator' cannot be accessed by name.
468 return name != bce->cx->names().dotGenerator;
469 }
470
471 static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops);
472 NameLocation searchAndCache(BytecodeEmitter* bce, JSAtom* name);
473
474 template <typename ScopeCreator>
475 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
476 template <typename ScopeCreator>
477 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope);
478 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool appendScopeNote(BytecodeEmitter* bce);
479
480 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
481 uint32_t slotEnd);
482
483 public:
484 explicit EmitterScope(BytecodeEmitter* bce)
485 : Nestable<EmitterScope>(&bce->innermostEmitterScope),
486 nameCache_(bce->cx->frontendCollectionPool()),
487 hasEnvironment_(false),
488 environmentChainLength_(0),
489 nextFrameSlot_(0),
490 scopeIndex_(ScopeNote::NoScopeIndex),
491 noteIndex_(ScopeNote::NoScopeNoteIndex)
492 { }
493
494 void dump(BytecodeEmitter* bce);
495
496 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
497 Handle<LexicalScope::Data*> bindings);
498 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
499 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
500 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox);
501 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterParameterExpressionVar(BytecodeEmitter* bce);
502 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc);
503 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
504 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterModule(BytecodeEmitter* module, ModuleSharedContext* modulesc);
505 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool enterWith(BytecodeEmitter* bce);
506 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool deadZoneFrameSlots(BytecodeEmitter* bce);
507
508 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool leave(BytecodeEmitter* bce, bool nonLocal = false);
509
510 uint32_t index() const {
511 MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, "Did you forget to intern a Scope?")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(scopeIndex_ != ScopeNote::NoScopeIndex)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(scopeIndex_ != ScopeNote::NoScopeIndex))), 0))) { MOZ_ReportAssertionFailure
("scopeIndex_ != ScopeNote::NoScopeIndex" " (" "Did you forget to intern a Scope?"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 511); do { } while (false); do { *((volatile int*) __null) =
511; ::abort(); } while (false); } } while (false)
;
512 return scopeIndex_;
513 }
514
515 uint32_t noteIndex() const {
516 return noteIndex_;
517 }
518
519 Scope* scope(const BytecodeEmitter* bce) const {
520 return bce->scopeList.vector[index()];
521 }
522
523 bool hasEnvironment() const {
524 return hasEnvironment_;
525 }
526
527 // The first frame slot used.
528 uint32_t frameSlotStart() const {
529 if (EmitterScope* inFrame = enclosingInFrame())
530 return inFrame->nextFrameSlot_;
531 return 0;
532 }
533
534 // The last frame slot used + 1.
535 uint32_t frameSlotEnd() const {
536 return nextFrameSlot_;
537 }
538
539 uint32_t numFrameSlots() const {
540 return frameSlotEnd() - frameSlotStart();
541 }
542
543 EmitterScope* enclosingInFrame() const {
544 return Nestable<EmitterScope>::enclosing();
545 }
546
547 NameLocation lookup(BytecodeEmitter* bce, JSAtom* name) {
548 if (Maybe<NameLocation> loc = lookupInCache(bce, name))
549 return *loc;
550 return searchAndCache(bce, name);
551 }
552
553 Maybe<NameLocation> locationBoundInScope(JSAtom* name, EmitterScope* target);
554};
555
556void
557BytecodeEmitter::EmitterScope::dump(BytecodeEmitter* bce)
558{
559 fprintf(stdoutstdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce)->kind()), this);
560
561 for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
562 const NameLocation& l = r.front().value();
563
564 JSAutoByteString bytes;
565 if (!AtomToPrintableString(bce->cx, r.front().key(), &bytes))
566 return;
567 if (l.kind() != NameLocation::Kind::Dynamic)
568 fprintf(stdoutstdout, " %s %s ", BindingKindString(l.bindingKind()), bytes.ptr());
569 else
570 fprintf(stdoutstdout, " %s ", bytes.ptr());
571
572 switch (l.kind()) {
573 case NameLocation::Kind::Dynamic:
574 fprintf(stdoutstdout, "dynamic\n");
575 break;
576 case NameLocation::Kind::Global:
577 fprintf(stdoutstdout, "global\n");
578 break;
579 case NameLocation::Kind::Intrinsic:
580 fprintf(stdoutstdout, "intrinsic\n");
581 break;
582 case NameLocation::Kind::NamedLambdaCallee:
583 fprintf(stdoutstdout, "named lambda callee\n");
584 break;
585 case NameLocation::Kind::Import:
586 fprintf(stdoutstdout, "import\n");
587 break;
588 case NameLocation::Kind::ArgumentSlot:
589 fprintf(stdoutstdout, "arg slot=%u\n", l.argumentSlot());
590 break;
591 case NameLocation::Kind::FrameSlot:
592 fprintf(stdoutstdout, "frame slot=%u\n", l.frameSlot());
593 break;
594 case NameLocation::Kind::EnvironmentCoordinate:
595 fprintf(stdoutstdout, "environment hops=%u slot=%u\n",
596 l.environmentCoordinate().hops(), l.environmentCoordinate().slot());
597 break;
598 case NameLocation::Kind::DynamicAnnexBVar:
599 fprintf(stdoutstdout, "dynamic annex b var\n");
600 break;
601 }
602 }
603
604 fprintf(stdoutstdout, "\n");
605}
606
607template <typename ScopeCreator>
608bool
609BytecodeEmitter::EmitterScope::internScope(BytecodeEmitter* bce, ScopeCreator createScope)
610{
611 RootedScope enclosing(bce->cx, enclosingScope(bce));
612 Scope* scope = createScope(bce->cx, enclosing);
613 if (!scope)
614 return false;
615 hasEnvironment_ = scope->hasEnvironment();
616 scopeIndex_ = bce->scopeList.length();
617 return bce->scopeList.append(scope);
618}
619
620template <typename ScopeCreator>
621bool
622BytecodeEmitter::EmitterScope::internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope)
623{
624 MOZ_ASSERT(bce->bodyScopeIndex == UINT32_MAX, "There can be only one body scope")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bce->bodyScopeIndex == (4294967295U))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(bce->bodyScopeIndex == (4294967295U)))), 0))) { MOZ_ReportAssertionFailure
("bce->bodyScopeIndex == (4294967295U)" " (" "There can be only one body scope"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 624); do { } while (false); do { *((volatile int*) __null) =
624; ::abort(); } while (false); } } while (false)
;
625 bce->bodyScopeIndex = bce->scopeList.length();
626 return internScope(bce, createScope);
627}
628
629bool
630BytecodeEmitter::EmitterScope::appendScopeNote(BytecodeEmitter* bce)
631{
632 MOZ_ASSERT(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame(),do { static_assert(mozilla::detail::AssertionConditionType<
decltype(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame
()))), 0))) { MOZ_ReportAssertionFailure("ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame()"
" (" "Scope notes are not needed for body-level scopes." ")"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 633); do { } while (false); do { *((volatile int*) __null) =
633; ::abort(); } while (false); } } while (false)
633 "Scope notes are not needed for body-level scopes.")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame
()))), 0))) { MOZ_ReportAssertionFailure("ScopeKindIsInBody(scope(bce)->kind()) && enclosingInFrame()"
" (" "Scope notes are not needed for body-level scopes." ")"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 633); do { } while (false); do { *((volatile int*) __null) =
633; ::abort(); } while (false); } } while (false)
;
634 noteIndex_ = bce->scopeNoteList.length();
635 return bce->scopeNoteList.append(index(), bce->offset(), bce->inPrologue(),
636 enclosingInFrame() ? enclosingInFrame()->noteIndex()
637 : ScopeNote::NoScopeNoteIndex);
638}
639
640#ifdef DEBUG1
641static bool
642NameIsOnEnvironment(Scope* scope, JSAtom* name)
643{
644 for (BindingIter bi(scope); bi; bi++) {
645 // If found, the name must already be on the environment or an import,
646 // or else there is a bug in the closed-over name analysis in the
647 // Parser.
648 if (bi.name() == name) {
649 BindingLocation::Kind kind = bi.location().kind();
650
651 if (bi.hasArgumentSlot()) {
652 JSScript* script = scope->as<FunctionScope>().script();
653 if (!script->strict() && !script->functionHasParameterExprs()) {
654 // Check for duplicate positional formal parameters.
655 for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
656 if (bi2.name() == name)
657 kind = bi2.location().kind();
658 }
659 }
660 }
661
662 return kind == BindingLocation::Kind::Global ||
663 kind == BindingLocation::Kind::Environment ||
664 kind == BindingLocation::Kind::Import;
665 }
666 }
667
668 // If not found, assume it's on the global or dynamically accessed.
669 return true;
670}
671#endif
672
673/* static */ NameLocation
674BytecodeEmitter::EmitterScope::searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops)
675{
676 for (ScopeIter si(scope); si; si++) {
677 MOZ_ASSERT(NameIsOnEnvironment(si.scope(), name))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(NameIsOnEnvironment(si.scope(), name))>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(NameIsOnEnvironment(si.scope(), name)))), 0))) { MOZ_ReportAssertionFailure
("NameIsOnEnvironment(si.scope(), name)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 677); do { } while (false); do { *((volatile int*) __null) =
677; ::abort(); } while (false); } } while (false)
;
678
679 bool hasEnv = si.hasSyntacticEnvironment();
680
681 switch (si.kind()) {
682 case ScopeKind::Function:
683 if (hasEnv) {
684 JSScript* script = si.scope()->as<FunctionScope>().script();
685 if (script->funHasExtensibleScope())
686 return NameLocation::Dynamic();
687
688 for (BindingIter bi(si.scope()); bi; bi++) {
689 if (bi.name() != name)
690 continue;
691
692 BindingLocation bindLoc = bi.location();
693 if (bi.hasArgumentSlot() &&
694 !script->strict() &&
695 !script->functionHasParameterExprs())
696 {
697 // Check for duplicate positional formal parameters.
698 for (BindingIter bi2(bi); bi2 && bi2.hasArgumentSlot(); bi2++) {
699 if (bi2.name() == name)
700 bindLoc = bi2.location();
701 }
702 }
703
704 MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bindLoc.kind() == BindingLocation::Kind::Environment
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(bindLoc.kind() == BindingLocation::Kind::Environment
))), 0))) { MOZ_ReportAssertionFailure("bindLoc.kind() == BindingLocation::Kind::Environment"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 704); do { } while (false); do { *((volatile int*) __null) =
704; ::abort(); } while (false); } } while (false)
;
705 return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
706 }
707 }
708 break;
709
710 case ScopeKind::FunctionBodyVar:
711 case ScopeKind::ParameterExpressionVar:
712 case ScopeKind::Lexical:
713 case ScopeKind::NamedLambda:
714 case ScopeKind::StrictNamedLambda:
715 case ScopeKind::SimpleCatch:
716 case ScopeKind::Catch:
717 if (hasEnv) {
718 for (BindingIter bi(si.scope()); bi; bi++) {
719 if (bi.name() != name)
720 continue;
721
722 // The name must already have been marked as closed
723 // over. If this assertion is hit, there is a bug in the
724 // name analysis.
725 BindingLocation bindLoc = bi.location();
726 MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bindLoc.kind() == BindingLocation::Kind::Environment
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(bindLoc.kind() == BindingLocation::Kind::Environment
))), 0))) { MOZ_ReportAssertionFailure("bindLoc.kind() == BindingLocation::Kind::Environment"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 726); do { } while (false); do { *((volatile int*) __null) =
726; ::abort(); } while (false); } } while (false)
;
727 return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
728 }
729 }
730 break;
731
732 case ScopeKind::Module:
733 if (hasEnv) {
734 for (BindingIter bi(si.scope()); bi; bi++) {
735 if (bi.name() != name)
736 continue;
737
738 BindingLocation bindLoc = bi.location();
739
740 // Imports are on the environment but are indirect
741 // bindings and must be accessed dynamically instead of
742 // using an EnvironmentCoordinate.
743 if (bindLoc.kind() == BindingLocation::Kind::Import) {
744 MOZ_ASSERT(si.kind() == ScopeKind::Module)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(si.kind() == ScopeKind::Module)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(si.kind() == ScopeKind::Module
))), 0))) { MOZ_ReportAssertionFailure("si.kind() == ScopeKind::Module"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 744); do { } while (false); do { *((volatile int*) __null) =
744; ::abort(); } while (false); } } while (false)
;
745 return NameLocation::Import();
746 }
747
748 MOZ_ASSERT(bindLoc.kind() == BindingLocation::Kind::Environment)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bindLoc.kind() == BindingLocation::Kind::Environment
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(bindLoc.kind() == BindingLocation::Kind::Environment
))), 0))) { MOZ_ReportAssertionFailure("bindLoc.kind() == BindingLocation::Kind::Environment"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 748); do { } while (false); do { *((volatile int*) __null) =
748; ::abort(); } while (false); } } while (false)
;
749 return NameLocation::EnvironmentCoordinate(bi.kind(), hops, bindLoc.slot());
750 }
751 }
752 break;
753
754 case ScopeKind::Eval:
755 case ScopeKind::StrictEval:
756 // As an optimization, if the eval doesn't have its own var
757 // environment and its immediate enclosing scope is a global
758 // scope, all accesses are global.
759 if (!hasEnv && si.scope()->enclosing()->is<GlobalScope>())
760 return NameLocation::Global(BindingKind::Var);
761 return NameLocation::Dynamic();
762
763 case ScopeKind::Global:
764 return NameLocation::Global(BindingKind::Var);
765
766 case ScopeKind::With:
767 case ScopeKind::NonSyntactic:
768 return NameLocation::Dynamic();
769
770 case ScopeKind::WasmInstance:
771 case ScopeKind::WasmFunction:
772 MOZ_CRASH("No direct eval inside wasm functions")do { MOZ_ReportCrash("" "No direct eval inside wasm functions"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 772); do { } while (false); do { *((volatile int*) __null) =
772; ::abort(); } while (false); } while (false)
;
773 }
774
775 if (hasEnv) {
776 MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT - 1)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(hops < ENVCOORD_HOPS_LIMIT - 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hops < ENVCOORD_HOPS_LIMIT
- 1))), 0))) { MOZ_ReportAssertionFailure("hops < ENVCOORD_HOPS_LIMIT - 1"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 776); do { } while (false); do { *((volatile int*) __null) =
776; ::abort(); } while (false); } } while (false)
;
777 hops++;
778 }
779 }
780
781 MOZ_CRASH("Malformed scope chain")do { MOZ_ReportCrash("" "Malformed scope chain", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 781); do { } while (false); do { *((volatile int*) __null) =
781; ::abort(); } while (false); } while (false)
;
782}
783
784NameLocation
785BytecodeEmitter::EmitterScope::searchAndCache(BytecodeEmitter* bce, JSAtom* name)
786{
787 Maybe<NameLocation> loc;
788 uint8_t hops = hasEnvironment() ? 1 : 0;
789 DebugOnly<bool> inCurrentScript = enclosingInFrame();
790
791 // Start searching in the current compilation.
792 for (EmitterScope* es = enclosing(&bce); es; es = es->enclosing(&bce)) {
793 loc = es->lookupInCache(bce, name);
794 if (loc) {
795 if (loc->kind() == NameLocation::Kind::EnvironmentCoordinate)
796 *loc = loc->addHops(hops);
797 break;
798 }
799
800 if (es->hasEnvironment())
801 hops++;
802
803#ifdef DEBUG1
804 if (!es->enclosingInFrame())
805 inCurrentScript = false;
806#endif
807 }
808
809 // If the name is not found in the current compilation, walk the Scope
810 // chain encompassing the compilation.
811 if (!loc) {
812 inCurrentScript = false;
813 loc = Some(searchInEnclosingScope(name, bce->sc->compilationEnclosingScope(), hops));
814 }
815
816 // Each script has its own frame. A free name that is accessed
817 // from an inner script must not be a frame slot access. If this
818 // assertion is hit, it is a bug in the free name analysis in the
819 // parser.
820 MOZ_ASSERT_IF(!inCurrentScript, loc->kind() != NameLocation::Kind::FrameSlot)do { if (!inCurrentScript) { do { static_assert(mozilla::detail
::AssertionConditionType<decltype(loc->kind() != NameLocation
::Kind::FrameSlot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(loc->kind() != NameLocation
::Kind::FrameSlot))), 0))) { MOZ_ReportAssertionFailure("loc->kind() != NameLocation::Kind::FrameSlot"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 820); do { } while (false); do { *((volatile int*) __null) =
820; ::abort(); } while (false); } } while (false); } } while
(false)
;
821
822 // It is always correct to not cache the location. Ignore OOMs to make
823 // lookups infallible.
824 if (!putNameInCache(bce, name, *loc))
825 bce->cx->recoverFromOutOfMemory();
826
827 return *loc;
828}
829
830Maybe<NameLocation>
831BytecodeEmitter::EmitterScope::locationBoundInScope(JSAtom* name, EmitterScope* target)
832{
833 // The target scope must be an intra-frame enclosing scope of this
834 // one. Count the number of extra hops to reach it.
835 uint8_t extraHops = 0;
836 for (EmitterScope* es = this; es != target; es = es->enclosingInFrame()) {
837 if (es->hasEnvironment())
838 extraHops++;
839 }
840
841 // Caches are prepopulated with bound names. So if the name is bound in a
842 // particular scope, it must already be in the cache. Furthermore, don't
843 // consult the fallback location as we only care about binding names.
844 Maybe<NameLocation> loc;
845 if (NameLocationMap::Ptr p = target->nameCache_->lookup(name)) {
846 NameLocation l = p->value().wrapped;
847 if (l.kind() == NameLocation::Kind::EnvironmentCoordinate)
848 loc = Some(l.addHops(extraHops));
849 else
850 loc = Some(l);
851 }
852 return loc;
853}
854
855bool
856BytecodeEmitter::EmitterScope::deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
857 uint32_t slotEnd)
858{
859 // Lexical bindings throw ReferenceErrors if they are used before
860 // initialization. See ES6 8.1.1.1.6.
861 //
862 // For completeness, lexical bindings are initialized in ES6 by calling
863 // InitializeBinding, after which touching the binding will no longer
864 // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6,
865 // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15.
866 if (slotStart != slotEnd) {
867 if (!bce->emit1(JSOP_UNINITIALIZED))
868 return false;
869 for (uint32_t slot = slotStart; slot < slotEnd; slot++) {
870 if (!bce->emitLocalOp(JSOP_INITLEXICAL, slot))
871 return false;
872 }
873 if (!bce->emit1(JSOP_POP))
874 return false;
875 }
876
877 return true;
878}
879
880bool
881BytecodeEmitter::EmitterScope::deadZoneFrameSlots(BytecodeEmitter* bce)
882{
883 return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
884}
885
886bool
887BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
888 Handle<LexicalScope::Data*> bindings)
889{
890 MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(kind != ScopeKind::NamedLambda && kind != ScopeKind
::StrictNamedLambda)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(kind != ScopeKind::NamedLambda
&& kind != ScopeKind::StrictNamedLambda))), 0))) { MOZ_ReportAssertionFailure
("kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 890); do { } while (false); do { *((volatile int*) __null) =
890; ::abort(); } while (false); } } while (false)
;
891 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 891); do { } while (false); do { *((volatile int*) __null) =
891; ::abort(); } while (false); } } while (false)
;
892
893 if (!ensureCache(bce))
894 return false;
895
896 // Marks all names as closed over if the context requires it. This
897 // cannot be done in the Parser as we may not know if the context requires
898 // all bindings to be closed over until after parsing is finished. For
899 // example, legacy generators require all bindings to be closed over but
900 // it is unknown if a function is a legacy generator until the first
901 // 'yield' expression is parsed.
902 //
903 // This is not a problem with other scopes, as all other scopes with
904 // bindings are body-level. At the time of their creation, whether or not
905 // the context requires all bindings to be closed over is already known.
906 if (bce->sc->allBindingsClosedOver())
907 MarkAllBindingsClosedOver(*bindings);
908
909 // Resolve bindings.
910 TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
911 uint32_t firstFrameSlot = frameSlotStart();
912 BindingIter bi(*bindings, firstFrameSlot, /* isNamedLambda = */ false);
913 for (; bi; bi++) {
914 if (!checkSlotLimits(bce, bi))
915 return false;
916
917 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
918 if (!putNameInCache(bce, bi.name(), loc))
919 return false;
920
921 if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
922 return false;
923 }
924
925 updateFrameFixedSlots(bce, bi);
926
927 // Create and intern the VM scope.
928 auto createScope = [kind, bindings, firstFrameSlot](JSContext* cx,
929 HandleScope enclosing)
930 {
931 return LexicalScope::create(cx, kind, bindings, firstFrameSlot, enclosing);
932 };
933 if (!internScope(bce, createScope))
934 return false;
935
936 if (ScopeKindIsInBody(kind) && hasEnvironment()) {
937 // After interning the VM scope we can get the scope index.
938 if (!bce->emitInternedScopeOp(index(), JSOP_PUSHLEXICALENV))
939 return false;
940 }
941
942 // Lexical scopes need notes to be mapped from a pc.
943 if (!appendScopeNote(bce))
944 return false;
945
946 // Put frame slots in TDZ. Environment slots are poisoned during
947 // environment creation.
948 //
949 // This must be done after appendScopeNote to be considered in the extent
950 // of the scope.
951 if (!deadZoneFrameSlotRange(bce, firstFrameSlot, frameSlotEnd()))
952 return false;
953
954 return checkEnvironmentChainLength(bce);
955}
956
957bool
958BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
959{
960 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 960); do { } while (false); do { *((volatile int*) __null) =
960; ::abort(); } while (false); } } while (false)
;
961 MOZ_ASSERT(funbox->namedLambdaBindings())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(funbox->namedLambdaBindings())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(funbox->namedLambdaBindings
()))), 0))) { MOZ_ReportAssertionFailure("funbox->namedLambdaBindings()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 961); do { } while (false); do { *((volatile int*) __null) =
961; ::abort(); } while (false); } } while (false)
;
962
963 if (!ensureCache(bce))
964 return false;
965
966 // See comment in enterLexical about allBindingsClosedOver.
967 if (funbox->allBindingsClosedOver())
968 MarkAllBindingsClosedOver(*funbox->namedLambdaBindings());
969
970 BindingIter bi(*funbox->namedLambdaBindings(), LOCALNO_LIMIT, /* isNamedLambda = */ true);
971 MOZ_ASSERT(bi.kind() == BindingKind::NamedLambdaCallee)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bi.kind() == BindingKind::NamedLambdaCallee)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(bi.kind() == BindingKind::NamedLambdaCallee))), 0))) { MOZ_ReportAssertionFailure
("bi.kind() == BindingKind::NamedLambdaCallee", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 971); do { } while (false); do { *((volatile int*) __null) =
971; ::abort(); } while (false); } } while (false)
;
972
973 // The lambda name, if not closed over, is accessed via JSOP_CALLEE and
974 // not a frame slot. Do not update frame slot information.
975 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
976 if (!putNameInCache(bce, bi.name(), loc))
977 return false;
978
979 bi++;
980 MOZ_ASSERT(!bi, "There should be exactly one binding in a NamedLambda scope")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!bi)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!bi))), 0))) { MOZ_ReportAssertionFailure
("!bi" " (" "There should be exactly one binding in a NamedLambda scope"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 980); do { } while (false); do { *((volatile int*) __null) =
980; ::abort(); } while (false); } } while (false)
;
981
982 auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
983 ScopeKind scopeKind =
984 funbox->strict() ? ScopeKind::StrictNamedLambda : ScopeKind::NamedLambda;
985 return LexicalScope::create(cx, scopeKind, funbox->namedLambdaBindings(),
986 LOCALNO_LIMIT, enclosing);
987 };
988 if (!internScope(bce, createScope))
989 return false;
990
991 return checkEnvironmentChainLength(bce);
992}
993
994bool
995BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
996{
997 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 997); do { } while (false); do { *((volatile int*) __null) =
997; ::abort(); } while (false); } } while (false)
;
998
999 if (!ensureCache(bce))
1000 return false;
1001
1002 // Parameter expressions var scopes have no pre-set bindings and are
1003 // always extensible, as they are needed for eval.
1004 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1005
1006 // Create and intern the VM scope.
1007 uint32_t firstFrameSlot = frameSlotStart();
1008 auto createScope = [firstFrameSlot](JSContext* cx, HandleScope enclosing) {
1009 return VarScope::create(cx, ScopeKind::ParameterExpressionVar,
1010 /* data = */ nullptr, firstFrameSlot,
1011 /* needsEnvironment = */ true, enclosing);
1012 };
1013 if (!internScope(bce, createScope))
1014 return false;
1015
1016 MOZ_ASSERT(hasEnvironment())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(hasEnvironment())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hasEnvironment()))), 0))) { MOZ_ReportAssertionFailure
("hasEnvironment()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1016); do { } while (false); do { *((volatile int*) __null)
= 1016; ::abort(); } while (false); } } while (false)
;
1017 if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1018 return false;
1019
1020 // The extra var scope needs a note to be mapped from a pc.
1021 if (!appendScopeNote(bce))
1022 return false;
1023
1024 return checkEnvironmentChainLength(bce);
1025}
1026
1027bool
1028BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
1029{
1030 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1030); do { } while (false); do { *((volatile int*) __null)
= 1030; ::abort(); } while (false); } } while (false)
;
1031
1032 // If there are parameter expressions, there is an extra var scope.
1033 if (!funbox->hasExtraBodyVarScope())
1034 bce->setVarEmitterScope(this);
1035
1036 if (!ensureCache(bce))
1037 return false;
1038
1039 // Resolve body-level bindings, if there are any.
1040 auto bindings = funbox->functionScopeBindings();
1041 Maybe<uint32_t> lastLexicalSlot;
1042 if (bindings) {
1043 NameLocationMap& cache = *nameCache_;
1044
1045 BindingIter bi(*bindings, funbox->hasParameterExprs);
1046 for (; bi; bi++) {
1047 if (!checkSlotLimits(bce, bi))
1048 return false;
1049
1050 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1051 NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
1052
1053 // The only duplicate bindings that occur are simple formal
1054 // parameters, in which case the last position counts, so update the
1055 // location.
1056 if (p) {
1057 MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bi.kind() == BindingKind::FormalParameter)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(bi.kind() == BindingKind::FormalParameter))), 0))) { MOZ_ReportAssertionFailure
("bi.kind() == BindingKind::FormalParameter", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1057); do { } while (false); do { *((volatile int*) __null)
= 1057; ::abort(); } while (false); } } while (false)
;
1058 MOZ_ASSERT(!funbox->hasDestructuringArgs)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!funbox->hasDestructuringArgs)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!funbox->hasDestructuringArgs
))), 0))) { MOZ_ReportAssertionFailure("!funbox->hasDestructuringArgs"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1058); do { } while (false); do { *((volatile int*) __null)
= 1058; ::abort(); } while (false); } } while (false)
;
1059 MOZ_ASSERT(!funbox->hasRest())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!funbox->hasRest())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!funbox->hasRest()))), 0)
)) { MOZ_ReportAssertionFailure("!funbox->hasRest()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1059); do { } while (false); do { *((volatile int*) __null)
= 1059; ::abort(); } while (false); } } while (false)
;
1060 p->value() = loc;
1061 continue;
1062 }
1063
1064 if (!cache.add(p, bi.name(), loc)) {
1065 ReportOutOfMemory(bce->cx);
1066 return false;
1067 }
1068 }
1069
1070 updateFrameFixedSlots(bce, bi);
1071 } else {
1072 nextFrameSlot_ = 0;
1073 }
1074
1075 // If the function's scope may be extended at runtime due to sloppy direct
1076 // eval and there is no extra var scope, any names beyond the function
1077 // scope must be accessed dynamically as we don't know if the name will
1078 // become a 'var' binding due to direct eval.
1079 if (!funbox->hasParameterExprs && funbox->hasExtensibleScope())
1080 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1081
1082 // In case of parameter expressions, the parameters are lexical
1083 // bindings and have TDZ.
1084 if (funbox->hasParameterExprs && nextFrameSlot_) {
1085 uint32_t paramFrameSlotEnd = 0;
1086 for (BindingIter bi(*bindings, true); bi; bi++) {
1087 if (!BindingKindIsLexical(bi.kind()))
1088 break;
1089
1090 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1091 if (loc.kind() == NameLocation::Kind::FrameSlot) {
1092 MOZ_ASSERT(paramFrameSlotEnd <= loc.frameSlot())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(paramFrameSlotEnd <= loc.frameSlot())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(paramFrameSlotEnd <= loc.frameSlot()))), 0))) { MOZ_ReportAssertionFailure
("paramFrameSlotEnd <= loc.frameSlot()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1092); do { } while (false); do { *((volatile int*) __null)
= 1092; ::abort(); } while (false); } } while (false)
;
1093 paramFrameSlotEnd = loc.frameSlot() + 1;
1094 }
1095 }
1096
1097 if (!deadZoneFrameSlotRange(bce, 0, paramFrameSlotEnd))
1098 return false;
1099 }
1100
1101 // Create and intern the VM scope.
1102 auto createScope = [funbox](JSContext* cx, HandleScope enclosing) {
1103 RootedFunction fun(cx, funbox->function());
1104 return FunctionScope::create(cx, funbox->functionScopeBindings(),
1105 funbox->hasParameterExprs,
1106 funbox->needsCallObjectRegardlessOfBindings(),
1107 fun, enclosing);
1108 };
1109 if (!internBodyScope(bce, createScope))
1110 return false;
1111
1112 return checkEnvironmentChainLength(bce);
1113}
1114
1115bool
1116BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox)
1117{
1118 MOZ_ASSERT(funbox->hasParameterExprs)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(funbox->hasParameterExprs)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(funbox->hasParameterExprs
))), 0))) { MOZ_ReportAssertionFailure("funbox->hasParameterExprs"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1118); do { } while (false); do { *((volatile int*) __null)
= 1118; ::abort(); } while (false); } } while (false)
;
1119 MOZ_ASSERT(funbox->extraVarScopeBindings() ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(funbox->extraVarScopeBindings() || funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(funbox->extraVarScopeBindings() || funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings
()))), 0))) { MOZ_ReportAssertionFailure("funbox->extraVarScopeBindings() || funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1120); do { } while (false); do { *((volatile int*) __null)
= 1120; ::abort(); } while (false); } } while (false)
1120 funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(funbox->extraVarScopeBindings() || funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(funbox->extraVarScopeBindings() || funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings
()))), 0))) { MOZ_ReportAssertionFailure("funbox->extraVarScopeBindings() || funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1120); do { } while (false); do { *((volatile int*) __null)
= 1120; ::abort(); } while (false); } } while (false)
;
1121 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1121); do { } while (false); do { *((volatile int*) __null)
= 1121; ::abort(); } while (false); } } while (false)
;
1122
1123 // The extra var scope is never popped once it's entered. It replaces the
1124 // function scope as the var emitter scope.
1125 bce->setVarEmitterScope(this);
1126
1127 if (!ensureCache(bce))
1128 return false;
1129
1130 // Resolve body-level bindings, if there are any.
1131 uint32_t firstFrameSlot = frameSlotStart();
1132 if (auto bindings = funbox->extraVarScopeBindings()) {
1133 BindingIter bi(*bindings, firstFrameSlot);
1134 for (; bi; bi++) {
1135 if (!checkSlotLimits(bce, bi))
1136 return false;
1137
1138 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1139 if (!putNameInCache(bce, bi.name(), loc))
1140 return false;
1141 }
1142
1143 updateFrameFixedSlots(bce, bi);
1144 } else {
1145 nextFrameSlot_ = firstFrameSlot;
1146 }
1147
1148 // If the extra var scope may be extended at runtime due to sloppy
1149 // direct eval, any names beyond the var scope must be accessed
1150 // dynamically as we don't know if the name will become a 'var' binding
1151 // due to direct eval.
1152 if (funbox->hasExtensibleScope())
1153 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1154
1155 // Create and intern the VM scope.
1156 auto createScope = [funbox, firstFrameSlot](JSContext* cx, HandleScope enclosing) {
1157 return VarScope::create(cx, ScopeKind::FunctionBodyVar,
1158 funbox->extraVarScopeBindings(), firstFrameSlot,
1159 funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings(),
1160 enclosing);
1161 };
1162 if (!internScope(bce, createScope))
1163 return false;
1164
1165 if (hasEnvironment()) {
1166 if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1167 return false;
1168 }
1169
1170 // The extra var scope needs a note to be mapped from a pc.
1171 if (!appendScopeNote(bce))
1172 return false;
1173
1174 return checkEnvironmentChainLength(bce);
1175}
1176
1177class DynamicBindingIter : public BindingIter
1178{
1179 public:
1180 explicit DynamicBindingIter(GlobalSharedContext* sc)
1181 : BindingIter(*sc->bindings)
1182 { }
1183
1184 explicit DynamicBindingIter(EvalSharedContext* sc)
1185 : BindingIter(*sc->bindings, /* strict = */ false)
1186 {
1187 MOZ_ASSERT(!sc->strict())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!sc->strict())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sc->strict()))), 0))) { MOZ_ReportAssertionFailure
("!sc->strict()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1187); do { } while (false); do { *((volatile int*) __null)
= 1187; ::abort(); } while (false); } } while (false)
;
1188 }
1189
1190 JSOp bindingOp() const {
1191 switch (kind()) {
1192 case BindingKind::Var:
1193 return JSOP_DEFVAR;
1194 case BindingKind::Let:
1195 return JSOP_DEFLET;
1196 case BindingKind::Const:
1197 return JSOP_DEFCONST;
1198 default:
1199 MOZ_CRASH("Bad BindingKind")do { MOZ_ReportCrash("" "Bad BindingKind", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1199); do { } while (false); do { *((volatile int*) __null)
= 1199; ::abort(); } while (false); } while (false)
;
1200 }
1201 }
1202};
1203
1204bool
1205BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
1206{
1207 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1207); do { } while (false); do { *((volatile int*) __null)
= 1207; ::abort(); } while (false); } } while (false)
;
1208
1209 bce->setVarEmitterScope(this);
1210
1211 if (!ensureCache(bce))
1212 return false;
1213
1214 if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
1215 // In self-hosting, it is incorrect to consult the global scope because
1216 // self-hosted scripts are cloned into their target compartments before
1217 // they are run. Instead of Global, Intrinsic is used for all names.
1218 //
1219 // Intrinsic lookups are redirected to the special intrinsics holder
1220 // in the global object, into which any missing values are cloned
1221 // lazily upon first access.
1222 fallbackFreeNameLocation_ = Some(NameLocation::Intrinsic());
1223
1224 auto createScope = [](JSContext* cx, HandleScope enclosing) {
1225 MOZ_ASSERT(!enclosing)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!enclosing)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!enclosing))), 0))) { MOZ_ReportAssertionFailure
("!enclosing", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1225); do { } while (false); do { *((volatile int*) __null)
= 1225; ::abort(); } while (false); } } while (false)
;
1226 return &cx->global()->emptyGlobalScope();
1227 };
1228 return internBodyScope(bce, createScope);
1229 }
1230
1231 // Resolve binding names and emit DEF{VAR,LET,CONST} prologue ops.
1232 if (globalsc->bindings) {
1233 for (DynamicBindingIter bi(globalsc); bi; bi++) {
1234 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1235 JSAtom* name = bi.name();
1236 if (!putNameInCache(bce, name, loc))
1237 return false;
1238
1239 // Define the name in the prologue. Do not emit DEFVAR for
1240 // functions that we'll emit DEFFUN for.
1241 if (bi.isTopLevelFunction())
1242 continue;
1243
1244 if (!bce->emitAtomOp(name, bi.bindingOp()))
1245 return false;
1246 }
1247 }
1248
1249 // Note that to save space, we don't add free names to the cache for
1250 // global scopes. They are assumed to be global vars in the syntactic
1251 // global scope, dynamic accesses under non-syntactic global scope.
1252 if (globalsc->scopeKind() == ScopeKind::Global)
1253 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1254 else
1255 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1256
1257 auto createScope = [globalsc](JSContext* cx, HandleScope enclosing) {
1258 MOZ_ASSERT(!enclosing)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!enclosing)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!enclosing))), 0))) { MOZ_ReportAssertionFailure
("!enclosing", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1258); do { } while (false); do { *((volatile int*) __null)
= 1258; ::abort(); } while (false); } } while (false)
;
1259 return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
1260 };
1261 return internBodyScope(bce, createScope);
1262}
1263
1264bool
1265BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
1266{
1267 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1267); do { } while (false); do { *((volatile int*) __null)
= 1267; ::abort(); } while (false); } } while (false)
;
1268
1269 bce->setVarEmitterScope(this);
1270
1271 if (!ensureCache(bce))
1272 return false;
1273
1274 // For simplicity, treat all free name lookups in eval scripts as dynamic.
1275 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1276
1277 // Create the `var` scope. Note that there is also a lexical scope, created
1278 // separately in emitScript().
1279 auto createScope = [evalsc](JSContext* cx, HandleScope enclosing) {
1280 ScopeKind scopeKind = evalsc->strict() ? ScopeKind::StrictEval : ScopeKind::Eval;
1281 return EvalScope::create(cx, scopeKind, evalsc->bindings, enclosing);
1282 };
1283 if (!internBodyScope(bce, createScope))
1284 return false;
1285
1286 if (hasEnvironment()) {
1287 if (!bce->emitInternedScopeOp(index(), JSOP_PUSHVARENV))
1288 return false;
1289 } else {
1290 // Resolve binding names and emit DEFVAR prologue ops if we don't have
1291 // an environment (i.e., a sloppy eval not in a parameter expression).
1292 // Eval scripts always have their own lexical scope, but non-strict
1293 // scopes may introduce 'var' bindings to the nearest var scope.
1294 //
1295 // TODO: We may optimize strict eval bindings in the future to be on
1296 // the frame. For now, handle everything dynamically.
1297 if (!hasEnvironment() && evalsc->bindings) {
1298 for (DynamicBindingIter bi(evalsc); bi; bi++) {
1299 MOZ_ASSERT(bi.bindingOp() == JSOP_DEFVAR)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bi.bindingOp() == JSOP_DEFVAR)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bi.bindingOp() == JSOP_DEFVAR
))), 0))) { MOZ_ReportAssertionFailure("bi.bindingOp() == JSOP_DEFVAR"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1299); do { } while (false); do { *((volatile int*) __null)
= 1299; ::abort(); } while (false); } } while (false)
;
1300
1301 if (bi.isTopLevelFunction())
1302 continue;
1303
1304 if (!bce->emitAtomOp(bi.name(), JSOP_DEFVAR))
1305 return false;
1306 }
1307 }
1308
1309 // As an optimization, if the eval does not have its own var
1310 // environment and is directly enclosed in a global scope, then all
1311 // free name lookups are global.
1312 if (scope(bce)->enclosing()->is<GlobalScope>())
1313 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1314 }
1315
1316 return true;
1317}
1318
1319bool
1320BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
1321{
1322 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1322); do { } while (false); do { *((volatile int*) __null)
= 1322; ::abort(); } while (false); } } while (false)
;
1323
1324 bce->setVarEmitterScope(this);
1325
1326 if (!ensureCache(bce))
1327 return false;
1328
1329 // Resolve body-level bindings, if there are any.
1330 TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
1331 Maybe<uint32_t> firstLexicalFrameSlot;
1332 if (ModuleScope::Data* bindings = modulesc->bindings) {
1333 BindingIter bi(*bindings);
1334 for (; bi; bi++) {
1335 if (!checkSlotLimits(bce, bi))
1336 return false;
1337
1338 NameLocation loc = NameLocation::fromBinding(bi.kind(), bi.location());
1339 if (!putNameInCache(bce, bi.name(), loc))
1340 return false;
1341
1342 if (BindingKindIsLexical(bi.kind())) {
1343 if (loc.kind() == NameLocation::Kind::FrameSlot && !firstLexicalFrameSlot)
1344 firstLexicalFrameSlot = Some(loc.frameSlot());
1345
1346 if (!tdzCache->noteTDZCheck(bce, bi.name(), CheckTDZ))
1347 return false;
1348 }
1349 }
1350
1351 updateFrameFixedSlots(bce, bi);
1352 } else {
1353 nextFrameSlot_ = 0;
1354 }
1355
1356 // Modules are toplevel, so any free names are global.
1357 fallbackFreeNameLocation_ = Some(NameLocation::Global(BindingKind::Var));
1358
1359 // Put lexical frame slots in TDZ. Environment slots are poisoned during
1360 // environment creation.
1361 if (firstLexicalFrameSlot) {
1362 if (!deadZoneFrameSlotRange(bce, *firstLexicalFrameSlot, frameSlotEnd()))
1363 return false;
1364 }
1365
1366 // Create and intern the VM scope.
1367 auto createScope = [modulesc](JSContext* cx, HandleScope enclosing) {
1368 return ModuleScope::create(cx, modulesc->bindings, modulesc->module(), enclosing);
1369 };
1370 if (!internBodyScope(bce, createScope))
1371 return false;
1372
1373 return checkEnvironmentChainLength(bce);
1374}
1375
1376bool
1377BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
1378{
1379 MOZ_ASSERT(this == bce->innermostEmitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this == bce->innermostEmitterScope)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1379); do { } while (false); do { *((volatile int*) __null)
= 1379; ::abort(); } while (false); } } while (false)
;
1380
1381 if (!ensureCache(bce))
1382 return false;
1383
1384 // 'with' make all accesses dynamic and unanalyzable.
1385 fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
1386
1387 auto createScope = [](JSContext* cx, HandleScope enclosing) {
1388 return WithScope::create(cx, enclosing);
1389 };
1390 if (!internScope(bce, createScope))
1391 return false;
1392
1393 if (!bce->emitInternedScopeOp(index(), JSOP_ENTERWITH))
1394 return false;
1395
1396 if (!appendScopeNote(bce))
1397 return false;
1398
1399 return checkEnvironmentChainLength(bce);
1400}
1401
1402bool
1403BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
1404{
1405 // If we aren't leaving the scope due to a non-local jump (e.g., break),
1406 // we must be the innermost scope.
1407 MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope)do { if (!nonLocal) { do { static_assert(mozilla::detail::AssertionConditionType
<decltype(this == bce->innermostEmitterScope)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(this == bce->innermostEmitterScope))), 0))) { MOZ_ReportAssertionFailure
("this == bce->innermostEmitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1407); do { } while (false); do { *((volatile int*) __null)
= 1407; ::abort(); } while (false); } } while (false); } } while
(false)
;
1408
1409 ScopeKind kind = scope(bce)->kind();
1410 switch (kind) {
1411 case ScopeKind::Lexical:
1412 case ScopeKind::SimpleCatch:
1413 case ScopeKind::Catch:
1414 if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV))
1415 return false;
1416 break;
1417
1418 case ScopeKind::With:
1419 if (!bce->emit1(JSOP_LEAVEWITH))
1420 return false;
1421 break;
1422
1423 case ScopeKind::ParameterExpressionVar:
1424 MOZ_ASSERT(hasEnvironment())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(hasEnvironment())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hasEnvironment()))), 0))) { MOZ_ReportAssertionFailure
("hasEnvironment()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1424); do { } while (false); do { *((volatile int*) __null)
= 1424; ::abort(); } while (false); } } while (false)
;
1425 if (!bce->emit1(JSOP_POPVARENV))
1426 return false;
1427 break;
1428
1429 case ScopeKind::Function:
1430 case ScopeKind::FunctionBodyVar:
1431 case ScopeKind::NamedLambda:
1432 case ScopeKind::StrictNamedLambda:
1433 case ScopeKind::Eval:
1434 case ScopeKind::StrictEval:
1435 case ScopeKind::Global:
1436 case ScopeKind::NonSyntactic:
1437 case ScopeKind::Module:
1438 break;
1439
1440 case ScopeKind::WasmInstance:
1441 case ScopeKind::WasmFunction:
1442 MOZ_CRASH("No wasm function scopes in JS")do { MOZ_ReportCrash("" "No wasm function scopes in JS", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1442); do { } while (false); do { *((volatile int*) __null)
= 1442; ::abort(); } while (false); } while (false)
;
1443 }
1444
1445 // Finish up the scope if we are leaving it in LIFO fashion.
1446 if (!nonLocal) {
1447 // Popping scopes due to non-local jumps generate additional scope
1448 // notes. See NonLocalExitControl::prepareForNonLocalJump.
1449 if (ScopeKindIsInBody(kind)) {
1450 // The extra function var scope is never popped once it's pushed,
1451 // so its scope note extends until the end of any possible code.
1452 uint32_t offset = kind == ScopeKind::FunctionBodyVar ? UINT32_MAX(4294967295U) : bce->offset();
1453 bce->scopeNoteList.recordEnd(noteIndex_, offset, bce->inPrologue());
1454 }
1455 }
1456
1457 return true;
1458}
1459
1460Maybe<MaybeCheckTDZ>
1461BytecodeEmitter::TDZCheckCache::needsTDZCheck(BytecodeEmitter* bce, JSAtom* name)
1462{
1463 if (!ensureCache(bce))
1464 return Nothing();
1465
1466 CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
1467 if (p)
1468 return Some(p->value().wrapped);
1469
1470 MaybeCheckTDZ rv = CheckTDZ;
1471 for (TDZCheckCache* it = enclosing(); it; it = it->enclosing()) {
1472 if (it->cache_) {
1473 if (CheckTDZMap::Ptr p2 = it->cache_->lookup(name)) {
1474 rv = p2->value();
1475 break;
1476 }
1477 }
1478 }
1479
1480 if (!cache_->add(p, name, rv)) {
1481 ReportOutOfMemory(bce->cx);
1482 return Nothing();
1483 }
1484
1485 return Some(rv);
1486}
1487
1488bool
1489BytecodeEmitter::TDZCheckCache::noteTDZCheck(BytecodeEmitter* bce, JSAtom* name,
1490 MaybeCheckTDZ check)
1491{
1492 if (!ensureCache(bce))
1493 return false;
1494
1495 CheckTDZMap::AddPtr p = cache_->lookupForAdd(name);
1496 if (p) {
1497 MOZ_ASSERT(!check, "TDZ only needs to be checked once per binding per basic block.")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!check)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!check))), 0))) { MOZ_ReportAssertionFailure
("!check" " (" "TDZ only needs to be checked once per binding per basic block."
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1497); do { } while (false); do { *((volatile int*) __null)
= 1497; ::abort(); } while (false); } } while (false)
;
1498 p->value() = check;
1499 } else {
1500 if (!cache_->add(p, name, check))
1501 return false;
1502 }
1503
1504 return true;
1505}
1506
1507class MOZ_STACK_CLASS TryEmitter
1508{
1509 public:
1510 enum Kind {
1511 TryCatch,
1512 TryCatchFinally,
1513 TryFinally
1514 };
1515 enum ShouldUseRetVal {
1516 UseRetVal,
1517 DontUseRetVal
1518 };
1519 enum ShouldUseControl {
1520 UseControl,
1521 DontUseControl,
1522 };
1523
1524 private:
1525 BytecodeEmitter* bce_;
1526 Kind kind_;
1527 ShouldUseRetVal retValKind_;
1528
1529 // Track jumps-over-catches and gosubs-to-finally for later fixup.
1530 //
1531 // When a finally block is active, non-local jumps (including
1532 // jumps-over-catches) result in a GOSUB being written into the bytecode
1533 // stream and fixed-up later.
1534 //
1535 // If ShouldUseControl is DontUseControl, all that handling is skipped.
1536 // DontUseControl is used by yield* and the internal try-catch around
1537 // IteratorClose. These internal uses must:
1538 // * have only one catch block
1539 // * have JSOP_GOTO at the end of catch-block
1540 // * have no non-local-jump
1541 // * don't use finally block for normal completion of try-block and
1542 // catch-block
1543 //
1544 // Additionally, a finally block may be emitted when ShouldUseControl is
1545 // DontUseControl, even if the kind is not TryCatchFinally or TryFinally,
1546 // because GOSUBs are not emitted. This internal use shares the
1547 // requirements as above.
1548 Maybe<TryFinallyControl> controlInfo_;
1549
1550 int depth_;
1551 unsigned noteIndex_;
1552 ptrdiff_t tryStart_;
1553 JumpList catchAndFinallyJump_;
1554 JumpTarget tryEnd_;
1555 JumpTarget finallyStart_;
1556
1557 enum State {
1558 Start,
1559 Try,
1560 TryEnd,
1561 Catch,
1562 CatchEnd,
1563 Finally,
1564 FinallyEnd,
1565 End
1566 };
1567 State state_;
1568
1569 bool hasCatch() const {
1570 return kind_ == TryCatch || kind_ == TryCatchFinally;
1571 }
1572 bool hasFinally() const {
1573 return kind_ == TryCatchFinally || kind_ == TryFinally;
1574 }
1575
1576 public:
1577 TryEmitter(BytecodeEmitter* bce, Kind kind, ShouldUseRetVal retValKind = UseRetVal,
1578 ShouldUseControl controlKind = UseControl)
1579 : bce_(bce),
1580 kind_(kind),
1581 retValKind_(retValKind),
1582 depth_(0),
1583 noteIndex_(0),
1584 tryStart_(0),
1585 state_(Start)
1586 {
1587 if (controlKind == UseControl)
1588 controlInfo_.emplace(bce_, hasFinally() ? StatementKind::Finally : StatementKind::Try);
1589 finallyStart_.offset = 0;
1590 }
1591
1592 bool emitJumpOverCatchAndFinally() {
1593 if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1594 return false;
1595 return true;
1596 }
1597
1598 bool emitTry() {
1599 MOZ_ASSERT(state_ == Start)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == Start)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == Start))), 0))) { MOZ_ReportAssertionFailure
("state_ == Start", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1599); do { } while (false); do { *((volatile int*) __null)
= 1599; ::abort(); } while (false); } } while (false)
;
1600
1601 // Since an exception can be thrown at any place inside the try block,
1602 // we need to restore the stack and the scope chain before we transfer
1603 // the control to the exception handler.
1604 //
1605 // For that we store in a try note associated with the catch or
1606 // finally block the stack depth upon the try entry. The interpreter
1607 // uses this depth to properly unwind the stack and the scope chain.
1608 depth_ = bce_->stackDepth;
1609
1610 // Record the try location, then emit the try block.
1611 if (!bce_->newSrcNote(SRC_TRY, &noteIndex_))
1612 return false;
1613 if (!bce_->emit1(JSOP_TRY))
1614 return false;
1615 tryStart_ = bce_->offset();
1616
1617 state_ = Try;
1618 return true;
1619 }
1620
1621 private:
1622 bool emitTryEnd() {
1623 MOZ_ASSERT(state_ == Try)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == Try)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == Try))), 0))) { MOZ_ReportAssertionFailure
("state_ == Try", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1623); do { } while (false); do { *((volatile int*) __null)
= 1623; ::abort(); } while (false); } } while (false)
;
1624 MOZ_ASSERT(depth_ == bce_->stackDepth)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(depth_ == bce_->stackDepth)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(depth_ == bce_->stackDepth
))), 0))) { MOZ_ReportAssertionFailure("depth_ == bce_->stackDepth"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1624); do { } while (false); do { *((volatile int*) __null)
= 1624; ::abort(); } while (false); } } while (false)
;
1625
1626 // GOSUB to finally, if present.
1627 if (hasFinally() && controlInfo_) {
1628 if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
1629 return false;
1630 }
1631
1632 // Source note points to the jump at the end of the try block.
1633 if (!bce_->setSrcNoteOffset(noteIndex_, 0, bce_->offset() - tryStart_ + JSOP_TRY_LENGTH))
1634 return false;
1635
1636 // Emit jump over catch and/or finally.
1637 if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1638 return false;
1639
1640 if (!bce_->emitJumpTarget(&tryEnd_))
1641 return false;
1642
1643 return true;
1644 }
1645
1646 public:
1647 bool emitCatch() {
1648 MOZ_ASSERT(state_ == Try)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == Try)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == Try))), 0))) { MOZ_ReportAssertionFailure
("state_ == Try", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1648); do { } while (false); do { *((volatile int*) __null)
= 1648; ::abort(); } while (false); } } while (false)
;
1649 if (!emitTryEnd())
1650 return false;
1651
1652 MOZ_ASSERT(bce_->stackDepth == depth_)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bce_->stackDepth == depth_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce_->stackDepth == depth_
))), 0))) { MOZ_ReportAssertionFailure("bce_->stackDepth == depth_"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1652); do { } while (false); do { *((volatile int*) __null)
= 1652; ::abort(); } while (false); } } while (false)
;
1653
1654 if (retValKind_ == UseRetVal) {
1655 // Clear the frame's return value that might have been set by the
1656 // try block:
1657 //
1658 // eval("try { 1; throw 2 } catch(e) {}"); // undefined, not 1
1659 if (!bce_->emit1(JSOP_UNDEFINED))
1660 return false;
1661 if (!bce_->emit1(JSOP_SETRVAL))
1662 return false;
1663 }
1664
1665 state_ = Catch;
1666 return true;
1667 }
1668
1669 private:
1670 bool emitCatchEnd() {
1671 MOZ_ASSERT(state_ == Catch)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == Catch)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == Catch))), 0))) { MOZ_ReportAssertionFailure
("state_ == Catch", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1671); do { } while (false); do { *((volatile int*) __null)
= 1671; ::abort(); } while (false); } } while (false)
;
1672
1673 if (!controlInfo_)
1674 return true;
1675
1676 // gosub <finally>, if required.
1677 if (hasFinally()) {
1678 if (!bce_->emitJump(JSOP_GOSUB, &controlInfo_->gosubs))
1679 return false;
1680 MOZ_ASSERT(bce_->stackDepth == depth_)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bce_->stackDepth == depth_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce_->stackDepth == depth_
))), 0))) { MOZ_ReportAssertionFailure("bce_->stackDepth == depth_"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1680); do { } while (false); do { *((volatile int*) __null)
= 1680; ::abort(); } while (false); } } while (false)
;
1681
1682 // Jump over the finally block.
1683 if (!bce_->emitJump(JSOP_GOTO, &catchAndFinallyJump_))
1684 return false;
1685 }
1686
1687 return true;
1688 }
1689
1690 public:
1691 bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
1692 // If we are using controlInfo_ (i.e., emitting a syntactic try
1693 // blocks), we must have specified up front if there will be a finally
1694 // close. For internal try blocks, like those emitted for yield* and
1695 // IteratorClose inside for-of loops, we can emitFinally even without
1696 // specifying up front, since the internal try blocks emit no GOSUBs.
1697 if (!controlInfo_) {
1698 if (kind_ == TryCatch)
1699 kind_ = TryCatchFinally;
1700 } else {
1701 MOZ_ASSERT(hasFinally())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(hasFinally())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hasFinally()))), 0))) { MOZ_ReportAssertionFailure
("hasFinally()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1701); do { } while (false); do { *((volatile int*) __null)
= 1701; ::abort(); } while (false); } } while (false)
;
1702 }
1703
1704 if (state_ == Try) {
1705 if (!emitTryEnd())
1706 return false;
1707 } else {
1708 MOZ_ASSERT(state_ == Catch)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == Catch)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == Catch))), 0))) { MOZ_ReportAssertionFailure
("state_ == Catch", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1708); do { } while (false); do { *((volatile int*) __null)
= 1708; ::abort(); } while (false); } } while (false)
;
1709 if (!emitCatchEnd())
1710 return false;
1711 }
1712
1713 MOZ_ASSERT(bce_->stackDepth == depth_)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bce_->stackDepth == depth_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce_->stackDepth == depth_
))), 0))) { MOZ_ReportAssertionFailure("bce_->stackDepth == depth_"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1713); do { } while (false); do { *((volatile int*) __null)
= 1713; ::abort(); } while (false); } } while (false)
;
1714
1715 if (!bce_->emitJumpTarget(&finallyStart_))
1716 return false;
1717
1718 if (controlInfo_) {
1719 // Fix up the gosubs that might have been emitted before non-local
1720 // jumps to the finally code.
1721 bce_->patchJumpsToTarget(controlInfo_->gosubs, finallyStart_);
1722
1723 // Indicate that we're emitting a subroutine body.
1724 controlInfo_->setEmittingSubroutine();
1725 }
1726 if (finallyPos) {
1727 if (!bce_->updateSourceCoordNotes(finallyPos.value()))
1728 return false;
1729 }
1730 if (!bce_->emit1(JSOP_FINALLY))
1731 return false;
1732
1733 if (retValKind_ == UseRetVal) {
1734 if (!bce_->emit1(JSOP_GETRVAL))
1735 return false;
1736
1737 // Clear the frame's return value to make break/continue return
1738 // correct value even if there's no other statement before them:
1739 //
1740 // eval("x: try { 1 } finally { break x; }"); // undefined, not 1
1741 if (!bce_->emit1(JSOP_UNDEFINED))
1742 return false;
1743 if (!bce_->emit1(JSOP_SETRVAL))
1744 return false;
1745 }
1746
1747 state_ = Finally;
1748 return true;
1749 }
1750
1751 private:
1752 bool emitFinallyEnd() {
1753 MOZ_ASSERT(state_ == Finally)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == Finally)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == Finally))), 0))) {
MOZ_ReportAssertionFailure("state_ == Finally", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1753); do { } while (false); do { *((volatile int*) __null)
= 1753; ::abort(); } while (false); } } while (false)
;
1754
1755 if (retValKind_ == UseRetVal) {
1756 if (!bce_->emit1(JSOP_SETRVAL))
1757 return false;
1758 }
1759
1760 if (!bce_->emit1(JSOP_RETSUB))
1761 return false;
1762
1763 bce_->hasTryFinally = true;
1764 return true;
1765 }
1766
1767 public:
1768 bool emitEnd() {
1769 if (state_ == Catch) {
1770 MOZ_ASSERT(!hasFinally())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!hasFinally())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!hasFinally()))), 0))) { MOZ_ReportAssertionFailure
("!hasFinally()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1770); do { } while (false); do { *((volatile int*) __null)
= 1770; ::abort(); } while (false); } } while (false)
;
1771 if (!emitCatchEnd())
1772 return false;
1773 } else {
1774 MOZ_ASSERT(state_ == Finally)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == Finally)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == Finally))), 0))) {
MOZ_ReportAssertionFailure("state_ == Finally", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1774); do { } while (false); do { *((volatile int*) __null)
= 1774; ::abort(); } while (false); } } while (false)
;
1775 MOZ_ASSERT(hasFinally())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(hasFinally())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hasFinally()))), 0))) { MOZ_ReportAssertionFailure
("hasFinally()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1775); do { } while (false); do { *((volatile int*) __null)
= 1775; ::abort(); } while (false); } } while (false)
;
1776 if (!emitFinallyEnd())
1777 return false;
1778 }
1779
1780 MOZ_ASSERT(bce_->stackDepth == depth_)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(bce_->stackDepth == depth_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bce_->stackDepth == depth_
))), 0))) { MOZ_ReportAssertionFailure("bce_->stackDepth == depth_"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1780); do { } while (false); do { *((volatile int*) __null)
= 1780; ::abort(); } while (false); } } while (false)
;
1781
1782 // ReconstructPCStack needs a NOP here to mark the end of the last
1783 // catch block.
1784 if (!bce_->emit1(JSOP_NOP))
1785 return false;
1786
1787 // Fix up the end-of-try/catch jumps to come here.
1788 if (!bce_->emitJumpTargetAndPatch(catchAndFinallyJump_))
1789 return false;
1790
1791 // Add the try note last, to let post-order give us the right ordering
1792 // (first to last for a given nesting level, inner to outer by level).
1793 if (hasCatch()) {
1794 if (!bce_->tryNoteList.append(JSTRY_CATCH, depth_, tryStart_, tryEnd_.offset))
1795 return false;
1796 }
1797
1798 // If we've got a finally, mark try+catch region with additional
1799 // trynote to catch exceptions (re)thrown from a catch block or
1800 // for the try{}finally{} case.
1801 if (hasFinally()) {
1802 if (!bce_->tryNoteList.append(JSTRY_FINALLY, depth_, tryStart_, finallyStart_.offset))
1803 return false;
1804 }
1805
1806 state_ = End;
1807 return true;
1808 }
1809};
1810
1811class MOZ_STACK_CLASS IfThenElseEmitter
1812{
1813 BytecodeEmitter* bce_;
1814 JumpList jumpAroundThen_;
1815 JumpList jumpsAroundElse_;
1816 unsigned noteIndex_;
1817 int32_t thenDepth_;
1818#ifdef DEBUG1
1819 int32_t pushed_;
1820 bool calculatedPushed_;
1821#endif
1822 enum State {
1823 Start,
1824 If,
1825 Cond,
1826 IfElse,
1827 Else,
1828 End
1829 };
1830 State state_;
1831
1832 public:
1833 explicit IfThenElseEmitter(BytecodeEmitter* bce)
1834 : bce_(bce),
1835 noteIndex_(-1),
1836 thenDepth_(0),
1837#ifdef DEBUG1
1838 pushed_(0),
1839 calculatedPushed_(false),
1840#endif
1841 state_(Start)
1842 {}
1843
1844 ~IfThenElseEmitter()
1845 {}
1846
1847 private:
1848 bool emitIf(State nextState) {
1849 MOZ_ASSERT(state_ == Start || state_ == Else)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == Start || state_ == Else)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == Start || state_ ==
Else))), 0))) { MOZ_ReportAssertionFailure("state_ == Start || state_ == Else"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1849); do { } while (false); do { *((volatile int*) __null)
= 1849; ::abort(); } while (false); } } while (false)
;
1850 MOZ_ASSERT(nextState == If || nextState == IfElse || nextState == Cond)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(nextState == If || nextState == IfElse || nextState ==
Cond)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nextState == If || nextState == IfElse || nextState ==
Cond))), 0))) { MOZ_ReportAssertionFailure("nextState == If || nextState == IfElse || nextState == Cond"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1850); do { } while (false); do { *((volatile int*) __null)
= 1850; ::abort(); } while (false); } } while (false)
;
1851
1852 // Clear jumpAroundThen_ offset that points previous JSOP_IFEQ.
1853 if (state_ == Else)
1854 jumpAroundThen_ = JumpList();
1855
1856 // Emit an annotated branch-if-false around the then part.
1857 SrcNoteType type = nextState == If ? SRC_IF : nextState == IfElse ? SRC_IF_ELSE : SRC_COND;
1858 if (!bce_->newSrcNote(type, &noteIndex_))
1859 return false;
1860 if (!bce_->emitJump(JSOP_IFEQ, &jumpAroundThen_))
1861 return false;
1862
1863 // To restore stack depth in else part, save depth of the then part.
1864#ifdef DEBUG1
1865 // If DEBUG, this is also necessary to calculate |pushed_|.
1866 thenDepth_ = bce_->stackDepth;
1867#else
1868 if (nextState == IfElse || nextState == Cond)
1869 thenDepth_ = bce_->stackDepth;
1870#endif
1871 state_ = nextState;
1872 return true;
1873 }
1874
1875 public:
1876 bool emitIf() {
1877 return emitIf(If);
1878 }
1879
1880 bool emitCond() {
1881 return emitIf(Cond);
1882 }
1883
1884 bool emitIfElse() {
1885 return emitIf(IfElse);
1886 }
1887
1888 bool emitElse() {
1889 MOZ_ASSERT(state_ == IfElse || state_ == Cond)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == IfElse || state_ == Cond)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == IfElse || state_ ==
Cond))), 0))) { MOZ_ReportAssertionFailure("state_ == IfElse || state_ == Cond"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1889); do { } while (false); do { *((volatile int*) __null)
= 1889; ::abort(); } while (false); } } while (false)
;
1890
1891 calculateOrCheckPushed();
1892
1893 // Emit a jump from the end of our then part around the else part. The
1894 // patchJumpsToTarget call at the bottom of this function will fix up
1895 // the offset with jumpsAroundElse value.
1896 if (!bce_->emitJump(JSOP_GOTO, &jumpsAroundElse_))
1897 return false;
1898
1899 // Ensure the branch-if-false comes here, then emit the else.
1900 if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
1901 return false;
1902
1903 // Annotate SRC_IF_ELSE or SRC_COND with the offset from branch to
1904 // jump, for IonMonkey's benefit. We can't just "back up" from the pc
1905 // of the else clause, because we don't know whether an extended
1906 // jump was required to leap from the end of the then clause over
1907 // the else clause.
1908 if (!bce_->setSrcNoteOffset(noteIndex_, 0,
1909 jumpsAroundElse_.offset - jumpAroundThen_.offset))
1910 {
1911 return false;
1912 }
1913
1914 // Restore stack depth of the then part.
1915 bce_->stackDepth = thenDepth_;
1916 state_ = Else;
1917 return true;
1918 }
1919
1920 bool emitEnd() {
1921 MOZ_ASSERT(state_ == If || state_ == Else)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(state_ == If || state_ == Else)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(state_ == If || state_ == Else
))), 0))) { MOZ_ReportAssertionFailure("state_ == If || state_ == Else"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1921); do { } while (false); do { *((volatile int*) __null)
= 1921; ::abort(); } while (false); } } while (false)
;
1922
1923 calculateOrCheckPushed();
1924
1925 if (state_ == If) {
1926 // No else part, fixup the branch-if-false to come here.
1927 if (!bce_->emitJumpTargetAndPatch(jumpAroundThen_))
1928 return false;
1929 }
1930
1931 // Patch all the jumps around else parts.
1932 if (!bce_->emitJumpTargetAndPatch(jumpsAroundElse_))
1933 return false;
1934
1935 state_ = End;
1936 return true;
1937 }
1938
1939 void calculateOrCheckPushed() {
1940#ifdef DEBUG1
1941 if (!calculatedPushed_) {
1942 pushed_ = bce_->stackDepth - thenDepth_;
1943 calculatedPushed_ = true;
1944 } else {
1945 MOZ_ASSERT(pushed_ == bce_->stackDepth - thenDepth_)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pushed_ == bce_->stackDepth - thenDepth_)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(pushed_ == bce_->stackDepth - thenDepth_))), 0))) { MOZ_ReportAssertionFailure
("pushed_ == bce_->stackDepth - thenDepth_", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 1945); do { } while (false); do { *((volatile int*) __null)
= 1945; ::abort(); } while (false); } } while (false)
;
1946 }
1947#endif
1948 }
1949
1950#ifdef DEBUG1
1951 int32_t pushed() const {
1952 return pushed_;
1953 }
1954
1955 int32_t popped() const {
1956 return -pushed_;
1957 }
1958#endif
1959};
1960
1961class ForOfLoopControl : public LoopControl
1962{
1963 // The stack depth of the iterator.
1964 int32_t iterDepth_;
1965
1966 // for-of loops, when throwing from non-iterator code (i.e. from the body
1967 // or from evaluating the LHS of the loop condition), need to call
1968 // IteratorClose. This is done by enclosing non-iterator code with
1969 // try-catch and call IteratorClose in `catch` block.
1970 // If IteratorClose itself throws, we must not re-call IteratorClose. Since
1971 // non-local jumps like break and return call IteratorClose, whenever a
1972 // non-local jump is emitted, we must tell catch block not to perform
1973 // IteratorClose.
1974 //
1975 // for (x of y) {
1976 // // Operations for iterator (IteratorNext etc) are outside of
1977 // // try-block.
1978 // try {
1979 // ...
1980 // if (...) {
1981 // // Before non-local jump, clear iterator on the stack to tell
1982 // // catch block not to perform IteratorClose.
1983 // tmpIterator = iterator;
1984 // iterator = undefined;
1985 // IteratorClose(tmpIterator, { break });
1986 // break;
1987 // }
1988 // ...
1989 // } catch (e) {
1990 // // Just throw again when iterator is cleared by non-local jump.
1991 // if (iterator === undefined)
1992 // throw e;
1993 // IteratorClose(iterator, { throw, e });
1994 // }
1995 // }
1996 Maybe<TryEmitter> tryCatch_;
1997
1998 // Used to track if any yields were emitted between calls to to
1999 // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
2000 uint32_t numYieldsAtBeginCodeNeedingIterClose_;
2001
2002 bool allowSelfHosted_;
2003
2004 IteratorKind iterKind_;
2005
2006 public:
2007 ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
2008 IteratorKind iterKind)
2009 : LoopControl(bce, StatementKind::ForOfLoop),
2010 iterDepth_(iterDepth),
2011 numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX(4294967295U)),
2012 allowSelfHosted_(allowSelfHosted),
2013 iterKind_(iterKind)
2014 {
2015 }
2016
2017 bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
2018 tryCatch_.emplace(bce, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
2019 TryEmitter::DontUseControl);
2020
2021 if (!tryCatch_->emitTry())
2022 return false;
2023
2024 MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(numYieldsAtBeginCodeNeedingIterClose_ == (4294967295U
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(numYieldsAtBeginCodeNeedingIterClose_ == (4294967295U
)))), 0))) { MOZ_ReportAssertionFailure("numYieldsAtBeginCodeNeedingIterClose_ == (4294967295U)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2024); do { } while (false); do { *((volatile int*) __null)
= 2024; ::abort(); } while (false); } } while (false)
;
2025 numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
2026
2027 return true;
2028 }
2029
2030 bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
2031 if (!tryCatch_->emitCatch()) // ITER ...
2032 return false;
2033
2034 if (!bce->emit1(JSOP_EXCEPTION)) // ITER ... EXCEPTION
2035 return false;
2036 unsigned slotFromTop = bce->stackDepth - iterDepth_;
2037 if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
2038 return false;
2039
2040 // If ITER is undefined, it means the exception is thrown by
2041 // IteratorClose for non-local jump, and we should't perform
2042 // IteratorClose again here.
2043 if (!bce->emit1(JSOP_UNDEFINED)) // ITER ... EXCEPTION ITER UNDEF
2044 return false;
2045 if (!bce->emit1(JSOP_STRICTNE)) // ITER ... EXCEPTION NE
2046 return false;
2047
2048 IfThenElseEmitter ifIteratorIsNotClosed(bce);
2049 if (!ifIteratorIsNotClosed.emitIf()) // ITER ... EXCEPTION
2050 return false;
2051
2052 MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(slotFromTop == unsigned(bce->stackDepth - iterDepth_
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(slotFromTop == unsigned(bce->stackDepth - iterDepth_
)))), 0))) { MOZ_ReportAssertionFailure("slotFromTop == unsigned(bce->stackDepth - iterDepth_)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2052); do { } while (false); do { *((volatile int*) __null)
= 2052; ::abort(); } while (false); } } while (false)
;
2053 if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
2054 return false;
2055 if (!emitIteratorClose(bce, CompletionKind::Throw)) // ITER ... EXCEPTION
2056 return false;
2057
2058 if (!ifIteratorIsNotClosed.emitEnd()) // ITER ... EXCEPTION
2059 return false;
2060
2061 if (!bce->emit1(JSOP_THROW)) // ITER ...
2062 return false;
2063
2064 // If any yields were emitted, then this for-of loop is inside a star
2065 // generator and must handle the case of Generator.return. Like in
2066 // yield*, it is handled with a finally block.
2067 uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
2068 if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
2069 if (!tryCatch_->emitFinally())
2070 return false;
2071
2072 IfThenElseEmitter ifGeneratorClosing(bce);
2073 if (!bce->emit1(JSOP_ISGENCLOSING)) // ITER ... FTYPE FVALUE CLOSING
2074 return false;
2075 if (!ifGeneratorClosing.emitIf()) // ITER ... FTYPE FVALUE
2076 return false;
2077 if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
2078 return false;
2079 if (!emitIteratorClose(bce, CompletionKind::Normal)) // ITER ... FTYPE FVALUE
2080 return false;
2081 if (!ifGeneratorClosing.emitEnd()) // ITER ... FTYPE FVALUE
2082 return false;
2083 }
2084
2085 if (!tryCatch_->emitEnd())
2086 return false;
2087
2088 tryCatch_.reset();
2089 numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX(4294967295U);
2090
2091 return true;
2092 }
2093
2094 bool emitIteratorClose(BytecodeEmitter* bce,
2095 CompletionKind completionKind = CompletionKind::Normal) {
2096 ptrdiff_t start = bce->offset();
2097 if (!bce->emitIteratorClose(iterKind_, completionKind, allowSelfHosted_))
2098 return false;
2099 ptrdiff_t end = bce->offset();
2100 return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
2101 }
2102
2103 bool emitPrepareForNonLocalJump(BytecodeEmitter* bce, bool isTarget) {
2104 // Pop unnecessary value from the stack. Effectively this means
2105 // leaving try-catch block. However, the performing IteratorClose can
2106 // reach the depth for try-catch, and effectively re-enter the
2107 // try-catch block.
2108 if (!bce->emit1(JSOP_POP)) // NEXT ITER
2109 return false;
2110
2111 // Pop the iterator's next method.
2112 if (!bce->emit1(JSOP_SWAP)) // ITER NEXT
2113 return false;
2114 if (!bce->emit1(JSOP_POP)) // ITER
2115 return false;
2116
2117 // Clear ITER slot on the stack to tell catch block to avoid performing
2118 // IteratorClose again.
2119 if (!bce->emit1(JSOP_UNDEFINED)) // ITER UNDEF
2120 return false;
2121 if (!bce->emit1(JSOP_SWAP)) // UNDEF ITER
2122 return false;
2123
2124 if (!emitIteratorClose(bce)) // UNDEF
2125 return false;
2126
2127 if (isTarget) {
2128 // At the level of the target block, there's bytecode after the
2129 // loop that will pop the next method, the iterator, and the
2130 // value, so push two undefineds to balance the stack.
2131 if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF
2132 return false;
2133 if (!bce->emit1(JSOP_UNDEFINED)) // UNDEF UNDEF UNDEF
2134 return false;
2135 } else {
2136 if (!bce->emit1(JSOP_POP)) //
2137 return false;
2138 }
2139
2140 return true;
2141 }
2142};
2143
2144BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
2145 const EitherParser<FullParseHandler>& parser, SharedContext* sc,
2146 HandleScript script, Handle<LazyScript*> lazyScript,
2147 uint32_t lineNum, EmitterMode emitterMode)
2148 : sc(sc),
2149 cx(sc->context),
2150 parent(parent),
2151 script(cx, script),
2152 lazyScript(cx, lazyScript),
2153 prologue(cx, lineNum),
2154 main(cx, lineNum),
2155 current(&main),
2156 parser(parser),
2157 atomIndices(cx->frontendCollectionPool()),
2158 firstLine(lineNum),
2159 maxFixedSlots(0),
2160 maxStackDepth(0),
2161 stackDepth(0),
2162 emitLevel(0),
2163 bodyScopeIndex(UINT32_MAX(4294967295U)),
2164 varEmitterScope(nullptr),
2165 innermostNestableControl(nullptr),
2166 innermostEmitterScope(nullptr),
2167 innermostTDZCheckCache(nullptr),
2168 constList(cx),
2169 scopeList(cx),
2170 tryNoteList(cx),
2171 scopeNoteList(cx),
2172 yieldAndAwaitOffsetList(cx),
2173 typesetCount(0),
2174 hasSingletons(false),
2175 hasTryFinally(false),
2176 emittingRunOnceLambda(false),
2177 emitterMode(emitterMode),
2178 functionBodyEndPosSet(false)
2179{
2180 MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript)do { if (emitterMode == LazyFunction) { do { static_assert(mozilla
::detail::AssertionConditionType<decltype(lazyScript)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(lazyScript))), 0))) { MOZ_ReportAssertionFailure("lazyScript"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2180); do { } while (false); do { *((volatile int*) __null)
= 2180; ::abort(); } while (false); } } while (false); } } while
(false)
;
2181}
2182
2183BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
2184 const EitherParser<FullParseHandler>& parser, SharedContext* sc,
2185 HandleScript script, Handle<LazyScript*> lazyScript,
2186 TokenPos bodyPosition, EmitterMode emitterMode)
2187 : BytecodeEmitter(parent, parser, sc, script, lazyScript,
2188 parser.tokenStream().srcCoords.lineNum(bodyPosition.begin),
2189 emitterMode)
2190{
2191 setFunctionBodyEndPos(bodyPosition);
2192}
2193
2194bool
2195BytecodeEmitter::init()
2196{
2197 return atomIndices.acquire(cx);
2198}
2199
2200template <typename Predicate /* (NestableControl*) -> bool */>
2201BytecodeEmitter::NestableControl*
2202BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
2203{
2204 return NestableControl::findNearest(innermostNestableControl, predicate);
2205}
2206
2207template <typename T>
2208T*
2209BytecodeEmitter::findInnermostNestableControl() const
2210{
2211 return NestableControl::findNearest<T>(innermostNestableControl);
2212}
2213
2214template <typename T, typename Predicate /* (T*) -> bool */>
2215T*
2216BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
2217{
2218 return NestableControl::findNearest<T>(innermostNestableControl, predicate);
2219}
2220
2221NameLocation
2222BytecodeEmitter::lookupName(JSAtom* name)
2223{
2224 return innermostEmitterScope->lookup(this, name);
2225}
2226
2227Maybe<NameLocation>
2228BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
2229{
2230 return innermostEmitterScope->locationBoundInScope(name, target);
2231}
2232
2233Maybe<NameLocation>
2234BytecodeEmitter::locationOfNameBoundInFunctionScope(JSAtom* name, EmitterScope* source)
2235{
2236 EmitterScope* funScope = source;
2237 while (!funScope->scope(this)->is<FunctionScope>())
2238 funScope = funScope->enclosingInFrame();
2239 return source->locationBoundInScope(name, funScope);
2240}
2241
2242bool
2243BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset)
2244{
2245 *offset = code().length();
2246
2247 if (!code().growBy(delta)) {
2248 ReportOutOfMemory(cx);
2249 return false;
2250 }
2251 return true;
2252}
2253
2254void
2255BytecodeEmitter::updateDepth(ptrdiff_t target)
2256{
2257 jsbytecode* pc = code(target);
2258
2259 int nuses = StackUses(pc);
2260 int ndefs = StackDefs(pc);
2261
2262 stackDepth -= nuses;
2263 MOZ_ASSERT(stackDepth >= 0)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(stackDepth >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(stackDepth >= 0))), 0))) {
MOZ_ReportAssertionFailure("stackDepth >= 0", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2263); do { } while (false); do { *((volatile int*) __null)
= 2263; ::abort(); } while (false); } } while (false)
;
2264 stackDepth += ndefs;
2265
2266 if ((uint32_t)stackDepth > maxStackDepth)
2267 maxStackDepth = stackDepth;
2268}
2269
2270#ifdef DEBUG1
2271bool
2272BytecodeEmitter::checkStrictOrSloppy(JSOp op)
2273{
2274 if (IsCheckStrictOp(op) && !sc->strict())
2275 return false;
2276 if (IsCheckSloppyOp(op) && sc->strict())
2277 return false;
2278 return true;
2279}
2280#endif
2281
2282bool
2283BytecodeEmitter::emit1(JSOp op)
2284{
2285 MOZ_ASSERT(checkStrictOrSloppy(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(checkStrictOrSloppy(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(checkStrictOrSloppy(op)))), 0
))) { MOZ_ReportAssertionFailure("checkStrictOrSloppy(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2285); do { } while (false); do { *((volatile int*) __null)
= 2285; ::abort(); } while (false); } } while (false)
;
2286
2287 ptrdiff_t offset;
2288 if (!emitCheck(1, &offset))
2289 return false;
2290
2291 jsbytecode* code = this->code(offset);
2292 code[0] = jsbytecode(op);
2293 updateDepth(offset);
2294 return true;
2295}
2296
2297bool
2298BytecodeEmitter::emit2(JSOp op, uint8_t op1)
2299{
2300 MOZ_ASSERT(checkStrictOrSloppy(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(checkStrictOrSloppy(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(checkStrictOrSloppy(op)))), 0
))) { MOZ_ReportAssertionFailure("checkStrictOrSloppy(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2300); do { } while (false); do { *((volatile int*) __null)
= 2300; ::abort(); } while (false); } } while (false)
;
2301
2302 ptrdiff_t offset;
2303 if (!emitCheck(2, &offset))
2304 return false;
2305
2306 jsbytecode* code = this->code(offset);
2307 code[0] = jsbytecode(op);
2308 code[1] = jsbytecode(op1);
2309 updateDepth(offset);
2310 return true;
2311}
2312
2313bool
2314BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2)
2315{
2316 MOZ_ASSERT(checkStrictOrSloppy(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(checkStrictOrSloppy(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(checkStrictOrSloppy(op)))), 0
))) { MOZ_ReportAssertionFailure("checkStrictOrSloppy(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2316); do { } while (false); do { *((volatile int*) __null)
= 2316; ::abort(); } while (false); } } while (false)
;
2317
2318 /* These should filter through emitVarOp. */
2319 MOZ_ASSERT(!IsArgOp(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!IsArgOp(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsArgOp(op)))), 0))) { MOZ_ReportAssertionFailure
("!IsArgOp(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2319); do { } while (false); do { *((volatile int*) __null)
= 2319; ::abort(); } while (false); } } while (false)
;
2320 MOZ_ASSERT(!IsLocalOp(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!IsLocalOp(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsLocalOp(op)))), 0))) { MOZ_ReportAssertionFailure
("!IsLocalOp(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2320); do { } while (false); do { *((volatile int*) __null)
= 2320; ::abort(); } while (false); } } while (false)
;
2321
2322 ptrdiff_t offset;
2323 if (!emitCheck(3, &offset))
2324 return false;
2325
2326 jsbytecode* code = this->code(offset);
2327 code[0] = jsbytecode(op);
2328 code[1] = op1;
2329 code[2] = op2;
2330 updateDepth(offset);
2331 return true;
2332}
2333
2334bool
2335BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t* offset)
2336{
2337 MOZ_ASSERT(checkStrictOrSloppy(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(checkStrictOrSloppy(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(checkStrictOrSloppy(op)))), 0
))) { MOZ_ReportAssertionFailure("checkStrictOrSloppy(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2337); do { } while (false); do { *((volatile int*) __null)
= 2337; ::abort(); } while (false); } } while (false)
;
2338 ptrdiff_t length = 1 + ptrdiff_t(extra);
2339
2340 ptrdiff_t off;
2341 if (!emitCheck(length, &off))
2342 return false;
2343
2344 jsbytecode* code = this->code(off);
2345 code[0] = jsbytecode(op);
2346 /* The remaining |extra| bytes are set by the caller */
2347
2348 /*
2349 * Don't updateDepth if op's use-count comes from the immediate
2350 * operand yet to be stored in the extra bytes after op.
2351 */
2352 if (CodeSpec[op].nuses >= 0)
2353 updateDepth(off);
2354
2355 if (offset)
2356 *offset = off;
2357 return true;
2358}
2359
2360bool
2361BytecodeEmitter::emitJumpTarget(JumpTarget* target)
2362{
2363 ptrdiff_t off = offset();
2364
2365 // Alias consecutive jump targets.
2366 if (off == current->lastTarget.offset + ptrdiff_t(JSOP_JUMPTARGET_LENGTH)) {
2367 target->offset = current->lastTarget.offset;
2368 return true;
2369 }
2370
2371 target->offset = off;
2372 current->lastTarget.offset = off;
2373 if (!emit1(JSOP_JUMPTARGET))
2374 return false;
2375 return true;
2376}
2377
2378void
2379JumpList::push(jsbytecode* code, ptrdiff_t jumpOffset)
2380{
2381 SET_JUMP_OFFSET(&code[jumpOffset], offset - jumpOffset);
2382 offset = jumpOffset;
2383}
2384
2385void
2386JumpList::patchAll(jsbytecode* code, JumpTarget target)
2387{
2388 ptrdiff_t delta;
2389 for (ptrdiff_t jumpOffset = offset; jumpOffset != -1; jumpOffset += delta) {
2390 jsbytecode* pc = &code[jumpOffset];
2391 MOZ_ASSERT(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL))
), 0))) { MOZ_ReportAssertionFailure("IsJumpOpcode(JSOp(*pc)) || JSOp(*pc) == JSOP_LABEL"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2391); do { } while (false); do { *((volatile int*) __null)
= 2391; ::abort(); } while (false); } } while (false)
;
2392 delta = GET_JUMP_OFFSET(pc);
2393 MOZ_ASSERT(delta < 0)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(delta < 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(delta < 0))), 0))) { MOZ_ReportAssertionFailure
("delta < 0", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2393); do { } while (false); do { *((volatile int*) __null)
= 2393; ::abort(); } while (false); } } while (false)
;
2394 ptrdiff_t span = target.offset - jumpOffset;
2395 SET_JUMP_OFFSET(pc, span);
2396 }
2397}
2398
2399bool
2400BytecodeEmitter::emitJumpNoFallthrough(JSOp op, JumpList* jump)
2401{
2402 ptrdiff_t offset;
2403 if (!emitCheck(5, &offset))
2404 return false;
2405
2406 jsbytecode* code = this->code(offset);
2407 code[0] = jsbytecode(op);
2408 MOZ_ASSERT(-1 <= jump->offset && jump->offset < offset)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(-1 <= jump->offset && jump->offset <
offset)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(-1 <= jump->offset && jump->offset <
offset))), 0))) { MOZ_ReportAssertionFailure("-1 <= jump->offset && jump->offset < offset"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2408); do { } while (false); do { *((volatile int*) __null)
= 2408; ::abort(); } while (false); } } while (false)
;
2409 jump->push(this->code(0), offset);
2410 updateDepth(offset);
2411 return true;
2412}
2413
2414bool
2415BytecodeEmitter::emitJump(JSOp op, JumpList* jump)
2416{
2417 if (!emitJumpNoFallthrough(op, jump))
2418 return false;
2419 if (BytecodeFallsThrough(op)) {
2420 JumpTarget fallthrough;
2421 if (!emitJumpTarget(&fallthrough))
2422 return false;
2423 }
2424 return true;
2425}
2426
2427bool
2428BytecodeEmitter::emitBackwardJump(JSOp op, JumpTarget target, JumpList* jump, JumpTarget* fallthrough)
2429{
2430 if (!emitJumpNoFallthrough(op, jump))
2431 return false;
2432 patchJumpsToTarget(*jump, target);
2433
2434 // Unconditionally create a fallthrough for closing iterators, and as a
2435 // target for break statements.
2436 if (!emitJumpTarget(fallthrough))
2437 return false;
2438 return true;
2439}
2440
2441void
2442BytecodeEmitter::patchJumpsToTarget(JumpList jump, JumpTarget target)
2443{
2444 MOZ_ASSERT(-1 <= jump.offset && jump.offset <= offset())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(-1 <= jump.offset && jump.offset <= offset
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(-1 <= jump.offset && jump.offset <= offset
()))), 0))) { MOZ_ReportAssertionFailure("-1 <= jump.offset && jump.offset <= offset()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2444); do { } while (false); do { *((volatile int*) __null)
= 2444; ::abort(); } while (false); } } while (false)
;
2445 MOZ_ASSERT(0 <= target.offset && target.offset <= offset())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(0 <= target.offset && target.offset <=
offset())>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(0 <= target.offset && target
.offset <= offset()))), 0))) { MOZ_ReportAssertionFailure(
"0 <= target.offset && target.offset <= offset()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2445); do { } while (false); do { *((volatile int*) __null)
= 2445; ::abort(); } while (false); } } while (false)
;
2446 MOZ_ASSERT_IF(jump.offset != -1 && target.offset + 4 <= offset(),do { if (jump.offset != -1 && target.offset + 4 <=
offset()) { do { static_assert(mozilla::detail::AssertionConditionType
<decltype(BytecodeIsJumpTarget(JSOp(*code(target.offset)))
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(BytecodeIsJumpTarget(JSOp(*code(target.offset)))))),
0))) { MOZ_ReportAssertionFailure("BytecodeIsJumpTarget(JSOp(*code(target.offset)))"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2447); do { } while (false); do { *((volatile int*) __null)
= 2447; ::abort(); } while (false); } } while (false); } } while
(false)
2447 BytecodeIsJumpTarget(JSOp(*code(target.offset))))do { if (jump.offset != -1 && target.offset + 4 <=
offset()) { do { static_assert(mozilla::detail::AssertionConditionType
<decltype(BytecodeIsJumpTarget(JSOp(*code(target.offset)))
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(BytecodeIsJumpTarget(JSOp(*code(target.offset)))))),
0))) { MOZ_ReportAssertionFailure("BytecodeIsJumpTarget(JSOp(*code(target.offset)))"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2447); do { } while (false); do { *((volatile int*) __null)
= 2447; ::abort(); } while (false); } } while (false); } } while
(false)
;
2448 jump.patchAll(code(0), target);
2449}
2450
2451bool
2452BytecodeEmitter::emitJumpTargetAndPatch(JumpList jump)
2453{
2454 if (jump.offset == -1)
2455 return true;
2456 JumpTarget target;
2457 if (!emitJumpTarget(&target))
2458 return false;
2459 patchJumpsToTarget(jump, target);
2460 return true;
2461}
2462
2463bool
2464BytecodeEmitter::emitCall(JSOp op, uint16_t argc, ParseNode* pn)
2465{
2466 if (pn && !updateSourceCoordNotes(pn->pn_pos.begin))
2467 return false;
2468 return emit3(op, ARGC_LO(argc), ARGC_HI(argc));
2469}
2470
2471bool
2472BytecodeEmitter::emitDupAt(unsigned slotFromTop)
2473{
2474 MOZ_ASSERT(slotFromTop < unsigned(stackDepth))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(slotFromTop < unsigned(stackDepth))>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(slotFromTop < unsigned(stackDepth)))), 0))) { MOZ_ReportAssertionFailure
("slotFromTop < unsigned(stackDepth)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2474); do { } while (false); do { *((volatile int*) __null)
= 2474; ::abort(); } while (false); } } while (false)
;
2475
2476 if (slotFromTop == 0)
2477 return emit1(JSOP_DUP);
2478
2479 if (slotFromTop >= JS_BIT(24)((uint32_t)1 << (24))) {
2480 reportError(nullptr, JSMSG_TOO_MANY_LOCALS);
2481 return false;
2482 }
2483
2484 ptrdiff_t off;
2485 if (!emitN(JSOP_DUPAT, 3, &off))
2486 return false;
2487
2488 jsbytecode* pc = code(off);
2489 SET_UINT24(pc, slotFromTop);
2490 return true;
2491}
2492
2493bool
2494BytecodeEmitter::emitPopN(unsigned n)
2495{
2496 MOZ_ASSERT(n != 0)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(n != 0)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(n != 0))), 0))) { MOZ_ReportAssertionFailure
("n != 0", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2496); do { } while (false); do { *((volatile int*) __null)
= 2496; ::abort(); } while (false); } } while (false)
;
2497
2498 if (n == 1)
2499 return emit1(JSOP_POP);
2500
2501 // 2 JSOP_POPs (2 bytes) are shorter than JSOP_POPN (3 bytes).
2502 if (n == 2)
2503 return emit1(JSOP_POP) && emit1(JSOP_POP);
2504
2505 return emitUint16Operand(JSOP_POPN, n);
2506}
2507
2508bool
2509BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind)
2510{
2511 return emit2(JSOP_CHECKISOBJ, uint8_t(kind));
2512}
2513
2514bool
2515BytecodeEmitter::emitCheckIsCallable(CheckIsCallableKind kind)
2516{
2517 return emit2(JSOP_CHECKISCALLABLE, uint8_t(kind));
2518}
2519
2520static inline unsigned
2521LengthOfSetLine(unsigned line)
2522{
2523 return 1 /* SRC_SETLINE */ + (line > SN_4BYTE_OFFSET_MASK0x7f ? 4 : 1);
2524}
2525
2526/* Updates line number notes, not column notes. */
2527bool
2528BytecodeEmitter::updateLineNumberNotes(uint32_t offset)
2529{
2530 TokenStreamAnyChars* ts = &parser.tokenStream();
2531 bool onThisLine;
2532 if (!ts->srcCoords.isOnThisLine(offset, currentLine(), &onThisLine)) {
2533 ts->reportErrorNoOffset(JSMSG_OUT_OF_MEMORY);
2534 return false;
2535 }
2536
2537 if (!onThisLine) {
2538 unsigned line = ts->srcCoords.lineNum(offset);
2539 unsigned delta = line - currentLine();
2540
2541 /*
2542 * Encode any change in the current source line number by using
2543 * either several SRC_NEWLINE notes or just one SRC_SETLINE note,
2544 * whichever consumes less space.
2545 *
2546 * NB: We handle backward line number deltas (possible with for
2547 * loops where the update part is emitted after the body, but its
2548 * line number is <= any line number in the body) here by letting
2549 * unsigned delta_ wrap to a very large number, which triggers a
2550 * SRC_SETLINE.
2551 */
2552 current->currentLine = line;
2553 current->lastColumn = 0;
2554 if (delta >= LengthOfSetLine(line)) {
2555 if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(line)))
2556 return false;
2557 } else {
2558 do {
2559 if (!newSrcNote(SRC_NEWLINE))
2560 return false;
2561 } while (--delta != 0);
2562 }
2563 }
2564 return true;
2565}
2566
2567/* Updates the line number and column number information in the source notes. */
2568bool
2569BytecodeEmitter::updateSourceCoordNotes(uint32_t offset)
2570{
2571 if (!updateLineNumberNotes(offset))
2572 return false;
2573
2574 uint32_t columnIndex = parser.tokenStream().srcCoords.columnIndex(offset);
2575 ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(current->lastColumn);
2576 if (colspan != 0) {
2577 // If the column span is so large that we can't store it, then just
2578 // discard this information. This can happen with minimized or otherwise
2579 // machine-generated code. Even gigantic column numbers are still
2580 // valuable if you have a source map to relate them to something real;
2581 // but it's better to fail soft here.
2582 if (!SN_REPRESENTABLE_COLSPAN(colspan))
2583 return true;
2584 if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan)))
2585 return false;
2586 current->lastColumn = columnIndex;
2587 }
2588 return true;
2589}
2590
2591bool
2592BytecodeEmitter::emitLoopHead(ParseNode* nextpn, JumpTarget* top)
2593{
2594 if (nextpn) {
2595 /*
2596 * Try to give the JSOP_LOOPHEAD the same line number as the next
2597 * instruction. nextpn is often a block, in which case the next
2598 * instruction typically comes from the first statement inside.
2599 */
2600 if (nextpn->isKind(ParseNodeKind::LexicalScope))
2601 nextpn = nextpn->scopeBody();
2602 MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList), nextpn->isArity(PN_LIST))do { if (nextpn->isKind(ParseNodeKind::StatementList)) { do
{ static_assert(mozilla::detail::AssertionConditionType<decltype
(nextpn->isArity(PN_LIST))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nextpn->isArity(PN_LIST))
)), 0))) { MOZ_ReportAssertionFailure("nextpn->isArity(PN_LIST)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2602); do { } while (false); do { *((volatile int*) __null)
= 2602; ::abort(); } while (false); } } while (false); } } while
(false)
;
2603 if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_headpn_u.list.head)
2604 nextpn = nextpn->pn_headpn_u.list.head;
2605 if (!updateSourceCoordNotes(nextpn->pn_pos.begin))
2606 return false;
2607 }
2608
2609 *top = { offset() };
2610 return emit1(JSOP_LOOPHEAD);
2611}
2612
2613bool
2614BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump)
2615{
2616 if (nextpn) {
2617 /* Update the line number, as for LOOPHEAD. */
2618 if (nextpn->isKind(ParseNodeKind::LexicalScope))
2619 nextpn = nextpn->scopeBody();
2620 MOZ_ASSERT_IF(nextpn->isKind(ParseNodeKind::StatementList), nextpn->isArity(PN_LIST))do { if (nextpn->isKind(ParseNodeKind::StatementList)) { do
{ static_assert(mozilla::detail::AssertionConditionType<decltype
(nextpn->isArity(PN_LIST))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nextpn->isArity(PN_LIST))
)), 0))) { MOZ_ReportAssertionFailure("nextpn->isArity(PN_LIST)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2620); do { } while (false); do { *((volatile int*) __null)
= 2620; ::abort(); } while (false); } } while (false); } } while
(false)
;
2621 if (nextpn->isKind(ParseNodeKind::StatementList) && nextpn->pn_headpn_u.list.head)
2622 nextpn = nextpn->pn_headpn_u.list.head;
2623 if (!updateSourceCoordNotes(nextpn->pn_pos.begin))
2624 return false;
2625 }
2626
2627 JumpTarget entry{ offset() };
2628 patchJumpsToTarget(entryJump, entry);
2629
2630 LoopControl& loopInfo = innermostNestableControl->as<LoopControl>();
2631 MOZ_ASSERT(loopInfo.loopDepth() > 0)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(loopInfo.loopDepth() > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(loopInfo.loopDepth() > 0)
)), 0))) { MOZ_ReportAssertionFailure("loopInfo.loopDepth() > 0"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2631); do { } while (false); do { *((volatile int*) __null)
= 2631; ::abort(); } while (false); } } while (false)
;
2632
2633 uint8_t loopDepthAndFlags = PackLoopEntryDepthHintAndFlags(loopInfo.loopDepth(),
2634 loopInfo.canIonOsr());
2635 return emit2(JSOP_LOOPENTRY, loopDepthAndFlags);
2636}
2637
2638void
2639BytecodeEmitter::checkTypeSet(JSOp op)
2640{
2641 if (CodeSpec[op].format & JOF_TYPESET) {
2642 if (typesetCount < UINT16_MAX(65535))
2643 typesetCount++;
2644 }
2645}
2646
2647bool
2648BytecodeEmitter::emitUint16Operand(JSOp op, uint32_t operand)
2649{
2650 MOZ_ASSERT(operand <= UINT16_MAX)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(operand <= (65535))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(operand <= (65535)))), 0)
)) { MOZ_ReportAssertionFailure("operand <= (65535)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2650); do { } while (false); do { *((volatile int*) __null)
= 2650; ::abort(); } while (false); } } while (false)
;
2651 if (!emit3(op, UINT16_LO(operand), UINT16_HI(operand)))
2652 return false;
2653 checkTypeSet(op);
2654 return true;
2655}
2656
2657bool
2658BytecodeEmitter::emitUint32Operand(JSOp op, uint32_t operand)
2659{
2660 ptrdiff_t off;
2661 if (!emitN(op, 4, &off))
2662 return false;
2663 SET_UINT32(code(off), operand);
2664 checkTypeSet(op);
2665 return true;
2666}
2667
2668namespace {
2669
2670class NonLocalExitControl
2671{
2672 public:
2673 enum Kind
2674 {
2675 // IteratorClose is handled especially inside the exception unwinder.
2676 Throw,
2677
2678 // A 'continue' statement does not call IteratorClose for the loop it
2679 // is continuing, i.e. excluding the target loop.
2680 Continue,
2681
2682 // A 'break' or 'return' statement does call IteratorClose for the
2683 // loop it is breaking out of or returning from, i.e. including the
2684 // target loop.
2685 Break,
2686 Return
2687 };
2688
2689 private:
2690 BytecodeEmitter* bce_;
2691 const uint32_t savedScopeNoteIndex_;
2692 const int savedDepth_;
2693 uint32_t openScopeNoteIndex_;
2694 Kind kind_;
2695
2696 NonLocalExitControl(const NonLocalExitControl&) = delete;
2697
2698 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool leaveScope(BytecodeEmitter::EmitterScope* scope);
2699
2700 public:
2701 NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
2702 : bce_(bce),
2703 savedScopeNoteIndex_(bce->scopeNoteList.length()),
2704 savedDepth_(bce->stackDepth),
2705 openScopeNoteIndex_(bce->innermostEmitterScope->noteIndex()),
2706 kind_(kind)
2707 { }
2708
2709 ~NonLocalExitControl() {
2710 for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length(); n++)
2711 bce_->scopeNoteList.recordEnd(n, bce_->offset(), bce_->inPrologue());
2712 bce_->stackDepth = savedDepth_;
2713 }
2714
2715 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool prepareForNonLocalJump(BytecodeEmitter::NestableControl* target);
2716
2717 MOZ_MUST_USE__attribute__ ((warn_unused_result)) bool prepareForNonLocalJumpToOutermost() {
2718 return prepareForNonLocalJump(nullptr);
2719 }
2720};
2721
2722bool
2723NonLocalExitControl::leaveScope(BytecodeEmitter::EmitterScope* es)
2724{
2725 if (!es->leave(bce_, /* nonLocal = */ true))
2726 return false;
2727
2728 // As we pop each scope due to the non-local jump, emit notes that
2729 // record the extent of the enclosing scope. These notes will have
2730 // their ends recorded in ~NonLocalExitControl().
2731 uint32_t enclosingScopeIndex = ScopeNote::NoScopeIndex;
2732 if (es->enclosingInFrame())
2733 enclosingScopeIndex = es->enclosingInFrame()->index();
2734 if (!bce_->scopeNoteList.append(enclosingScopeIndex, bce_->offset(), bce_->inPrologue(),
2735 openScopeNoteIndex_))
2736 return false;
2737 openScopeNoteIndex_ = bce_->scopeNoteList.length() - 1;
2738
2739 return true;
2740}
2741
2742/*
2743 * Emit additional bytecode(s) for non-local jumps.
2744 */
2745bool
2746NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* target)
2747{
2748 using NestableControl = BytecodeEmitter::NestableControl;
2749 using EmitterScope = BytecodeEmitter::EmitterScope;
2750
2751 EmitterScope* es = bce_->innermostEmitterScope;
2752 int npops = 0;
2753
2754 // For 'continue', 'break', and 'return' statements, emit IteratorClose
2755 // bytecode inline. 'continue' statements do not call IteratorClose for
2756 // the loop they are continuing.
2757 bool emitIteratorClose = kind_ == Continue || kind_ == Break || kind_ == Return;
2758 bool emitIteratorCloseAtTarget = emitIteratorClose && kind_ != Continue;
2759
2760 auto flushPops = [&npops](BytecodeEmitter* bce) {
2761 if (npops && !bce->emitPopN(npops))
2762 return false;
2763 npops = 0;
2764 return true;
2765 };
2766
2767 // Walk the nestable control stack and patch jumps.
2768 for (NestableControl* control = bce_->innermostNestableControl;
2769 control != target;
2770 control = control->enclosing())
2771 {
2772 // Walk the scope stack and leave the scopes we entered. Leaving a scope
2773 // may emit administrative ops like JSOP_POPLEXICALENV but never anything
2774 // that manipulates the stack.
2775 for (; es != control->emitterScope(); es = es->enclosingInFrame()) {
2776 if (!leaveScope(es))
2777 return false;
2778 }
2779
2780 switch (control->kind()) {
2781 case StatementKind::Finally: {
2782 TryFinallyControl& finallyControl = control->as<TryFinallyControl>();
2783 if (finallyControl.emittingSubroutine()) {
2784 /*
2785 * There's a [exception or hole, retsub pc-index] pair and the
2786 * possible return value on the stack that we need to pop.
2787 */
2788 npops += 3;
2789 } else {
2790 if (!flushPops(bce_))
2791 return false;
2792 if (!bce_->emitJump(JSOP_GOSUB, &finallyControl.gosubs)) // ...
2793 return false;
2794 }
2795 break;
2796 }
2797
2798 case StatementKind::ForOfLoop:
2799 if (emitIteratorClose) {
2800 if (!flushPops(bce_))
2801 return false;
2802
2803 ForOfLoopControl& loopinfo = control->as<ForOfLoopControl>();
2804 if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ false)) // ...
2805 return false;
2806 } else {
2807 // The iterator next method, the iterator, and the current
2808 // value are on the stack.
2809 npops += 3;
2810 }
2811 break;
2812
2813 case StatementKind::ForInLoop:
2814 if (!flushPops(bce_))
2815 return false;
2816
2817 // The iterator and the current value are on the stack.
2818 if (!bce_->emit1(JSOP_POP)) // ... ITER
2819 return false;
2820 if (!bce_->emit1(JSOP_ENDITER)) // ...
2821 return false;
2822 break;
2823
2824 default:
2825 break;
2826 }
2827 }
2828
2829 if (!flushPops(bce_))
2830 return false;
2831
2832 if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
2833 ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
2834 if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ true)) // ... UNDEF UNDEF UNDEF
2835 return false;
2836 }
2837
2838 EmitterScope* targetEmitterScope = target ? target->emitterScope() : bce_->varEmitterScope;
2839 for (; es != targetEmitterScope; es = es->enclosingInFrame()) {
2840 if (!leaveScope(es))
2841 return false;
2842 }
2843
2844 return true;
2845}
2846
2847} // anonymous namespace
2848
2849bool
2850BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist, SrcNoteType noteType)
2851{
2852 NonLocalExitControl nle(this, noteType == SRC_CONTINUE
2853 ? NonLocalExitControl::Continue
2854 : NonLocalExitControl::Break);
2855
2856 if (!nle.prepareForNonLocalJump(target))
2857 return false;
2858
2859 if (noteType != SRC_NULL) {
2860 if (!newSrcNote(noteType))
2861 return false;
2862 }
2863
2864 return emitJump(JSOP_GOTO, jumplist);
2865}
2866
2867Scope*
2868BytecodeEmitter::innermostScope() const
2869{
2870 return innermostEmitterScope->scope(this);
2871}
2872
2873bool
2874BytecodeEmitter::emitIndex32(JSOp op, uint32_t index)
2875{
2876 MOZ_ASSERT(checkStrictOrSloppy(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(checkStrictOrSloppy(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(checkStrictOrSloppy(op)))), 0
))) { MOZ_ReportAssertionFailure("checkStrictOrSloppy(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2876); do { } while (false); do { *((volatile int*) __null)
= 2876; ::abort(); } while (false); } } while (false)
;
2877
2878 const size_t len = 1 + UINT32_INDEX_LEN;
2879 MOZ_ASSERT(len == size_t(CodeSpec[op].length))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(len == size_t(CodeSpec[op].length))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(len == size_t(CodeSpec[op].length
)))), 0))) { MOZ_ReportAssertionFailure("len == size_t(CodeSpec[op].length)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2879); do { } while (false); do { *((volatile int*) __null)
= 2879; ::abort(); } while (false); } } while (false)
;
2880
2881 ptrdiff_t offset;
2882 if (!emitCheck(len, &offset))
2883 return false;
2884
2885 jsbytecode* code = this->code(offset);
2886 code[0] = jsbytecode(op);
2887 SET_UINT32_INDEX(code, index);
2888 checkTypeSet(op);
2889 updateDepth(offset);
2890 return true;
2891}
2892
2893bool
2894BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index)
2895{
2896 MOZ_ASSERT(checkStrictOrSloppy(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(checkStrictOrSloppy(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(checkStrictOrSloppy(op)))), 0
))) { MOZ_ReportAssertionFailure("checkStrictOrSloppy(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2896); do { } while (false); do { *((volatile int*) __null)
= 2896; ::abort(); } while (false); } } while (false)
;
2897
2898 const size_t len = CodeSpec[op].length;
2899 MOZ_ASSERT(len >= 1 + UINT32_INDEX_LEN)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(len >= 1 + UINT32_INDEX_LEN)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(len >= 1 + UINT32_INDEX_LEN
))), 0))) { MOZ_ReportAssertionFailure("len >= 1 + UINT32_INDEX_LEN"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2899); do { } while (false); do { *((volatile int*) __null)
= 2899; ::abort(); } while (false); } } while (false)
;
2900
2901 ptrdiff_t offset;
2902 if (!emitCheck(len, &offset))
2903 return false;
2904
2905 jsbytecode* code = this->code(offset);
2906 code[0] = jsbytecode(op);
2907 SET_UINT32_INDEX(code, index);
2908 checkTypeSet(op);
2909 updateDepth(offset);
2910 return true;
2911}
2912
2913bool
2914BytecodeEmitter::emitAtomOp(JSAtom* atom, JSOp op)
2915{
2916 MOZ_ASSERT(atom)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(atom)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(atom))), 0))) { MOZ_ReportAssertionFailure
("atom", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2916); do { } while (false); do { *((volatile int*) __null)
= 2916; ::abort(); } while (false); } } while (false)
;
2917 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(JOF_OPTYPE(op) == JOF_ATOM)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JOF_OPTYPE(op) == JOF_ATOM))
), 0))) { MOZ_ReportAssertionFailure("JOF_OPTYPE(op) == JOF_ATOM"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2917); do { } while (false); do { *((volatile int*) __null)
= 2917; ::abort(); } while (false); } } while (false)
;
2918
2919 // .generator lookups should be emitted as JSOP_GETALIASEDVAR instead of
2920 // JSOP_GETNAME etc, to bypass |with| objects on the scope chain.
2921 // It's safe to emit .this lookups though because |with| objects skip
2922 // those.
2923 MOZ_ASSERT_IF(op == JSOP_GETNAME || op == JSOP_GETGNAME,do { if (op == JSOP_GETNAME || op == JSOP_GETGNAME) { do { static_assert
(mozilla::detail::AssertionConditionType<decltype(atom != cx
->names().dotGenerator)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(atom != cx->names().dotGenerator
))), 0))) { MOZ_ReportAssertionFailure("atom != cx->names().dotGenerator"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2924); do { } while (false); do { *((volatile int*) __null)
= 2924; ::abort(); } while (false); } } while (false); } } while
(false)
2924 atom != cx->names().dotGenerator)do { if (op == JSOP_GETNAME || op == JSOP_GETGNAME) { do { static_assert
(mozilla::detail::AssertionConditionType<decltype(atom != cx
->names().dotGenerator)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(atom != cx->names().dotGenerator
))), 0))) { MOZ_ReportAssertionFailure("atom != cx->names().dotGenerator"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2924); do { } while (false); do { *((volatile int*) __null)
= 2924; ::abort(); } while (false); } } while (false); } } while
(false)
;
2925
2926 if (op == JSOP_GETPROP && atom == cx->names().length) {
2927 /* Specialize length accesses for the interpreter. */
2928 op = JSOP_LENGTH;
2929 }
2930
2931 uint32_t index;
2932 if (!makeAtomIndex(atom, &index))
2933 return false;
2934
2935 return emitIndexOp(op, index);
2936}
2937
2938bool
2939BytecodeEmitter::emitAtomOp(ParseNode* pn, JSOp op)
2940{
2941 MOZ_ASSERT(pn->pn_atom != nullptr)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.name.atom != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->pn_u.name.atom != nullptr
))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.name.atom != nullptr"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2941); do { } while (false); do { *((volatile int*) __null)
= 2941; ::abort(); } while (false); } } while (false)
;
2942 return emitAtomOp(pn->pn_atompn_u.name.atom, op);
2943}
2944
2945bool
2946BytecodeEmitter::emitInternedScopeOp(uint32_t index, JSOp op)
2947{
2948 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(JOF_OPTYPE(op) == JOF_SCOPE)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JOF_OPTYPE(op) == JOF_SCOPE)
)), 0))) { MOZ_ReportAssertionFailure("JOF_OPTYPE(op) == JOF_SCOPE"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2948); do { } while (false); do { *((volatile int*) __null)
= 2948; ::abort(); } while (false); } } while (false)
;
2949 MOZ_ASSERT(index < scopeList.length())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(index < scopeList.length())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(index < scopeList.length(
)))), 0))) { MOZ_ReportAssertionFailure("index < scopeList.length()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2949); do { } while (false); do { *((volatile int*) __null)
= 2949; ::abort(); } while (false); } } while (false)
;
2950 return emitIndex32(op, index);
2951}
2952
2953bool
2954BytecodeEmitter::emitInternedObjectOp(uint32_t index, JSOp op)
2955{
2956 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(JOF_OPTYPE(op) == JOF_OBJECT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JOF_OPTYPE(op) == JOF_OBJECT
))), 0))) { MOZ_ReportAssertionFailure("JOF_OPTYPE(op) == JOF_OBJECT"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2956); do { } while (false); do { *((volatile int*) __null)
= 2956; ::abort(); } while (false); } } while (false)
;
2957 MOZ_ASSERT(index < objectList.length)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(index < objectList.length)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(index < objectList.length
))), 0))) { MOZ_ReportAssertionFailure("index < objectList.length"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2957); do { } while (false); do { *((volatile int*) __null)
= 2957; ::abort(); } while (false); } } while (false)
;
2958 return emitIndex32(op, index);
2959}
2960
2961bool
2962BytecodeEmitter::emitObjectOp(ObjectBox* objbox, JSOp op)
2963{
2964 return emitInternedObjectOp(objectList.add(objbox), op);
2965}
2966
2967bool
2968BytecodeEmitter::emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op)
2969{
2970 uint32_t index = objectList.add(objbox1);
2971 objectList.add(objbox2);
2972 return emitInternedObjectOp(index, op);
2973}
2974
2975bool
2976BytecodeEmitter::emitRegExp(uint32_t index)
2977{
2978 return emitIndex32(JSOP_REGEXP, index);
2979}
2980
2981bool
2982BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot)
2983{
2984 MOZ_ASSERT(JOF_OPTYPE(op) != JOF_ENVCOORD)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(JOF_OPTYPE(op) != JOF_ENVCOORD)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JOF_OPTYPE(op) != JOF_ENVCOORD
))), 0))) { MOZ_ReportAssertionFailure("JOF_OPTYPE(op) != JOF_ENVCOORD"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2984); do { } while (false); do { *((volatile int*) __null)
= 2984; ::abort(); } while (false); } } while (false)
;
2985 MOZ_ASSERT(IsLocalOp(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(IsLocalOp(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsLocalOp(op)))), 0))) { MOZ_ReportAssertionFailure
("IsLocalOp(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2985); do { } while (false); do { *((volatile int*) __null)
= 2985; ::abort(); } while (false); } } while (false)
;
2986
2987 ptrdiff_t off;
2988 if (!emitN(op, LOCALNO_LEN, &off))
2989 return false;
2990
2991 SET_LOCALNO(code(off), slot);
2992 return true;
2993}
2994
2995bool
2996BytecodeEmitter::emitArgOp(JSOp op, uint16_t slot)
2997{
2998 MOZ_ASSERT(IsArgOp(op))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(IsArgOp(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsArgOp(op)))), 0))) { MOZ_ReportAssertionFailure
("IsArgOp(op)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 2998); do { } while (false); do { *((volatile int*) __null)
= 2998; ::abort(); } while (false); } } while (false)
;
2999 ptrdiff_t off;
3000 if (!emitN(op, ARGNO_LEN, &off))
3001 return false;
3002
3003 SET_ARGNO(code(off), slot);
3004 return true;
3005}
3006
3007bool
3008BytecodeEmitter::emitEnvCoordOp(JSOp op, EnvironmentCoordinate ec)
3009{
3010 MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ENVCOORD)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(JOF_OPTYPE(op) == JOF_ENVCOORD)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JOF_OPTYPE(op) == JOF_ENVCOORD
))), 0))) { MOZ_ReportAssertionFailure("JOF_OPTYPE(op) == JOF_ENVCOORD"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3010); do { } while (false); do { *((volatile int*) __null)
= 3010; ::abort(); } while (false); } } while (false)
;
3011
3012 unsigned n = ENVCOORD_HOPS_LEN + ENVCOORD_SLOT_LEN;
3013 MOZ_ASSERT(int(n) + 1 /* op */ == CodeSpec[op].length)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(int(n) + 1 == CodeSpec[op].length)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int(n) + 1 == CodeSpec[op].length
))), 0))) { MOZ_ReportAssertionFailure("int(n) + 1 == CodeSpec[op].length"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3013); do { } while (false); do { *((volatile int*) __null)
= 3013; ::abort(); } while (false); } } while (false)
;
3014
3015 ptrdiff_t off;
3016 if (!emitN(op, n, &off))
3017 return false;
3018
3019 jsbytecode* pc = code(off);
3020 SET_ENVCOORD_HOPS(pc, ec.hops());
3021 pc += ENVCOORD_HOPS_LEN;
3022 SET_ENVCOORD_SLOT(pc, ec.slot());
3023 pc += ENVCOORD_SLOT_LEN;
3024 checkTypeSet(op);
3025 return true;
3026}
3027
3028static JSOp
3029GetIncDecInfo(ParseNodeKind kind, bool* post)
3030{
3031 MOZ_ASSERT(kind == ParseNodeKind::PostIncrement ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind
::PreIncrement || kind == ParseNodeKind::PostDecrement || kind
== ParseNodeKind::PreDecrement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(kind == ParseNodeKind::PostIncrement
|| kind == ParseNodeKind::PreIncrement || kind == ParseNodeKind
::PostDecrement || kind == ParseNodeKind::PreDecrement))), 0)
)) { MOZ_ReportAssertionFailure("kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind::PreIncrement || kind == ParseNodeKind::PostDecrement || kind == ParseNodeKind::PreDecrement"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3034); do { } while (false); do { *((volatile int*) __null)
= 3034; ::abort(); } while (false); } } while (false)
3032 kind == ParseNodeKind::PreIncrement ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind
::PreIncrement || kind == ParseNodeKind::PostDecrement || kind
== ParseNodeKind::PreDecrement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(kind == ParseNodeKind::PostIncrement
|| kind == ParseNodeKind::PreIncrement || kind == ParseNodeKind
::PostDecrement || kind == ParseNodeKind::PreDecrement))), 0)
)) { MOZ_ReportAssertionFailure("kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind::PreIncrement || kind == ParseNodeKind::PostDecrement || kind == ParseNodeKind::PreDecrement"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3034); do { } while (false); do { *((volatile int*) __null)
= 3034; ::abort(); } while (false); } } while (false)
3033 kind == ParseNodeKind::PostDecrement ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind
::PreIncrement || kind == ParseNodeKind::PostDecrement || kind
== ParseNodeKind::PreDecrement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(kind == ParseNodeKind::PostIncrement
|| kind == ParseNodeKind::PreIncrement || kind == ParseNodeKind
::PostDecrement || kind == ParseNodeKind::PreDecrement))), 0)
)) { MOZ_ReportAssertionFailure("kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind::PreIncrement || kind == ParseNodeKind::PostDecrement || kind == ParseNodeKind::PreDecrement"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3034); do { } while (false); do { *((volatile int*) __null)
= 3034; ::abort(); } while (false); } } while (false)
3034 kind == ParseNodeKind::PreDecrement)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind
::PreIncrement || kind == ParseNodeKind::PostDecrement || kind
== ParseNodeKind::PreDecrement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(kind == ParseNodeKind::PostIncrement
|| kind == ParseNodeKind::PreIncrement || kind == ParseNodeKind
::PostDecrement || kind == ParseNodeKind::PreDecrement))), 0)
)) { MOZ_ReportAssertionFailure("kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind::PreIncrement || kind == ParseNodeKind::PostDecrement || kind == ParseNodeKind::PreDecrement"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3034); do { } while (false); do { *((volatile int*) __null)
= 3034; ::abort(); } while (false); } } while (false)
;
3035 *post = kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind::PostDecrement;
3036 return (kind == ParseNodeKind::PostIncrement || kind == ParseNodeKind::PreIncrement)
3037 ? JSOP_ADD
3038 : JSOP_SUB;
3039}
3040
3041JSOp
3042BytecodeEmitter::strictifySetNameOp(JSOp op)
3043{
3044 switch (op) {
3045 case JSOP_SETNAME:
3046 if (sc->strict())
3047 op = JSOP_STRICTSETNAME;
3048 break;
3049 case JSOP_SETGNAME:
3050 if (sc->strict())
3051 op = JSOP_STRICTSETGNAME;
3052 break;
3053 default:;
3054 }
3055 return op;
3056}
3057
3058bool
3059BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
3060{
3061 if (!CheckRecursionLimit(cx))
3062 return false;
3063
3064 restart:
3065
3066 switch (pn->getKind()) {
3067 // Trivial cases with no side effects.
3068 case ParseNodeKind::EmptyStatement:
3069 case ParseNodeKind::String:
3070 case ParseNodeKind::TemplateString:
3071 case ParseNodeKind::RegExp:
3072 case ParseNodeKind::True:
3073 case ParseNodeKind::False:
3074 case ParseNodeKind::Null:
3075 case ParseNodeKind::RawUndefined:
3076 case ParseNodeKind::Elision:
3077 case ParseNodeKind::Generator:
3078 case ParseNodeKind::Number:
3079 case ParseNodeKind::ObjectPropertyName:
3080 MOZ_ASSERT(pn->isArity(PN_NULLARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_NULLARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_NULLARY)))
), 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_NULLARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3080); do { } while (false); do { *((volatile int*) __null)
= 3080; ::abort(); } while (false); } } while (false)
;
3081 *answer = false;
3082 return true;
3083
3084 // |this| can throw in derived class constructors, including nested arrow
3085 // functions or eval.
3086 case ParseNodeKind::This:
3087 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3087); do { } while (false); do { *((volatile int*) __null)
= 3087; ::abort(); } while (false); } } while (false)
;
3088 *answer = sc->needsThisTDZChecks();
3089 return true;
3090
3091 // Trivial binary nodes with more token pos holders.
3092 case ParseNodeKind::NewTarget:
3093 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3093); do { } while (false); do { *((volatile int*) __null)
= 3093; ::abort(); } while (false); } } while (false)
;
3094 MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::PosHolder))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.binary.left->isKind(ParseNodeKind::PosHolder
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pn->pn_u.binary.left->isKind(ParseNodeKind::PosHolder
)))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.binary.left->isKind(ParseNodeKind::PosHolder)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3094); do { } while (false); do { *((volatile int*) __null)
= 3094; ::abort(); } while (false); } } while (false)
;
3095 MOZ_ASSERT(pn->pn_right->isKind(ParseNodeKind::PosHolder))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.binary.right->isKind(ParseNodeKind::PosHolder
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pn->pn_u.binary.right->isKind(ParseNodeKind::PosHolder
)))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.binary.right->isKind(ParseNodeKind::PosHolder)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3095); do { } while (false); do { *((volatile int*) __null)
= 3095; ::abort(); } while (false); } } while (false)
;
3096 *answer = false;
3097 return true;
3098
3099 case ParseNodeKind::Break:
3100 case ParseNodeKind::Continue:
3101 case ParseNodeKind::Debugger:
3102 MOZ_ASSERT(pn->isArity(PN_NULLARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_NULLARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_NULLARY)))
), 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_NULLARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3102); do { } while (false); do { *((volatile int*) __null)
= 3102; ::abort(); } while (false); } } while (false)
;
3103 *answer = true;
3104 return true;
3105
3106 // Watch out for getters!
3107 case ParseNodeKind::Dot:
3108 MOZ_ASSERT(pn->isArity(PN_NAME))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_NAME))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_NAME)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_NAME)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3108); do { } while (false); do { *((volatile int*) __null)
= 3108; ::abort(); } while (false); } } while (false)
;
3109 *answer = true;
3110 return true;
3111
3112 // Unary cases with side effects only if the child has them.
3113 case ParseNodeKind::TypeOfExpr:
3114 case ParseNodeKind::Void:
3115 case ParseNodeKind::Not:
3116 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3116); do { } while (false); do { *((volatile int*) __null)
= 3116; ::abort(); } while (false); } } while (false)
;
3117 return checkSideEffects(pn->pn_kidpn_u.unary.kid, answer);
3118
3119 // Even if the name expression is effect-free, performing ToPropertyKey on
3120 // it might not be effect-free:
3121 //
3122 // RegExp.prototype.toString = () => { throw 42; };
3123 // ({ [/regex/]: 0 }); // ToPropertyKey(/regex/) throws 42
3124 //
3125 // function Q() {
3126 // ({ [new.target]: 0 });
3127 // }
3128 // Q.toString = () => { throw 17; };
3129 // new Q; // new.target will be Q, ToPropertyKey(Q) throws 17
3130 case ParseNodeKind::ComputedName:
3131 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3131); do { } while (false); do { *((volatile int*) __null)
= 3131; ::abort(); } while (false); } } while (false)
;
3132 *answer = true;
3133 return true;
3134
3135 // Looking up or evaluating the associated name could throw.
3136 case ParseNodeKind::TypeOfName:
3137 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3137); do { } while (false); do { *((volatile int*) __null)
= 3137; ::abort(); } while (false); } } while (false)
;
3138 *answer = true;
3139 return true;
3140
3141 // This unary case has side effects on the enclosing object, sure. But
3142 // that's not the question this function answers: it's whether the
3143 // operation may have a side effect on something *other* than the result
3144 // of the overall operation in which it's embedded. The answer to that
3145 // is no, because an object literal having a mutated prototype only
3146 // produces a value, without affecting anything else.
3147 case ParseNodeKind::MutateProto:
3148 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3148); do { } while (false); do { *((volatile int*) __null)
= 3148; ::abort(); } while (false); } } while (false)
;
3149 return checkSideEffects(pn->pn_kidpn_u.unary.kid, answer);
3150
3151 // Unary cases with obvious side effects.
3152 case ParseNodeKind::PreIncrement:
3153 case ParseNodeKind::PostIncrement:
3154 case ParseNodeKind::PreDecrement:
3155 case ParseNodeKind::PostDecrement:
3156 case ParseNodeKind::Throw:
3157 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3157); do { } while (false); do { *((volatile int*) __null)
= 3157; ::abort(); } while (false); } } while (false)
;
3158 *answer = true;
3159 return true;
3160
3161 // These might invoke valueOf/toString, even with a subexpression without
3162 // side effects! Consider |+{ valueOf: null, toString: null }|.
3163 case ParseNodeKind::BitNot:
3164 case ParseNodeKind::Pos:
3165 case ParseNodeKind::Neg:
3166 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3166); do { } while (false); do { *((volatile int*) __null)
= 3166; ::abort(); } while (false); } } while (false)
;
3167 *answer = true;
3168 return true;
3169
3170 // This invokes the (user-controllable) iterator protocol.
3171 case ParseNodeKind::Spread:
3172 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3172); do { } while (false); do { *((volatile int*) __null)
= 3172; ::abort(); } while (false); } } while (false)
;
3173 *answer = true;
3174 return true;
3175
3176 case ParseNodeKind::InitialYield:
3177 case ParseNodeKind::YieldStar:
3178 case ParseNodeKind::Yield:
3179 case ParseNodeKind::Await:
3180 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3180); do { } while (false); do { *((volatile int*) __null)
= 3180; ::abort(); } while (false); } } while (false)
;
3181 *answer = true;
3182 return true;
3183
3184 // Deletion generally has side effects, even if isolated cases have none.
3185 case ParseNodeKind::DeleteName:
3186 case ParseNodeKind::DeleteProp:
3187 case ParseNodeKind::DeleteElem:
3188 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3188); do { } while (false); do { *((volatile int*) __null)
= 3188; ::abort(); } while (false); } } while (false)
;
3189 *answer = true;
3190 return true;
3191
3192 // Deletion of a non-Reference expression has side effects only through
3193 // evaluating the expression.
3194 case ParseNodeKind::DeleteExpr: {
3195 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3195); do { } while (false); do { *((volatile int*) __null)
= 3195; ::abort(); } while (false); } } while (false)
;
3196 ParseNode* expr = pn->pn_kidpn_u.unary.kid;
3197 return checkSideEffects(expr, answer);
3198 }
3199
3200 case ParseNodeKind::ExpressionStatement:
3201 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3201); do { } while (false); do { *((volatile int*) __null)
= 3201; ::abort(); } while (false); } } while (false)
;
3202 return checkSideEffects(pn->pn_kidpn_u.unary.kid, answer);
3203
3204 // Binary cases with obvious side effects.
3205 case ParseNodeKind::Assign:
3206 case ParseNodeKind::AddAssign:
3207 case ParseNodeKind::SubAssign:
3208 case ParseNodeKind::BitOrAssign:
3209 case ParseNodeKind::BitXorAssign:
3210 case ParseNodeKind::BitAndAssign:
3211 case ParseNodeKind::LshAssign:
3212 case ParseNodeKind::RshAssign:
3213 case ParseNodeKind::UrshAssign:
3214 case ParseNodeKind::MulAssign:
3215 case ParseNodeKind::DivAssign:
3216 case ParseNodeKind::ModAssign:
3217 case ParseNodeKind::PowAssign:
3218 case ParseNodeKind::SetThis:
3219 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3219); do { } while (false); do { *((volatile int*) __null)
= 3219; ::abort(); } while (false); } } while (false)
;
3220 *answer = true;
3221 return true;
3222
3223 case ParseNodeKind::StatementList:
3224 // Strict equality operations and logical operators are well-behaved and
3225 // perform no conversions.
3226 case ParseNodeKind::Or:
3227 case ParseNodeKind::And:
3228 case ParseNodeKind::StrictEq:
3229 case ParseNodeKind::StrictNe:
3230 // Any subexpression of a comma expression could be effectful.
3231 case ParseNodeKind::Comma:
3232 MOZ_ASSERT(pn->pn_count > 0)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.list.count > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->pn_u.list.count > 0
))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.list.count > 0"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3232); do { } while (false); do { *((volatile int*) __null)
= 3232; ::abort(); } while (false); } } while (false)
;
3233 MOZ_FALLTHROUGH[[clang::fallthrough]];
3234 // Subcomponents of a literal may be effectful.
3235 case ParseNodeKind::Array:
3236 case ParseNodeKind::Object:
3237 MOZ_ASSERT(pn->isArity(PN_LIST))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_LIST))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_LIST)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_LIST)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3237); do { } while (false); do { *((volatile int*) __null)
= 3237; ::abort(); } while (false); } } while (false)
;
3238 for (ParseNode* item = pn->pn_headpn_u.list.head; item; item = item->pn_next) {
3239 if (!checkSideEffects(item, answer))
3240 return false;
3241 if (*answer)
3242 return true;
3243 }
3244 return true;
3245
3246 // Most other binary operations (parsed as lists in SpiderMonkey) may
3247 // perform conversions triggering side effects. Math operations perform
3248 // ToNumber and may fail invoking invalid user-defined toString/valueOf:
3249 // |5 < { toString: null }|. |instanceof| throws if provided a
3250 // non-object constructor: |null instanceof null|. |in| throws if given
3251 // a non-object RHS: |5 in null|.
3252 case ParseNodeKind::BitOr:
3253 case ParseNodeKind::BitXor:
3254 case ParseNodeKind::BitAnd:
3255 case ParseNodeKind::Eq:
3256 case ParseNodeKind::Ne:
3257 case ParseNodeKind::Lt:
3258 case ParseNodeKind::Le:
3259 case ParseNodeKind::Gt:
3260 case ParseNodeKind::Ge:
3261 case ParseNodeKind::InstanceOf:
3262 case ParseNodeKind::In:
3263 case ParseNodeKind::Lsh:
3264 case ParseNodeKind::Rsh:
3265 case ParseNodeKind::Ursh:
3266 case ParseNodeKind::Add:
3267 case ParseNodeKind::Sub:
3268 case ParseNodeKind::Star:
3269 case ParseNodeKind::Div:
3270 case ParseNodeKind::Mod:
3271 case ParseNodeKind::Pow:
3272 MOZ_ASSERT(pn->isArity(PN_LIST))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_LIST))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_LIST)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_LIST)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3272); do { } while (false); do { *((volatile int*) __null)
= 3272; ::abort(); } while (false); } } while (false)
;
3273 MOZ_ASSERT(pn->pn_count >= 2)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.list.count >= 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->pn_u.list.count >=
2))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.list.count >= 2"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3273); do { } while (false); do { *((volatile int*) __null)
= 3273; ::abort(); } while (false); } } while (false)
;
3274 *answer = true;
3275 return true;
3276
3277 case ParseNodeKind::Colon:
3278 case ParseNodeKind::Case:
3279 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3279); do { } while (false); do { *((volatile int*) __null)
= 3279; ::abort(); } while (false); } } while (false)
;
3280 if (!checkSideEffects(pn->pn_leftpn_u.binary.left, answer))
3281 return false;
3282 if (*answer)
3283 return true;
3284 return checkSideEffects(pn->pn_rightpn_u.binary.right, answer);
3285
3286 // More getters.
3287 case ParseNodeKind::Elem:
3288 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3288); do { } while (false); do { *((volatile int*) __null)
= 3288; ::abort(); } while (false); } } while (false)
;
3289 *answer = true;
3290 return true;
3291
3292 // These affect visible names in this code, or in other code.
3293 case ParseNodeKind::Import:
3294 case ParseNodeKind::ExportFrom:
3295 case ParseNodeKind::ExportDefault:
3296 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3296); do { } while (false); do { *((volatile int*) __null)
= 3296; ::abort(); } while (false); } } while (false)
;
3297 *answer = true;
3298 return true;
3299
3300 // Likewise.
3301 case ParseNodeKind::Export:
3302 MOZ_ASSERT(pn->isArity(PN_UNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_UNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_UNARY)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_UNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3302); do { } while (false); do { *((volatile int*) __null)
= 3302; ::abort(); } while (false); } } while (false)
;
3303 *answer = true;
3304 return true;
3305
3306 // Every part of a loop might be effect-free, but looping infinitely *is*
3307 // an effect. (Language lawyer trivia: C++ says threads can be assumed
3308 // to exit or have side effects, C++14 [intro.multithread]p27, so a C++
3309 // implementation's equivalent of the below could set |*answer = false;|
3310 // if all loop sub-nodes set |*answer = false|!)
3311 case ParseNodeKind::DoWhile:
3312 case ParseNodeKind::While:
3313 case ParseNodeKind::For:
3314 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3314); do { } while (false); do { *((volatile int*) __null)
= 3314; ::abort(); } while (false); } } while (false)
;
3315 *answer = true;
3316 return true;
3317
3318 // Declarations affect the name set of the relevant scope.
3319 case ParseNodeKind::Var:
3320 case ParseNodeKind::Const:
3321 case ParseNodeKind::Let:
3322 MOZ_ASSERT(pn->isArity(PN_LIST))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_LIST))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_LIST)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_LIST)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3322); do { } while (false); do { *((volatile int*) __null)
= 3322; ::abort(); } while (false); } } while (false)
;
3323 *answer = true;
3324 return true;
3325
3326 case ParseNodeKind::If:
3327 case ParseNodeKind::Conditional:
3328 MOZ_ASSERT(pn->isArity(PN_TERNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_TERNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_TERNARY)))
), 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_TERNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3328); do { } while (false); do { *((volatile int*) __null)
= 3328; ::abort(); } while (false); } } while (false)
;
3329 if (!checkSideEffects(pn->pn_kid1pn_u.ternary.kid1, answer))
3330 return false;
3331 if (*answer)
3332 return true;
3333 if (!checkSideEffects(pn->pn_kid2pn_u.ternary.kid2, answer))
3334 return false;
3335 if (*answer)
3336 return true;
3337 if ((pn = pn->pn_kid3pn_u.ternary.kid3))
3338 goto restart;
3339 return true;
3340
3341 // Function calls can invoke non-local code.
3342 case ParseNodeKind::New:
3343 case ParseNodeKind::Call:
3344 case ParseNodeKind::TaggedTemplate:
3345 case ParseNodeKind::SuperCall:
3346 MOZ_ASSERT(pn->isArity(PN_LIST))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_LIST))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_LIST)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_LIST)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3346); do { } while (false); do { *((volatile int*) __null)
= 3346; ::abort(); } while (false); } } while (false)
;
3347 *answer = true;
3348 return true;
3349
3350 case ParseNodeKind::Pipeline:
3351 MOZ_ASSERT(pn->isArity(PN_LIST))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_LIST))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_LIST)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_LIST)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3351); do { } while (false); do { *((volatile int*) __null)
= 3351; ::abort(); } while (false); } } while (false)
;
3352 MOZ_ASSERT(pn->pn_count >= 2)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.list.count >= 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->pn_u.list.count >=
2))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.list.count >= 2"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3352); do { } while (false); do { *((volatile int*) __null)
= 3352; ::abort(); } while (false); } } while (false)
;
3353 *answer = true;
3354 return true;
3355
3356 // Classes typically introduce names. Even if no name is introduced,
3357 // the heritage and/or class body (through computed property names)
3358 // usually have effects.
3359 case ParseNodeKind::Class:
3360 MOZ_ASSERT(pn->isArity(PN_TERNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_TERNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_TERNARY)))
), 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_TERNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3360); do { } while (false); do { *((volatile int*) __null)
= 3360; ::abort(); } while (false); } } while (false)
;
3361 *answer = true;
3362 return true;
3363
3364 // |with| calls |ToObject| on its expression and so throws if that value
3365 // is null/undefined.
3366 case ParseNodeKind::With:
3367 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3367); do { } while (false); do { *((volatile int*) __null)
= 3367; ::abort(); } while (false); } } while (false)
;
3368 *answer = true;
3369 return true;
3370
3371 case ParseNodeKind::Return:
3372 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3372); do { } while (false); do { *((volatile int*) __null)
= 3372; ::abort(); } while (false); } } while (false)
;
3373 *answer = true;
3374 return true;
3375
3376 case ParseNodeKind::Name:
3377 MOZ_ASSERT(pn->isArity(PN_NAME))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_NAME))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_NAME)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_NAME)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3377); do { } while (false); do { *((volatile int*) __null)
= 3377; ::abort(); } while (false); } } while (false)
;
3378 *answer = true;
3379 return true;
3380
3381 // Shorthands could trigger getters: the |x| in the object literal in
3382 // |with ({ get x() { throw 42; } }) ({ x });|, for example, triggers
3383 // one. (Of course, it isn't necessary to use |with| for a shorthand to
3384 // trigger a getter.)
3385 case ParseNodeKind::Shorthand:
3386 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3386); do { } while (false); do { *((volatile int*) __null)
= 3386; ::abort(); } while (false); } } while (false)
;
3387 *answer = true;
3388 return true;
3389
3390 case ParseNodeKind::Function:
3391 MOZ_ASSERT(pn->isArity(PN_CODE))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_CODE))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_CODE)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_CODE)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3391); do { } while (false); do { *((volatile int*) __null)
= 3391; ::abort(); } while (false); } } while (false)
;
3392 /*
3393 * A named function, contrary to ES3, is no longer effectful, because
3394 * we bind its name lexically (using JSOP_CALLEE) instead of creating
3395 * an Object instance and binding a readonly, permanent property in it
3396 * (the object and binding can be detected and hijacked or captured).
3397 * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
3398 */
3399 *answer = false;
3400 return true;
3401
3402 case ParseNodeKind::Module:
3403 *answer = false;
3404 return true;
3405
3406 case ParseNodeKind::Try:
3407 MOZ_ASSERT(pn->isArity(PN_TERNARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_TERNARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_TERNARY)))
), 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_TERNARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3407); do { } while (false); do { *((volatile int*) __null)
= 3407; ::abort(); } while (false); } } while (false)
;
3408 if (!checkSideEffects(pn->pn_kid1pn_u.ternary.kid1, answer))
3409 return false;
3410 if (*answer)
3411 return true;
3412 if (ParseNode* catchScope = pn->pn_kid2pn_u.ternary.kid2) {
3413 MOZ_ASSERT(catchScope->isKind(ParseNodeKind::LexicalScope))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(catchScope->isKind(ParseNodeKind::LexicalScope))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(catchScope->isKind(ParseNodeKind::LexicalScope)))
), 0))) { MOZ_ReportAssertionFailure("catchScope->isKind(ParseNodeKind::LexicalScope)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3413); do { } while (false); do { *((volatile int*) __null)
= 3413; ::abort(); } while (false); } } while (false)
;
3414 if (!checkSideEffects(catchScope, answer))
3415 return false;
3416 if (*answer)
3417 return true;
3418 }
3419 if (ParseNode* finallyBlock = pn->pn_kid3pn_u.ternary.kid3) {
3420 if (!checkSideEffects(finallyBlock, answer))
3421 return false;
3422 }
3423 return true;
3424
3425 case ParseNodeKind::Catch:
3426 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3426); do { } while (false); do { *((volatile int*) __null)
= 3426; ::abort(); } while (false); } } while (false)
;
3427 if (ParseNode* name = pn->pn_leftpn_u.binary.left) {
3428 if (!checkSideEffects(name, answer))
3429 return false;
3430 if (*answer)
3431 return true;
3432 }
3433 return checkSideEffects(pn->pn_rightpn_u.binary.right, answer);
3434
3435 case ParseNodeKind::Switch:
3436 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3436); do { } while (false); do { *((volatile int*) __null)
= 3436; ::abort(); } while (false); } } while (false)
;
3437 if (!checkSideEffects(pn->pn_leftpn_u.binary.left, answer))
3438 return false;
3439 return *answer || checkSideEffects(pn->pn_rightpn_u.binary.right, answer);
3440
3441 case ParseNodeKind::Label:
3442 MOZ_ASSERT(pn->isArity(PN_NAME))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_NAME))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_NAME)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_NAME)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3442); do { } while (false); do { *((volatile int*) __null)
= 3442; ::abort(); } while (false); } } while (false)
;
3443 return checkSideEffects(pn->expr(), answer);
3444
3445 case ParseNodeKind::LexicalScope:
3446 MOZ_ASSERT(pn->isArity(PN_SCOPE))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_SCOPE))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_SCOPE)))),
0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_SCOPE)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3446); do { } while (false); do { *((volatile int*) __null)
= 3446; ::abort(); } while (false); } } while (false)
;
3447 return checkSideEffects(pn->scopeBody(), answer);
3448
3449 // We could methodically check every interpolated expression, but it's
3450 // probably not worth the trouble. Treat template strings as effect-free
3451 // only if they don't contain any substitutions.
3452 case ParseNodeKind::TemplateStringList:
3453 MOZ_ASSERT(pn->isArity(PN_LIST))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_LIST))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_LIST)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_LIST)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3453); do { } while (false); do { *((volatile int*) __null)
= 3453; ::abort(); } while (false); } } while (false)
;
3454 MOZ_ASSERT(pn->pn_count > 0)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.list.count > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->pn_u.list.count > 0
))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.list.count > 0"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3454); do { } while (false); do { *((volatile int*) __null)
= 3454; ::abort(); } while (false); } } while (false)
;
3455 MOZ_ASSERT((pn->pn_count % 2) == 1,do { static_assert(mozilla::detail::AssertionConditionType<
decltype((pn->pn_u.list.count % 2) == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((pn->pn_u.list.count % 2)
== 1))), 0))) { MOZ_ReportAssertionFailure("(pn->pn_u.list.count % 2) == 1"
" (" "template strings must alternate template and substitution "
"parts" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3457); do { } while (false); do { *((volatile int*) __null)
= 3457; ::abort(); } while (false); } } while (false)
3456 "template strings must alternate template and substitution "do { static_assert(mozilla::detail::AssertionConditionType<
decltype((pn->pn_u.list.count % 2) == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((pn->pn_u.list.count % 2)
== 1))), 0))) { MOZ_ReportAssertionFailure("(pn->pn_u.list.count % 2) == 1"
" (" "template strings must alternate template and substitution "
"parts" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3457); do { } while (false); do { *((volatile int*) __null)
= 3457; ::abort(); } while (false); } } while (false)
3457 "parts")do { static_assert(mozilla::detail::AssertionConditionType<
decltype((pn->pn_u.list.count % 2) == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((pn->pn_u.list.count % 2)
== 1))), 0))) { MOZ_ReportAssertionFailure("(pn->pn_u.list.count % 2) == 1"
" (" "template strings must alternate template and substitution "
"parts" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3457); do { } while (false); do { *((volatile int*) __null)
= 3457; ::abort(); } while (false); } } while (false)
;
3458 *answer = pn->pn_countpn_u.list.count > 1;
3459 return true;
3460
3461 // This should be unreachable but is left as-is for now.
3462 case ParseNodeKind::ParamsBody:
3463 *answer = true;
3464 return true;
3465
3466 case ParseNodeKind::ForIn: // by ParseNodeKind::For
3467 case ParseNodeKind::ForOf: // by ParseNodeKind::For
3468 case ParseNodeKind::ForHead: // by ParseNodeKind::For
3469 case ParseNodeKind::ClassMethod: // by ParseNodeKind::Class
3470 case ParseNodeKind::ClassNames: // by ParseNodeKind::Class
3471 case ParseNodeKind::ClassMethodList: // by ParseNodeKind::Class
3472 case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
3473 case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
3474 case ParseNodeKind::ExportBatchSpec:// by ParseNodeKind::Export
3475 case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
3476 case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
3477 case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
3478 case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
3479 case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
3480 MOZ_CRASH("handled by parent nodes")do { MOZ_ReportCrash("" "handled by parent nodes", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3480); do { } while (false); do { *((volatile int*) __null)
= 3480; ::abort(); } while (false); } while (false)
;
3481
3482 case ParseNodeKind::Limit: // invalid sentinel value
3483 MOZ_CRASH("invalid node kind")do { MOZ_ReportCrash("" "invalid node kind", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3483); do { } while (false); do { *((volatile int*) __null)
= 3483; ::abort(); } while (false); } while (false)
;
3484 }
3485
3486 MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in "do { MOZ_ReportCrash("" "invalid, unenumerated ParseNodeKind value encountered in "
"BytecodeEmitter::checkSideEffects", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3487); do { } while (false); do { *((volatile int*) __null)
= 3487; ::abort(); } while (false); } while (false)
3487 "BytecodeEmitter::checkSideEffects")do { MOZ_ReportCrash("" "invalid, unenumerated ParseNodeKind value encountered in "
"BytecodeEmitter::checkSideEffects", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3487); do { } while (false); do { *((volatile int*) __null)
= 3487; ::abort(); } while (false); } while (false)
;
3488}
3489
3490bool
3491BytecodeEmitter::isInLoop()
3492{
3493 return findInnermostNestableControl<LoopControl>();
3494}
3495
3496bool
3497BytecodeEmitter::checkSingletonContext()
3498{
3499 if (!script->treatAsRunOnce() || sc->isFunctionBox() || isInLoop())
3500 return false;
3501 hasSingletons = true;
3502 return true;
3503}
3504
3505bool
3506BytecodeEmitter::checkRunOnceContext()
3507{
3508 return checkSingletonContext() || (!isInLoop() && isRunOnceLambda());
3509}
3510
3511bool
3512BytecodeEmitter::needsImplicitThis()
3513{
3514 // Short-circuit if there is an enclosing 'with' scope.
3515 if (sc->inWith())
3516 return true;
3517
3518 // Otherwise see if the current point is under a 'with'.
3519 for (EmitterScope* es = innermostEmitterScope; es; es = es->enclosingInFrame()) {
3520 if (es->scope(this)->kind() == ScopeKind::With)
3521 return true;
3522 }
3523
3524 return false;
3525}
3526
3527bool
3528BytecodeEmitter::maybeSetDisplayURL()
3529{
3530 if (tokenStream().hasDisplayURL()) {
3531 if (!parser.ss()->setDisplayURL(cx, tokenStream().displayURL()))
3532 return false;
3533 }
3534 return true;
3535}
3536
3537bool
3538BytecodeEmitter::maybeSetSourceMap()
3539{
3540 if (tokenStream().hasSourceMapURL()) {
3541 MOZ_ASSERT(!parser.ss()->hasSourceMapURL())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!parser.ss()->hasSourceMapURL())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!parser.ss()->hasSourceMapURL
()))), 0))) { MOZ_ReportAssertionFailure("!parser.ss()->hasSourceMapURL()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3541); do { } while (false); do { *((volatile int*) __null)
= 3541; ::abort(); } while (false); } } while (false)
;
3542 if (!parser.ss()->setSourceMapURL(cx, tokenStream().sourceMapURL()))
3543 return false;
3544 }
3545
3546 /*
3547 * Source map URLs passed as a compile option (usually via a HTTP source map
3548 * header) override any source map urls passed as comment pragmas.
3549 */
3550 if (parser.options().sourceMapURL()) {
3551 // Warn about the replacement, but use the new one.
3552 if (parser.ss()->hasSourceMapURL()) {
3553 if (!parser.warningNoOffset(JSMSG_ALREADY_HAS_PRAGMA,
3554 parser.ss()->filename(), "//# sourceMappingURL"))
3555 {
3556 return false;
3557 }
3558 }
3559
3560 if (!parser.ss()->setSourceMapURL(cx, parser.options().sourceMapURL()))
3561 return false;
3562 }
3563
3564 return true;
3565}
3566
3567void
3568BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext* cx)
3569{
3570 // Note: when parsing off thread the resulting scripts need to be handed to
3571 // the debugger after rejoining to the active thread.
3572 if (cx->helperThread())
3573 return;
3574
3575 // Lazy scripts are never top level (despite always being invoked with a
3576 // nullptr parent), and so the hook should never be fired.
3577 if (emitterMode != LazyFunction && !parent)
3578 Debugger::onNewScript(cx, script);
3579}
3580
3581inline TokenStreamAnyChars&
3582BytecodeEmitter::tokenStream()
3583{
3584 return parser.tokenStream();
3585}
3586
3587void
3588BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
3589{
3590 TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
3591
3592 va_list args;
3593 va_start(args, errorNumber)__builtin_va_start(args, errorNumber);
3594
3595 ErrorMetadata metadata;
3596 if (parser.computeErrorMetadata(&metadata, pos.begin))
3597 ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR0x0, errorNumber, args);
3598
3599 va_end(args)__builtin_va_end(args);
3600}
3601
3602bool
3603BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
3604{
3605 TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
3606
3607 va_list args;
3608 va_start(args, errorNumber)__builtin_va_start(args, errorNumber);
3609
3610 bool result = parser.reportExtraWarningErrorNumberVA(nullptr, pos.begin, errorNumber, &args);
3611
3612 va_end(args)__builtin_va_end(args);
3613 return result;
3614}
3615
3616bool
3617BytecodeEmitter::emitNewInit(JSProtoKey key)
3618{
3619 const size_t len = 1 + UINT32_INDEX_LEN;
3620 ptrdiff_t offset;
3621 if (!emitCheck(len, &offset))
3622 return false;
3623
3624 jsbytecode* code = this->code(offset);
3625 code[0] = JSOP_NEWINIT;
3626 code[1] = jsbytecode(key);
3627 code[2] = 0;
3628 code[3] = 0;
3629 code[4] = 0;
3630 checkTypeSet(JSOP_NEWINIT);
3631 updateDepth(offset);
3632 return true;
3633}
3634
3635bool
3636BytecodeEmitter::iteratorResultShape(unsigned* shape)
3637{
3638 // No need to do any guessing for the object kind, since we know exactly how
3639 // many properties we plan to have.
3640 gc::AllocKind kind = gc::GetGCObjectKind(2);
3641 RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject));
3642 if (!obj)
3643 return false;
3644
3645 Rooted<jsid> value_id(cx, NameToId(cx->names().value));
3646 Rooted<jsid> done_id(cx, NameToId(cx->names().done));
3647 if (!NativeDefineDataProperty(cx, obj, value_id, UndefinedHandleValue, JSPROP_ENUMERATE))
3648 return false;
3649 if (!NativeDefineDataProperty(cx, obj, done_id, UndefinedHandleValue, JSPROP_ENUMERATE))
3650 return false;
3651
3652 ObjectBox* objbox = parser.newObjectBox(obj);
3653 if (!objbox)
3654 return false;
3655
3656 *shape = objectList.add(objbox);
3657
3658 return true;
3659}
3660
3661bool
3662BytecodeEmitter::emitPrepareIteratorResult()
3663{
3664 unsigned shape;
3665 if (!iteratorResultShape(&shape))
3666 return false;
3667 return emitIndex32(JSOP_NEWOBJECT, shape);
3668}
3669
3670bool
3671BytecodeEmitter::emitFinishIteratorResult(bool done)
3672{
3673 uint32_t value_id;
3674 if (!makeAtomIndex(cx->names().value, &value_id))
3675 return false;
3676 uint32_t done_id;
3677 if (!makeAtomIndex(cx->names().done, &done_id))
3678 return false;
3679
3680 if (!emitIndex32(JSOP_INITPROP, value_id))
3681 return false;
3682 if (!emit1(done ? JSOP_TRUE : JSOP_FALSE))
3683 return false;
3684 if (!emitIndex32(JSOP_INITPROP, done_id))
3685 return false;
3686 return true;
3687}
3688
3689bool
3690BytecodeEmitter::emitGetNameAtLocation(JSAtom* name, const NameLocation& loc, bool callContext)
3691{
3692 switch (loc.kind()) {
3693 case NameLocation::Kind::Dynamic:
3694 if (!emitAtomOp(name, JSOP_GETNAME))
3695 return false;
3696 break;
3697
3698 case NameLocation::Kind::Global:
3699 if (!emitAtomOp(name, JSOP_GETGNAME))
3700 return false;
3701 break;
3702
3703 case NameLocation::Kind::Intrinsic:
3704 if (!emitAtomOp(name, JSOP_GETINTRINSIC))
3705 return false;
3706 break;
3707
3708 case NameLocation::Kind::NamedLambdaCallee:
3709 if (!emit1(JSOP_CALLEE))
3710 return false;
3711 break;
3712
3713 case NameLocation::Kind::Import:
3714 if (!emitAtomOp(name, JSOP_GETIMPORT))
3715 return false;
3716 break;
3717
3718 case NameLocation::Kind::ArgumentSlot:
3719 if (!emitArgOp(JSOP_GETARG, loc.argumentSlot()))
3720 return false;
3721 break;
3722
3723 case NameLocation::Kind::FrameSlot:
3724 if (loc.isLexical()) {
3725 if (!emitTDZCheckIfNeeded(name, loc))
3726 return false;
3727 }
3728 if (!emitLocalOp(JSOP_GETLOCAL, loc.frameSlot()))
3729 return false;
3730 break;
3731
3732 case NameLocation::Kind::EnvironmentCoordinate:
3733 if (loc.isLexical()) {
3734 if (!emitTDZCheckIfNeeded(name, loc))
3735 return false;
3736 }
3737 if (!emitEnvCoordOp(JSOP_GETALIASEDVAR, loc.environmentCoordinate()))
3738 return false;
3739 break;
3740
3741 case NameLocation::Kind::DynamicAnnexBVar:
3742 MOZ_CRASH("Synthesized vars for Annex B.3.3 should only be used in initialization")do { MOZ_ReportCrash("" "Synthesized vars for Annex B.3.3 should only be used in initialization"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3742); do { } while (false); do { *((volatile int*) __null)
= 3742; ::abort(); } while (false); } while (false)
;
3743 }
3744
3745 // Need to provide |this| value for call.
3746 if (callContext) {
3747 switch (loc.kind()) {
3748 case NameLocation::Kind::Dynamic: {
3749 JSOp thisOp = needsImplicitThis() ? JSOP_IMPLICITTHIS : JSOP_GIMPLICITTHIS;
3750 if (!emitAtomOp(name, thisOp))
3751 return false;
3752 break;
3753 }
3754
3755 case NameLocation::Kind::Global:
3756 if (!emitAtomOp(name, JSOP_GIMPLICITTHIS))
3757 return false;
3758 break;
3759
3760 case NameLocation::Kind::Intrinsic:
3761 case NameLocation::Kind::NamedLambdaCallee:
3762 case NameLocation::Kind::Import:
3763 case NameLocation::Kind::ArgumentSlot:
3764 case NameLocation::Kind::FrameSlot:
3765 case NameLocation::Kind::EnvironmentCoordinate:
3766 if (!emit1(JSOP_UNDEFINED))
3767 return false;
3768 break;
3769
3770 case NameLocation::Kind::DynamicAnnexBVar:
3771 MOZ_CRASH("Synthesized vars for Annex B.3.3 should only be used in initialization")do { MOZ_ReportCrash("" "Synthesized vars for Annex B.3.3 should only be used in initialization"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3771); do { } while (false); do { *((volatile int*) __null)
= 3771; ::abort(); } while (false); } while (false)
;
3772 }
3773 }
3774
3775 return true;
3776}
3777
3778bool
3779BytecodeEmitter::emitGetName(ParseNode* pn, bool callContext)
3780{
3781 return emitGetName(pn->name(), callContext);
3782}
3783
3784template <typename RHSEmitter>
3785bool
3786BytecodeEmitter::emitSetOrInitializeNameAtLocation(HandleAtom name, const NameLocation& loc,
3787 RHSEmitter emitRhs, bool initialize)
3788{
3789 bool emittedBindOp = false;
3790
3791 switch (loc.kind()) {
3792 case NameLocation::Kind::Dynamic:
3793 case NameLocation::Kind::Import:
3794 case NameLocation::Kind::DynamicAnnexBVar: {
3795 uint32_t atomIndex;
3796 if (!makeAtomIndex(name, &atomIndex))
3797 return false;
3798 if (loc.kind() == NameLocation::Kind::DynamicAnnexBVar) {
3799 // Annex B vars always go on the nearest variable environment,
3800 // even if lexical environments in between contain same-named
3801 // bindings.
3802 if (!emit1(JSOP_BINDVAR))
3803 return false;
3804 } else {
3805 if (!emitIndexOp(JSOP_BINDNAME, atomIndex))
3806 return false;
3807 }
3808 emittedBindOp = true;
3809 if (!emitRhs(this, loc, emittedBindOp))
3810 return false;
3811 if (!emitIndexOp(strictifySetNameOp(JSOP_SETNAME), atomIndex))
3812 return false;
3813 break;
3814 }
3815
3816 case NameLocation::Kind::Global: {
3817 JSOp op;
3818 uint32_t atomIndex;
3819 if (!makeAtomIndex(name, &atomIndex))
3820 return false;
3821 if (loc.isLexical() && initialize) {
3822 // INITGLEXICAL always gets the global lexical scope. It doesn't
3823 // need a BINDGNAME.
3824 MOZ_ASSERT(innermostScope()->is<GlobalScope>())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(innermostScope()->is<GlobalScope>())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(innermostScope()->is<GlobalScope>()))), 0))) { MOZ_ReportAssertionFailure
("innermostScope()->is<GlobalScope>()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3824); do { } while (false); do { *((volatile int*) __null)
= 3824; ::abort(); } while (false); } } while (false)
;
3825 op = JSOP_INITGLEXICAL;
3826 } else {
3827 if (!emitIndexOp(JSOP_BINDGNAME, atomIndex))
3828 return false;
3829 emittedBindOp = true;
3830 op = strictifySetNameOp(JSOP_SETGNAME);
3831 }
3832 if (!emitRhs(this, loc, emittedBindOp))
3833 return false;
3834 if (!emitIndexOp(op, atomIndex))
3835 return false;
3836 break;
3837 }
3838
3839 case NameLocation::Kind::Intrinsic:
3840 if (!emitRhs(this, loc, emittedBindOp))
3841 return false;
3842 if (!emitAtomOp(name, JSOP_SETINTRINSIC))
3843 return false;
3844 break;
3845
3846 case NameLocation::Kind::NamedLambdaCallee:
3847 if (!emitRhs(this, loc, emittedBindOp))
3848 return false;
3849 // Assigning to the named lambda is a no-op in sloppy mode but
3850 // throws in strict mode.
3851 if (sc->strict() && !emit1(JSOP_THROWSETCALLEE))
3852 return false;
3853 break;
3854
3855 case NameLocation::Kind::ArgumentSlot: {
3856 // If we assign to a positional formal parameter and the arguments
3857 // object is unmapped (strict mode or function with
3858 // default/rest/destructing args), parameters do not alias
3859 // arguments[i], and to make the arguments object reflect initial
3860 // parameter values prior to any mutation we create it eagerly
3861 // whenever parameters are (or might, in the case of calls to eval)
3862 // assigned.
3863 FunctionBox* funbox = sc->asFunctionBox();
3864 if (funbox->argumentsHasLocalBinding() && !funbox->hasMappedArgsObj())
3865 funbox->setDefinitelyNeedsArgsObj();
3866
3867 if (!emitRhs(this, loc, emittedBindOp))
3868 return false;
3869 if (!emitArgOp(JSOP_SETARG, loc.argumentSlot()))
3870 return false;
3871 break;
3872 }
3873
3874 case NameLocation::Kind::FrameSlot: {
3875 JSOp op = JSOP_SETLOCAL;
3876 if (!emitRhs(this, loc, emittedBindOp))
3877 return false;
3878 if (loc.isLexical()) {
3879 if (initialize) {
3880 op = JSOP_INITLEXICAL;
3881 } else {
3882 if (loc.isConst())
3883 op = JSOP_THROWSETCONST;
3884
3885 if (!emitTDZCheckIfNeeded(name, loc))
3886 return false;
3887 }
3888 }
3889 if (!emitLocalOp(op, loc.frameSlot()))
3890 return false;
3891 if (op == JSOP_INITLEXICAL) {
3892 if (!innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ))
3893 return false;
3894 }
3895 break;
3896 }
3897
3898 case NameLocation::Kind::EnvironmentCoordinate: {
3899 JSOp op = JSOP_SETALIASEDVAR;
3900 if (!emitRhs(this, loc, emittedBindOp))
3901 return false;
3902 if (loc.isLexical()) {
3903 if (initialize) {
3904 op = JSOP_INITALIASEDLEXICAL;
3905 } else {
3906 if (loc.isConst())
3907 op = JSOP_THROWSETALIASEDCONST;
3908
3909 if (!emitTDZCheckIfNeeded(name, loc))
3910 return false;
3911 }
3912 }
3913 if (loc.bindingKind() == BindingKind::NamedLambdaCallee) {
3914 // Assigning to the named lambda is a no-op in sloppy mode and throws
3915 // in strict mode.
3916 op = JSOP_THROWSETALIASEDCONST;
3917 if (sc->strict() && !emitEnvCoordOp(op, loc.environmentCoordinate()))
3918 return false;
3919 } else {
3920 if (!emitEnvCoordOp(op, loc.environmentCoordinate()))
3921 return false;
3922 }
3923 if (op == JSOP_INITALIASEDLEXICAL) {
3924 if (!innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ))
3925 return false;
3926 }
3927 break;
3928 }
3929 }
3930
3931 return true;
3932}
3933
3934bool
3935BytecodeEmitter::emitTDZCheckIfNeeded(JSAtom* name, const NameLocation& loc)
3936{
3937 // Dynamic accesses have TDZ checks built into their VM code and should
3938 // never emit explicit TDZ checks.
3939 MOZ_ASSERT(loc.hasKnownSlot())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(loc.hasKnownSlot())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(loc.hasKnownSlot()))), 0))) {
MOZ_ReportAssertionFailure("loc.hasKnownSlot()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3939); do { } while (false); do { *((volatile int*) __null)
= 3939; ::abort(); } while (false); } } while (false)
;
3940 MOZ_ASSERT(loc.isLexical())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(loc.isLexical())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(loc.isLexical()))), 0))) { MOZ_ReportAssertionFailure
("loc.isLexical()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3940); do { } while (false); do { *((volatile int*) __null)
= 3940; ::abort(); } while (false); } } while (false)
;
3941
3942 Maybe<MaybeCheckTDZ> check = innermostTDZCheckCache->needsTDZCheck(this, name);
3943 if (!check)
3944 return false;
3945
3946 // We've already emitted a check in this basic block.
3947 if (*check == DontCheckTDZ)
3948 return true;
3949
3950 if (loc.kind() == NameLocation::Kind::FrameSlot) {
3951 if (!emitLocalOp(JSOP_CHECKLEXICAL, loc.frameSlot()))
3952 return false;
3953 } else {
3954 if (!emitEnvCoordOp(JSOP_CHECKALIASEDLEXICAL, loc.environmentCoordinate()))
3955 return false;
3956 }
3957
3958 return innermostTDZCheckCache->noteTDZCheck(this, name, DontCheckTDZ);
3959}
3960
3961bool
3962BytecodeEmitter::emitPropLHS(ParseNode* pn)
3963{
3964 MOZ_ASSERT(pn->isKind(ParseNodeKind::Dot))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isKind(ParseNodeKind::Dot))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isKind(ParseNodeKind::
Dot)))), 0))) { MOZ_ReportAssertionFailure("pn->isKind(ParseNodeKind::Dot)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3964); do { } while (false); do { *((volatile int*) __null)
= 3964; ::abort(); } while (false); } } while (false)
;
3965 MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!pn->as<PropertyAccess>().isSuper())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!pn->as<PropertyAccess>().isSuper()))), 0))) { MOZ_ReportAssertionFailure
("!pn->as<PropertyAccess>().isSuper()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 3965); do { } while (false); do { *((volatile int*) __null)
= 3965; ::abort(); } while (false); } } while (false)
;
3966
3967 ParseNode* pn2 = pn->pn_exprpn_u.name.expr;
3968
3969 /*
3970 * If the object operand is also a dotted property reference, reverse the
3971 * list linked via pn_expr temporarily so we can iterate over it from the
3972 * bottom up (reversing again as we go), to avoid excessive recursion.
3973 */
3974 if (pn2->isKind(ParseNodeKind::Dot) && !pn2->as<PropertyAccess>().isSuper()) {
3975 ParseNode* pndot = pn2;
3976 ParseNode* pnup = nullptr;
3977 ParseNode* pndown;
3978 for (;;) {
3979 /* Reverse pndot->pn_expr to point up, not down. */
3980 pndown = pndot->pn_exprpn_u.name.expr;
3981 pndot->pn_exprpn_u.name.expr = pnup;
3982 if (!pndown->isKind(ParseNodeKind::Dot) || pndown->as<PropertyAccess>().isSuper())
3983 break;
3984 pnup = pndot;
3985 pndot = pndown;
3986 }
3987
3988 /* pndown is a primary expression, not a dotted property reference. */
3989 if (!emitTree(pndown))
3990 return false;
3991
3992 do {
3993 /* Walk back up the list, emitting annotated name ops. */
3994 if (!emitAtomOp(pndot, JSOP_GETPROP))
3995 return false;
3996
3997 /* Reverse the pn_expr link again. */
3998 pnup = pndot->pn_exprpn_u.name.expr;
3999 pndot->pn_exprpn_u.name.expr = pndown;
4000 pndown = pndot;
4001 } while ((pndot = pnup) != nullptr);
4002 return true;
4003 }
4004
4005 // The non-optimized case.
4006 return emitTree(pn2);
4007}
4008
4009bool
4010BytecodeEmitter::emitSuperPropLHS(ParseNode* superBase, bool isCall)
4011{
4012 if (!emitGetThisForSuperBase(superBase))
4013 return false;
4014 if (isCall && !emit1(JSOP_DUP))
4015 return false;
4016 if (!emit1(JSOP_SUPERBASE))
4017 return false;
4018 return true;
4019}
4020
4021bool
4022BytecodeEmitter::emitPropOp(ParseNode* pn, JSOp op)
4023{
4024 MOZ_ASSERT(pn->isArity(PN_NAME))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_NAME))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_NAME)))), 0
))) { MOZ_ReportAssertionFailure("pn->isArity(PN_NAME)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4024); do { } while (false); do { *((volatile int*) __null)
= 4024; ::abort(); } while (false); } } while (false)
;
4025
4026 if (!emitPropLHS(pn))
4027 return false;
4028
4029 if (op == JSOP_CALLPROP && !emit1(JSOP_DUP))
4030 return false;
4031
4032 if (!emitAtomOp(pn, op))
4033 return false;
4034
4035 if (op == JSOP_CALLPROP && !emit1(JSOP_SWAP))
4036 return false;
4037
4038 return true;
4039}
4040
4041bool
4042BytecodeEmitter::emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall)
4043{
4044 ParseNode* base = &pn->as<PropertyAccess>().expression();
4045 if (!emitSuperPropLHS(base, isCall))
4046 return false;
4047
4048 if (!emitAtomOp(pn, op))
4049 return false;
4050
4051 if (isCall && !emit1(JSOP_SWAP))
4052 return false;
4053
4054 return true;
4055}
4056
4057bool
4058BytecodeEmitter::emitPropIncDec(ParseNode* pn)
4059{
4060 MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Dot))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.unary.kid->isKind(ParseNodeKind::Dot)
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pn->pn_u.unary.kid->isKind(ParseNodeKind::Dot)
))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.unary.kid->isKind(ParseNodeKind::Dot)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4060); do { } while (false); do { *((volatile int*) __null)
= 4060; ::abort(); } while (false); } } while (false)
;
4061
4062 bool post;
4063 bool isSuper = pn->pn_kidpn_u.unary.kid->as<PropertyAccess>().isSuper();
4064 JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4065
4066 if (isSuper) {
4067 ParseNode* base = &pn->pn_kidpn_u.unary.kid->as<PropertyAccess>().expression();
4068 if (!emitSuperPropLHS(base)) // THIS OBJ
4069 return false;
4070 if (!emit1(JSOP_DUP2)) // THIS OBJ THIS OBJ
4071 return false;
4072 } else {
4073 if (!emitPropLHS(pn->pn_kidpn_u.unary.kid)) // OBJ
4074 return false;
4075 if (!emit1(JSOP_DUP)) // OBJ OBJ
4076 return false;
4077 }
4078 if (!emitAtomOp(pn->pn_kidpn_u.unary.kid, isSuper? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
4079 return false;
4080 if (!emit1(JSOP_POS)) // OBJ N
4081 return false;
4082 if (post && !emit1(JSOP_DUP)) // OBJ N? N
4083 return false;
4084 if (!emit1(JSOP_ONE)) // OBJ N? N 1
4085 return false;
4086 if (!emit1(binop)) // OBJ N? N+1
4087 return false;
4088
4089 if (post) {
4090 if (!emit2(JSOP_PICK, 2 + isSuper)) // N? N+1 OBJ
4091 return false;
4092 if (!emit1(JSOP_SWAP)) // N? OBJ N+1
4093 return false;
4094 if (isSuper) {
4095 if (!emit2(JSOP_PICK, 3)) // N THIS N+1 OBJ
4096 return false;
4097 if (!emit1(JSOP_SWAP)) // N THIS OBJ N+1
4098 return false;
4099 }
4100 }
4101
4102 JSOp setOp = isSuper ? sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
4103 : sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
4104 if (!emitAtomOp(pn->pn_kidpn_u.unary.kid, setOp)) // N? N+1
4105 return false;
4106 if (post && !emit1(JSOP_POP)) // RESULT
4107 return false;
4108
4109 return true;
4110}
4111
4112bool
4113BytecodeEmitter::emitGetNameAtLocationForCompoundAssignment(JSAtom* name, const NameLocation& loc)
4114{
4115 if (loc.kind() == NameLocation::Kind::Dynamic) {
4116 // For dynamic accesses we need to emit GETBOUNDNAME instead of
4117 // GETNAME for correctness: looking up @@unscopables on the
4118 // environment chain (due to 'with' environments) must only happen
4119 // once.
4120 //
4121 // GETBOUNDNAME uses the environment already pushed on the stack from
4122 // the earlier BINDNAME.
4123 if (!emit1(JSOP_DUP)) // ENV ENV
4124 return false;
4125 if (!emitAtomOp(name, JSOP_GETBOUNDNAME)) // ENV V
4126 return false;
4127 } else {
4128 if (!emitGetNameAtLocation(name, loc)) // ENV? V
4129 return false;
4130 }
4131
4132 return true;
4133}
4134
4135bool
4136BytecodeEmitter::emitNameIncDec(ParseNode* pn)
4137{
4138 MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Name))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.unary.kid->isKind(ParseNodeKind::Name
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pn->pn_u.unary.kid->isKind(ParseNodeKind::Name
)))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.unary.kid->isKind(ParseNodeKind::Name)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4138); do { } while (false); do { *((volatile int*) __null)
= 4138; ::abort(); } while (false); } } while (false)
;
4139
4140 bool post;
4141 JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4142
4143 auto emitRhs = [pn, post, binop](BytecodeEmitter* bce, const NameLocation& loc,
4144 bool emittedBindOp)
4145 {
4146 JSAtom* name = pn->pn_kidpn_u.unary.kid->name();
4147 if (!bce->emitGetNameAtLocationForCompoundAssignment(name, loc)) // ENV? V
4148 return false;
4149 if (!bce->emit1(JSOP_POS)) // ENV? N
4150 return false;
4151 if (post && !bce->emit1(JSOP_DUP)) // ENV? N? N
4152 return false;
4153 if (!bce->emit1(JSOP_ONE)) // ENV? N? N 1
4154 return false;
4155 if (!bce->emit1(binop)) // ENV? N? N+1
4156 return false;
4157
4158 if (post && emittedBindOp) {
4159 if (!bce->emit2(JSOP_PICK, 2)) // N? N+1 ENV?
4160 return false;
4161 if (!bce->emit1(JSOP_SWAP)) // N? ENV? N+1
4162 return false;
4163 }
4164
4165 return true;
4166 };
4167
4168 if (!emitSetName(pn->pn_kidpn_u.unary.kid, emitRhs))
4169 return false;
4170
4171 if (post && !emit1(JSOP_POP))
4172 return false;
4173
4174 return true;
4175}
4176
4177bool
4178BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts)
4179{
4180 MOZ_ASSERT(pn->isArity(PN_BINARY))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isArity(PN_BINARY))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isArity(PN_BINARY))))
, 0))) { MOZ_ReportAssertionFailure("pn->isArity(PN_BINARY)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4180); do { } while (false); do { *((volatile int*) __null)
= 4180; ::abort(); } while (false); } } while (false)
;
4181
4182 if (!emitTree(pn->pn_leftpn_u.binary.left))
4183 return false;
4184
4185 if (opts == EmitElemOption::IncDec) {
4186 if (!emit1(JSOP_CHECKOBJCOERCIBLE))
4187 return false;
4188 } else if (opts == EmitElemOption::Call) {
4189 if (!emit1(JSOP_DUP))
4190 return false;
4191 }
4192
4193 if (!emitTree(pn->pn_rightpn_u.binary.right))
4194 return false;
4195
4196 if (opts == EmitElemOption::Set) {
4197 if (!emit2(JSOP_PICK, 2))
4198 return false;
4199 } else if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
4200 if (!emit1(JSOP_TOID))
4201 return false;
4202 }
4203 return true;
4204}
4205
4206bool
4207BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
4208{
4209 MOZ_ASSERT(pn->isKind(ParseNodeKind::Elem) && pn->as<PropertyByValue>().isSuper())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isKind(ParseNodeKind::Elem) && pn->
as<PropertyByValue>().isSuper())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pn->isKind(ParseNodeKind::
Elem) && pn->as<PropertyByValue>().isSuper()
))), 0))) { MOZ_ReportAssertionFailure("pn->isKind(ParseNodeKind::Elem) && pn->as<PropertyByValue>().isSuper()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4209); do { } while (false); do { *((volatile int*) __null)
= 4209; ::abort(); } while (false); } } while (false)
;
4210
4211 // The ordering here is somewhat screwy. We need to evaluate the propval
4212 // first, by spec. Do a little dance to not emit more than one JSOP_THIS.
4213 // Since JSOP_THIS might throw in derived class constructors, we cannot
4214 // just push it earlier as the receiver. We have to swap it down instead.
4215
4216 if (!emitTree(pn->pn_rightpn_u.binary.right))
4217 return false;
4218
4219 // We need to convert the key to an object id first, so that we do not do
4220 // it inside both the GETELEM and the SETELEM.
4221 if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
4222 if (!emit1(JSOP_TOID))
4223 return false;
4224 }
4225
4226 if (!emitGetThisForSuperBase(pn->pn_leftpn_u.binary.left))
4227 return false;
4228
4229 if (opts == EmitElemOption::Call) {
4230 if (!emit1(JSOP_SWAP))
4231 return false;
4232
4233 // We need another |this| on top, also
4234 if (!emitDupAt(1))
4235 return false;
4236 }
4237
4238 if (!emit1(JSOP_SUPERBASE))
4239 return false;
4240
4241 if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 3))
4242 return false;
4243
4244 return true;
4245}
4246
4247bool
4248BytecodeEmitter::emitElemOpBase(JSOp op)
4249{
4250 if (!emit1(op))
4251 return false;
4252
4253 checkTypeSet(op);
4254 return true;
4255}
4256
4257bool
4258BytecodeEmitter::emitElemOp(ParseNode* pn, JSOp op)
4259{
4260 EmitElemOption opts = EmitElemOption::Get;
4261 if (op == JSOP_CALLELEM)
4262 opts = EmitElemOption::Call;
4263 else if (op == JSOP_SETELEM || op == JSOP_STRICTSETELEM)
4264 opts = EmitElemOption::Set;
4265
4266 return emitElemOperands(pn, opts) && emitElemOpBase(op);
4267}
4268
4269bool
4270BytecodeEmitter::emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall)
4271{
4272 EmitElemOption opts = EmitElemOption::Get;
4273 if (isCall)
4274 opts = EmitElemOption::Call;
4275 else if (op == JSOP_SETELEM_SUPER || op == JSOP_STRICTSETELEM_SUPER)
4276 opts = EmitElemOption::Set;
4277
4278 if (!emitSuperElemOperands(pn, opts))
4279 return false;
4280 if (!emitElemOpBase(op))
4281 return false;
4282
4283 if (isCall && !emit1(JSOP_SWAP))
4284 return false;
4285
4286 return true;
4287}
4288
4289bool
4290BytecodeEmitter::emitElemIncDec(ParseNode* pn)
4291{
4292 MOZ_ASSERT(pn->pn_kid->isKind(ParseNodeKind::Elem))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.unary.kid->isKind(ParseNodeKind::Elem
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pn->pn_u.unary.kid->isKind(ParseNodeKind::Elem
)))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.unary.kid->isKind(ParseNodeKind::Elem)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4292); do { } while (false); do { *((volatile int*) __null)
= 4292; ::abort(); } while (false); } } while (false)
;
4293
4294 bool isSuper = pn->pn_kidpn_u.unary.kid->as<PropertyByValue>().isSuper();
4295
4296 // We need to convert the key to an object id first, so that we do not do
4297 // it inside both the GETELEM and the SETELEM. This is done by
4298 // emit(Super)ElemOperands.
4299 if (isSuper) {
4300 if (!emitSuperElemOperands(pn->pn_kidpn_u.unary.kid, EmitElemOption::IncDec))
4301 return false;
4302 } else {
4303 if (!emitElemOperands(pn->pn_kidpn_u.unary.kid, EmitElemOption::IncDec))
4304 return false;
4305 }
4306
4307 bool post;
4308 JSOp binop = GetIncDecInfo(pn->getKind(), &post);
4309
4310 JSOp getOp;
4311 if (isSuper) {
4312 // There's no such thing as JSOP_DUP3, so we have to be creative.
4313 // Note that pushing things again is no fewer JSOps.
4314 if (!emitDupAt(2)) // KEY THIS OBJ KEY
4315 return false;
4316 if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS
4317 return false;
4318 if (!emitDupAt(2)) // KEY THIS OBJ KEY THIS OBJ
4319 return false;
4320 getOp = JSOP_GETELEM_SUPER;
4321 } else {
4322 // OBJ KEY
4323 if (!emit1(JSOP_DUP2)) // OBJ KEY OBJ KEY
4324 return false;
4325 getOp = JSOP_GETELEM;
4326 }
4327 if (!emitElemOpBase(getOp)) // OBJ KEY V
4328 return false;
4329 if (!emit1(JSOP_POS)) // OBJ KEY N
4330 return false;
4331 if (post && !emit1(JSOP_DUP)) // OBJ KEY N? N
4332 return false;
4333 if (!emit1(JSOP_ONE)) // OBJ KEY N? N 1
4334 return false;
4335 if (!emit1(binop)) // OBJ KEY N? N+1
4336 return false;
4337
4338 if (post) {
4339 if (isSuper) {
4340 // We have one more value to rotate around, because of |this|
4341 // on the stack
4342 if (!emit2(JSOP_PICK, 4))
4343 return false;
4344 }
4345 if (!emit2(JSOP_PICK, 3 + isSuper)) // KEY N N+1 OBJ
4346 return false;
4347 if (!emit2(JSOP_PICK, 3 + isSuper)) // N N+1 OBJ KEY
4348 return false;
4349 if (!emit2(JSOP_PICK, 2 + isSuper)) // N OBJ KEY N+1
4350 return false;
4351 }
4352
4353 JSOp setOp = isSuper ? (sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
4354 : (sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM);
4355 if (!emitElemOpBase(setOp)) // N? N+1
4356 return false;
4357 if (post && !emit1(JSOP_POP)) // RESULT
4358 return false;
4359
4360 return true;
4361}
4362
4363bool
4364BytecodeEmitter::emitCallIncDec(ParseNode* incDec)
4365{
4366 MOZ_ASSERT(incDec->isKind(ParseNodeKind::PreIncrement) ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(incDec->isKind(ParseNodeKind::PreIncrement) || incDec
->isKind(ParseNodeKind::PostIncrement) || incDec->isKind
(ParseNodeKind::PreDecrement) || incDec->isKind(ParseNodeKind
::PostDecrement))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(incDec->isKind(ParseNodeKind
::PreIncrement) || incDec->isKind(ParseNodeKind::PostIncrement
) || incDec->isKind(ParseNodeKind::PreDecrement) || incDec
->isKind(ParseNodeKind::PostDecrement)))), 0))) { MOZ_ReportAssertionFailure
("incDec->isKind(ParseNodeKind::PreIncrement) || incDec->isKind(ParseNodeKind::PostIncrement) || incDec->isKind(ParseNodeKind::PreDecrement) || incDec->isKind(ParseNodeKind::PostDecrement)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4369); do { } while (false); do { *((volatile int*) __null)
= 4369; ::abort(); } while (false); } } while (false)
4367 incDec->isKind(ParseNodeKind::PostIncrement) ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(incDec->isKind(ParseNodeKind::PreIncrement) || incDec
->isKind(ParseNodeKind::PostIncrement) || incDec->isKind
(ParseNodeKind::PreDecrement) || incDec->isKind(ParseNodeKind
::PostDecrement))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(incDec->isKind(ParseNodeKind
::PreIncrement) || incDec->isKind(ParseNodeKind::PostIncrement
) || incDec->isKind(ParseNodeKind::PreDecrement) || incDec
->isKind(ParseNodeKind::PostDecrement)))), 0))) { MOZ_ReportAssertionFailure
("incDec->isKind(ParseNodeKind::PreIncrement) || incDec->isKind(ParseNodeKind::PostIncrement) || incDec->isKind(ParseNodeKind::PreDecrement) || incDec->isKind(ParseNodeKind::PostDecrement)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4369); do { } while (false); do { *((volatile int*) __null)
= 4369; ::abort(); } while (false); } } while (false)
4368 incDec->isKind(ParseNodeKind::PreDecrement) ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(incDec->isKind(ParseNodeKind::PreIncrement) || incDec
->isKind(ParseNodeKind::PostIncrement) || incDec->isKind
(ParseNodeKind::PreDecrement) || incDec->isKind(ParseNodeKind
::PostDecrement))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(incDec->isKind(ParseNodeKind
::PreIncrement) || incDec->isKind(ParseNodeKind::PostIncrement
) || incDec->isKind(ParseNodeKind::PreDecrement) || incDec
->isKind(ParseNodeKind::PostDecrement)))), 0))) { MOZ_ReportAssertionFailure
("incDec->isKind(ParseNodeKind::PreIncrement) || incDec->isKind(ParseNodeKind::PostIncrement) || incDec->isKind(ParseNodeKind::PreDecrement) || incDec->isKind(ParseNodeKind::PostDecrement)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4369); do { } while (false); do { *((volatile int*) __null)
= 4369; ::abort(); } while (false); } } while (false)
4369 incDec->isKind(ParseNodeKind::PostDecrement))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(incDec->isKind(ParseNodeKind::PreIncrement) || incDec
->isKind(ParseNodeKind::PostIncrement) || incDec->isKind
(ParseNodeKind::PreDecrement) || incDec->isKind(ParseNodeKind
::PostDecrement))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(incDec->isKind(ParseNodeKind
::PreIncrement) || incDec->isKind(ParseNodeKind::PostIncrement
) || incDec->isKind(ParseNodeKind::PreDecrement) || incDec
->isKind(ParseNodeKind::PostDecrement)))), 0))) { MOZ_ReportAssertionFailure
("incDec->isKind(ParseNodeKind::PreIncrement) || incDec->isKind(ParseNodeKind::PostIncrement) || incDec->isKind(ParseNodeKind::PreDecrement) || incDec->isKind(ParseNodeKind::PostDecrement)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4369); do { } while (false); do { *((volatile int*) __null)
= 4369; ::abort(); } while (false); } } while (false)
;
4370
4371 MOZ_ASSERT(incDec->pn_kid->isKind(ParseNodeKind::Call))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(incDec->pn_u.unary.kid->isKind(ParseNodeKind::
Call))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(incDec->pn_u.unary.kid->isKind(ParseNodeKind::
Call)))), 0))) { MOZ_ReportAssertionFailure("incDec->pn_u.unary.kid->isKind(ParseNodeKind::Call)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4371); do { } while (false); do { *((volatile int*) __null)
= 4371; ::abort(); } while (false); } } while (false)
;
4372
4373 ParseNode* call = incDec->pn_kidpn_u.unary.kid;
4374 if (!emitTree(call)) // CALLRESULT
4375 return false;
4376 if (!emit1(JSOP_POS)) // N
4377 return false;
4378
4379 // The increment/decrement has no side effects, so proceed to throw for
4380 // invalid assignment target.
4381 return emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS);
4382}
4383
4384bool
4385BytecodeEmitter::emitNumberOp(double dval)
4386{
4387 int32_t ival;
4388 if (NumberIsInt32(dval, &ival)) {
4389 if (ival == 0)
4390 return emit1(JSOP_ZERO);
4391 if (ival == 1)
4392 return emit1(JSOP_ONE);
4393 if ((int)(int8_t)ival == ival)
4394 return emit2(JSOP_INT8, uint8_t(int8_t(ival)));
4395
4396 uint32_t u = uint32_t(ival);
4397 if (u < JS_BIT(16)((uint32_t)1 << (16))) {
4398 if (!emitUint16Operand(JSOP_UINT16, u))
4399 return false;
4400 } else if (u < JS_BIT(24)((uint32_t)1 << (24))) {
4401 ptrdiff_t off;
4402 if (!emitN(JSOP_UINT24, 3, &off))
4403 return false;
4404 SET_UINT24(code(off), u);
4405 } else {
4406 ptrdiff_t off;
4407 if (!emitN(JSOP_INT32, 4, &off))
4408 return false;
4409 SET_INT32(code(off), ival);
4410 }
4411 return true;
4412 }
4413
4414 if (!constList.append(DoubleValue(dval)))
4415 return false;
4416
4417 return emitIndex32(JSOP_DOUBLE, constList.length() - 1);
4418}
4419
4420/*
4421 * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047.
4422 * LLVM is deciding to inline this function which uses a lot of stack space
4423 * into emitTree which is recursive and uses relatively little stack space.
4424 */
4425MOZ_NEVER_INLINE__attribute__((noinline)) bool
4426BytecodeEmitter::emitSwitch(ParseNode* pn)
4427{
4428 ParseNode* cases = pn->pn_rightpn_u.binary.right;
4429 MOZ_ASSERT(cases->isKind(ParseNodeKind::LexicalScope) ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(cases->isKind(ParseNodeKind::LexicalScope) || cases
->isKind(ParseNodeKind::StatementList))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cases->isKind(ParseNodeKind
::LexicalScope) || cases->isKind(ParseNodeKind::StatementList
)))), 0))) { MOZ_ReportAssertionFailure("cases->isKind(ParseNodeKind::LexicalScope) || cases->isKind(ParseNodeKind::StatementList)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4430); do { } while (false); do { *((volatile int*) __null)
= 4430; ::abort(); } while (false); } } while (false)
4430 cases->isKind(ParseNodeKind::StatementList))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(cases->isKind(ParseNodeKind::LexicalScope) || cases
->isKind(ParseNodeKind::StatementList))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cases->isKind(ParseNodeKind
::LexicalScope) || cases->isKind(ParseNodeKind::StatementList
)))), 0))) { MOZ_ReportAssertionFailure("cases->isKind(ParseNodeKind::LexicalScope) || cases->isKind(ParseNodeKind::StatementList)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4430); do { } while (false); do { *((volatile int*) __null)
= 4430; ::abort(); } while (false); } } while (false)
;
4431
4432 // Emit code for the discriminant.
4433 if (!emitTree(pn->pn_leftpn_u.binary.left))
4434 return false;
4435
4436 // Enter the scope before pushing the switch BreakableControl since all
4437 // breaks are under this scope.
4438 Maybe<TDZCheckCache> tdzCache;
4439 Maybe<EmitterScope> emitterScope;
4440 if (cases->isKind(ParseNodeKind::LexicalScope)) {
4441 if (!cases->isEmptyScope()) {
4442 tdzCache.emplace(this);
4443 emitterScope.emplace(this);
4444 if (!emitterScope->enterLexical(this, ScopeKind::Lexical, cases->scopeBindings()))
4445 return false;
4446 }
4447
4448 // Advance |cases| to refer to the switch case list.
4449 cases = cases->scopeBody();
4450
4451 // A switch statement may contain hoisted functions inside its
4452 // cases. The PNX_FUNCDEFS flag is propagated from the STATEMENTLIST
4453 // bodies of the cases to the case list.
4454 if (cases->pn_xflagspn_u.list.xflags & PNX_FUNCDEFS0x01) {
4455 MOZ_ASSERT(emitterScope)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(emitterScope)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(emitterScope))), 0))) { MOZ_ReportAssertionFailure
("emitterScope", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4455); do { } while (false); do { *((volatile int*) __null)
= 4455; ::abort(); } while (false); } } while (false)
;
4456 for (ParseNode* caseNode = cases->pn_headpn_u.list.head; caseNode; caseNode = caseNode->pn_next) {
4457 if (caseNode->pn_rightpn_u.binary.right->pn_xflagspn_u.list.xflags & PNX_FUNCDEFS0x01) {
4458 if (!emitHoistedFunctionsInList(caseNode->pn_rightpn_u.binary.right))
4459 return false;
4460 }
4461 }
4462 }
4463 }
4464
4465 // After entering the scope, push the switch control.
4466 BreakableControl controlInfo(this, StatementKind::Switch);
4467
4468 ptrdiff_t top = offset();
4469
4470 // Switch bytecodes run from here till end of final case.
4471 uint32_t caseCount = cases->pn_countpn_u.list.count;
4472 if (caseCount > JS_BIT(16)((uint32_t)1 << (16))) {
4473 parser.reportError(JSMSG_TOO_MANY_CASES);
4474 return false;
4475 }
4476
4477 // Try for most optimal, fall back if not dense ints.
4478 JSOp switchOp = JSOP_TABLESWITCH;
4479 uint32_t tableLength = 0;
4480 int32_t low, high;
4481 bool hasDefault = false;
4482 CaseClause* firstCase = cases->pn_headpn_u.list.head ? &cases->pn_headpn_u.list.head->as<CaseClause>() : nullptr;
4483 if (caseCount == 0 ||
4484 (caseCount == 1 && (hasDefault = firstCase->isDefault())))
4485 {
4486 caseCount = 0;
Value stored to 'caseCount' is never read
4487 low = 0;
4488 high = -1;
4489 } else {
4490 Vector<size_t, 128, SystemAllocPolicy> intmap;
4491 int32_t intmapBitLength = 0;
4492
4493 low = JSVAL_INT_MAX((int32_t)0x7fffffff);
4494 high = JSVAL_INT_MIN((int32_t)0x80000000);
4495
4496 for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4497 if (caseNode->isDefault()) {
4498 hasDefault = true;
4499 caseCount--; // one of the "cases" was the default
4500 continue;
4501 }
4502
4503 if (switchOp == JSOP_CONDSWITCH)
4504 continue;
4505
4506 MOZ_ASSERT(switchOp == JSOP_TABLESWITCH)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(switchOp == JSOP_TABLESWITCH)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(switchOp == JSOP_TABLESWITCH
))), 0))) { MOZ_ReportAssertionFailure("switchOp == JSOP_TABLESWITCH"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4506); do { } while (false); do { *((volatile int*) __null)
= 4506; ::abort(); } while (false); } } while (false)
;
4507
4508 ParseNode* caseValue = caseNode->caseExpression();
4509
4510 if (caseValue->getKind() != ParseNodeKind::Number) {
4511 switchOp = JSOP_CONDSWITCH;
4512 continue;
4513 }
4514
4515 int32_t i;
4516 if (!NumberIsInt32(caseValue->pn_dvalpn_u.number.value, &i)) {
4517 switchOp = JSOP_CONDSWITCH;
4518 continue;
4519 }
4520
4521 if (unsigned(i + int(JS_BIT(15)((uint32_t)1 << (15)))) >= unsigned(JS_BIT(16)((uint32_t)1 << (16)))) {
4522 switchOp = JSOP_CONDSWITCH;
4523 continue;
4524 }
4525 if (i < low)
4526 low = i;
4527 if (i > high)
4528 high = i;
4529
4530 // Check for duplicates, which require a JSOP_CONDSWITCH.
4531 // We bias i by 65536 if it's negative, and hope that's a rare
4532 // case (because it requires a malloc'd bitmap).
4533 if (i < 0)
4534 i += JS_BIT(16)((uint32_t)1 << (16));
4535 if (i >= intmapBitLength) {
4536 size_t newLength = NumWordsForBitArrayOfLength(i + 1);
4537 if (!intmap.resize(newLength))
4538 return false;
4539 intmapBitLength = newLength * BitArrayElementBits;
4540 }
4541 if (IsBitArrayElementSet(intmap.begin(), intmap.length(), i)) {
4542 switchOp = JSOP_CONDSWITCH;
4543 continue;
4544 }
4545 SetBitArrayElement(intmap.begin(), intmap.length(), i);
4546 }
4547
4548 // Compute table length and select condswitch instead if overlarge or
4549 // more than half-sparse.
4550 if (switchOp == JSOP_TABLESWITCH) {
4551 tableLength = uint32_t(high - low + 1);
4552 if (tableLength >= JS_BIT(16)((uint32_t)1 << (16)) || tableLength > 2 * caseCount)
4553 switchOp = JSOP_CONDSWITCH;
4554 }
4555 }
4556
4557 // The note has one or two offsets: first tells total switch code length;
4558 // second (if condswitch) tells offset to first JSOP_CASE.
4559 unsigned noteIndex;
4560 size_t switchSize;
4561 if (switchOp == JSOP_CONDSWITCH) {
4562 // 0 bytes of immediate for unoptimized switch.
4563 switchSize = 0;
4564 if (!newSrcNote3(SRC_CONDSWITCH, 0, 0, &noteIndex))
4565 return false;
4566 } else {
4567 MOZ_ASSERT(switchOp == JSOP_TABLESWITCH)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(switchOp == JSOP_TABLESWITCH)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(switchOp == JSOP_TABLESWITCH
))), 0))) { MOZ_ReportAssertionFailure("switchOp == JSOP_TABLESWITCH"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4567); do { } while (false); do { *((volatile int*) __null)
= 4567; ::abort(); } while (false); } } while (false)
;
4568
4569 // 3 offsets (len, low, high) before the table, 1 per entry.
4570 switchSize = size_t(JUMP_OFFSET_LEN * (3 + tableLength));
4571 if (!newSrcNote2(SRC_TABLESWITCH, 0, &noteIndex))
4572 return false;
4573 }
4574
4575 // Emit switchOp followed by switchSize bytes of jump or lookup table.
4576 MOZ_ASSERT(top == offset())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(top == offset())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(top == offset()))), 0))) { MOZ_ReportAssertionFailure
("top == offset()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4576); do { } while (false); do { *((volatile int*) __null)
= 4576; ::abort(); } while (false); } } while (false)
;
4577 if (!emitN(switchOp, switchSize))
4578 return false;
4579
4580 Vector<CaseClause*, 32, SystemAllocPolicy> table;
4581
4582 JumpList condSwitchDefaultOff;
4583 if (switchOp == JSOP_CONDSWITCH) {
4584 unsigned caseNoteIndex;
4585 bool beforeCases = true;
4586 ptrdiff_t lastCaseOffset = -1;
4587
4588 // The case conditions need their own TDZ cache since they might not
4589 // all execute.
4590 TDZCheckCache tdzCache(this);
4591
4592 // Emit code for evaluating cases and jumping to case statements.
4593 for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4594 ParseNode* caseValue = caseNode->caseExpression();
4595
4596 // If the expression is a literal, suppress line number emission so
4597 // that debugging works more naturally.
4598 if (caseValue) {
4599 if (!emitTree(caseValue, ValueUsage::WantValue,
4600 caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
4601 {
4602 return false;
4603 }
4604 }
4605
4606 if (!beforeCases) {
4607 // prevCase is the previous JSOP_CASE's bytecode offset.
4608 if (!setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
4609 return false;
4610 }
4611 if (!caseValue) {
4612 // This is the default clause.
4613 continue;
4614 }
4615
4616 if (!newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex))
4617 return false;
4618
4619 // The case clauses are produced before any of the case body. The
4620 // JumpList is saved on the parsed tree, then later restored and
4621 // patched when generating the cases body.
4622 JumpList caseJump;
4623 if (!emitJump(JSOP_CASE, &caseJump))
4624 return false;
4625 caseNode->setOffset(caseJump.offset);
4626 lastCaseOffset = caseJump.offset;
4627
4628 if (beforeCases) {
4629 // Switch note's second offset is to first JSOP_CASE.
4630 unsigned noteCount = notes().length();
4631 if (!setSrcNoteOffset(noteIndex, 1, lastCaseOffset - top))
4632 return false;
4633 unsigned noteCountDelta = notes().length() - noteCount;
4634 if (noteCountDelta != 0)
4635 caseNoteIndex += noteCountDelta;
4636 beforeCases = false;
4637 }
4638 }
4639
4640 // If we didn't have an explicit default (which could fall in between
4641 // cases, preventing us from fusing this setSrcNoteOffset with the call
4642 // in the loop above), link the last case to the implicit default for
4643 // the benefit of IonBuilder.
4644 if (!hasDefault &&
4645 !beforeCases &&
4646 !setSrcNoteOffset(caseNoteIndex, 0, offset() - lastCaseOffset))
4647 {
4648 return false;
4649 }
4650
4651 // Emit default even if no explicit default statement.
4652 if (!emitJump(JSOP_DEFAULT, &condSwitchDefaultOff))
4653 return false;
4654 } else {
4655 MOZ_ASSERT(switchOp == JSOP_TABLESWITCH)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(switchOp == JSOP_TABLESWITCH)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(switchOp == JSOP_TABLESWITCH
))), 0))) { MOZ_ReportAssertionFailure("switchOp == JSOP_TABLESWITCH"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4655); do { } while (false); do { *((volatile int*) __null)
= 4655; ::abort(); } while (false); } } while (false)
;
4656
4657 // skip default offset.
4658 jsbytecode* pc = code(top + JUMP_OFFSET_LEN);
4659
4660 // Fill in switch bounds, which we know fit in 16-bit offsets.
4661 SET_JUMP_OFFSET(pc, low);
4662 pc += JUMP_OFFSET_LEN;
4663 SET_JUMP_OFFSET(pc, high);
4664 pc += JUMP_OFFSET_LEN;
4665
4666 if (tableLength != 0) {
4667 if (!table.growBy(tableLength))
4668 return false;
4669
4670 for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4671 if (ParseNode* caseValue = caseNode->caseExpression()) {
4672 MOZ_ASSERT(caseValue->isKind(ParseNodeKind::Number))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(caseValue->isKind(ParseNodeKind::Number))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(caseValue->isKind(ParseNodeKind::Number)))), 0))) { MOZ_ReportAssertionFailure
("caseValue->isKind(ParseNodeKind::Number)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4672); do { } while (false); do { *((volatile int*) __null)
= 4672; ::abort(); } while (false); } } while (false)
;
4673
4674 int32_t i = int32_t(caseValue->pn_dvalpn_u.number.value);
4675 MOZ_ASSERT(double(i) == caseValue->pn_dval)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(double(i) == caseValue->pn_u.number.value)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(double(i) == caseValue->pn_u.number.value))), 0))) { MOZ_ReportAssertionFailure
("double(i) == caseValue->pn_u.number.value", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4675); do { } while (false); do { *((volatile int*) __null)
= 4675; ::abort(); } while (false); } } while (false)
;
4676
4677 i -= low;
4678 MOZ_ASSERT(uint32_t(i) < tableLength)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(uint32_t(i) < tableLength)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(uint32_t(i) < tableLength
))), 0))) { MOZ_ReportAssertionFailure("uint32_t(i) < tableLength"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4678); do { } while (false); do { *((volatile int*) __null)
= 4678; ::abort(); } while (false); } } while (false)
;
4679 MOZ_ASSERT(!table[i])do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!table[i])>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!table[i]))), 0))) { MOZ_ReportAssertionFailure
("!table[i]", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4679); do { } while (false); do { *((volatile int*) __null)
= 4679; ::abort(); } while (false); } } while (false)
;
4680 table[i] = caseNode;
4681 }
4682 }
4683 }
4684 }
4685
4686 JumpTarget defaultOffset{ -1 };
4687
4688 // Emit code for each case's statements.
4689 for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
4690 if (switchOp == JSOP_CONDSWITCH && !caseNode->isDefault()) {
4691 // The case offset got saved in the caseNode structure after
4692 // emitting the JSOP_CASE jump instruction above.
4693 JumpList caseCond;
4694 caseCond.offset = caseNode->offset();
4695 if (!emitJumpTargetAndPatch(caseCond))
4696 return false;
4697 }
4698
4699 JumpTarget here;
4700 if (!emitJumpTarget(&here))
4701 return false;
4702 if (caseNode->isDefault())
4703 defaultOffset = here;
4704
4705 // If this is emitted as a TABLESWITCH, we'll need to know this case's
4706 // offset later when emitting the table. Store it in the node's
4707 // pn_offset (giving the field a different meaning vs. how we used it
4708 // on the immediately preceding line of code).
4709 caseNode->setOffset(here.offset);
4710
4711 TDZCheckCache tdzCache(this);
4712
4713 if (!emitTree(caseNode->statementList()))
4714 return false;
4715 }
4716
4717 if (!hasDefault) {
4718 // If no default case, offset for default is to end of switch.
4719 if (!emitJumpTarget(&defaultOffset))
4720 return false;
4721 }
4722 MOZ_ASSERT(defaultOffset.offset != -1)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(defaultOffset.offset != -1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(defaultOffset.offset != -1))
), 0))) { MOZ_ReportAssertionFailure("defaultOffset.offset != -1"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4722); do { } while (false); do { *((volatile int*) __null)
= 4722; ::abort(); } while (false); } } while (false)
;
4723
4724 // Set the default offset (to end of switch if no default).
4725 jsbytecode* pc;
4726 if (switchOp == JSOP_CONDSWITCH) {
4727 pc = nullptr;
4728 patchJumpsToTarget(condSwitchDefaultOff, defaultOffset);
4729 } else {
4730 MOZ_ASSERT(switchOp == JSOP_TABLESWITCH)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(switchOp == JSOP_TABLESWITCH)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(switchOp == JSOP_TABLESWITCH
))), 0))) { MOZ_ReportAssertionFailure("switchOp == JSOP_TABLESWITCH"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4730); do { } while (false); do { *((volatile int*) __null)
= 4730; ::abort(); } while (false); } } while (false)
;
4731 pc = code(top);
4732 SET_JUMP_OFFSET(pc, defaultOffset.offset - top);
4733 pc += JUMP_OFFSET_LEN;
4734 }
4735
4736 // Set the SRC_SWITCH note's offset operand to tell end of switch.
4737 if (!setSrcNoteOffset(noteIndex, 0, lastNonJumpTargetOffset() - top))
4738 return false;
4739
4740 if (switchOp == JSOP_TABLESWITCH) {
4741 // Skip over the already-initialized switch bounds.
4742 pc += 2 * JUMP_OFFSET_LEN;
4743
4744 // Fill in the jump table, if there is one.
4745 for (uint32_t i = 0; i < tableLength; i++) {
4746 CaseClause* caseNode = table[i];
4747 ptrdiff_t off = caseNode ? caseNode->offset() - top : 0;
4748 SET_JUMP_OFFSET(pc, off);
4749 pc += JUMP_OFFSET_LEN;
4750 }
4751 }
4752
4753 // Patch breaks before leaving the scope, as all breaks are under the
4754 // lexical scope if it exists.
4755 if (!controlInfo.patchBreaks(this))
4756 return false;
4757
4758 if (emitterScope && !emitterScope->leave(this))
4759 return false;
4760
4761 return true;
4762}
4763
4764bool
4765BytecodeEmitter::isRunOnceLambda()
4766{
4767 // The run once lambda flags set by the parser are approximate, and we look
4768 // at properties of the function itself before deciding to emit a function
4769 // as a run once lambda.
4770
4771 if (!(parent && parent->emittingRunOnceLambda) &&
4772 (emitterMode != LazyFunction || !lazyScript->treatAsRunOnce()))
4773 {
4774 return false;
4775 }
4776
4777 FunctionBox* funbox = sc->asFunctionBox();
4778 return !funbox->argumentsHasLocalBinding() &&
4779 !funbox->isGenerator() &&
4780 !funbox->isAsync() &&
4781 !funbox->function()->explicitName();
4782}
4783
4784bool
4785BytecodeEmitter::emitYieldOp(JSOp op)
4786{
4787 if (op == JSOP_FINALYIELDRVAL)
4788 return emit1(JSOP_FINALYIELDRVAL);
4789
4790 MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op ==
JSOP_AWAIT)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(op == JSOP_INITIALYIELD || op == JSOP_YIELD
|| op == JSOP_AWAIT))), 0))) { MOZ_ReportAssertionFailure("op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4790); do { } while (false); do { *((volatile int*) __null)
= 4790; ::abort(); } while (false); } } while (false)
;
4791
4792 ptrdiff_t off;
4793 if (!emitN(op, 3, &off))
4794 return false;
4795
4796 uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
4797 if (yieldAndAwaitIndex >= JS_BIT(24)((uint32_t)1 << (24))) {
4798 reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
4799 return false;
4800 }
4801
4802 if (op == JSOP_AWAIT)
4803 yieldAndAwaitOffsetList.numAwaits++;
4804 else
4805 yieldAndAwaitOffsetList.numYields++;
4806
4807 SET_UINT24(code(off), yieldAndAwaitIndex);
4808
4809 if (!yieldAndAwaitOffsetList.append(offset()))
4810 return false;
4811
4812 return emit1(JSOP_DEBUGAFTERYIELD);
4813}
4814
4815bool
4816BytecodeEmitter::emitSetThis(ParseNode* pn)
4817{
4818 // ParseNodeKind::SetThis is used to update |this| after a super() call
4819 // in a derived class constructor.
4820
4821 MOZ_ASSERT(pn->isKind(ParseNodeKind::SetThis))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->isKind(ParseNodeKind::SetThis))>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(pn->isKind(ParseNodeKind::SetThis)))), 0))) { MOZ_ReportAssertionFailure
("pn->isKind(ParseNodeKind::SetThis)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4821); do { } while (false); do { *((volatile int*) __null)
= 4821; ::abort(); } while (false); } } while (false)
;
4822 MOZ_ASSERT(pn->pn_left->isKind(ParseNodeKind::Name))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pn->pn_u.binary.left->isKind(ParseNodeKind::Name
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(pn->pn_u.binary.left->isKind(ParseNodeKind::Name
)))), 0))) { MOZ_ReportAssertionFailure("pn->pn_u.binary.left->isKind(ParseNodeKind::Name)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4822); do { } while (false); do { *((volatile int*) __null)
= 4822; ::abort(); } while (false); } } while (false)
;
4823
4824 RootedAtom name(cx, pn->pn_leftpn_u.binary.left->name());
4825 auto emitRhs = [&name, pn](BytecodeEmitter* bce, const NameLocation&, bool) {
4826 // Emit the new |this| value.
4827 if (!bce->emitTree(pn->pn_rightpn_u.binary.right))
4828 return false;
4829 // Get the original |this| and throw if we already initialized
4830 // it. Do *not* use the NameLocation argument, as that's the special
4831 // lexical location below to deal with super() semantics.
4832 if (!bce->emitGetName(name))
4833 return false;
4834 if (!bce->emit1(JSOP_CHECKTHISREINIT))
4835 return false;
4836 if (!bce->emit1(JSOP_POP))
4837 return false;
4838 return true;
4839 };
4840
4841 // The 'this' binding is not lexical, but due to super() semantics this
4842 // initialization needs to be treated as a lexical one.
4843 NameLocation loc = lookupName(name);
4844 NameLocation lexicalLoc;
4845 if (loc.kind() == NameLocation::Kind::FrameSlot) {
4846 lexicalLoc = NameLocation::FrameSlot(BindingKind::Let, loc.frameSlot());
4847 } else if (loc.kind() == NameLocation::Kind::EnvironmentCoordinate) {
4848 EnvironmentCoordinate coord = loc.environmentCoordinate();
4849 uint8_t hops = AssertedCast<uint8_t>(coord.hops());
4850 lexicalLoc = NameLocation::EnvironmentCoordinate(BindingKind::Let, hops, coord.slot());
4851 } else {
4852 MOZ_ASSERT(loc.kind() == NameLocation::Kind::Dynamic)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(loc.kind() == NameLocation::Kind::Dynamic)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(loc.kind() == NameLocation::Kind::Dynamic))), 0))) { MOZ_ReportAssertionFailure
("loc.kind() == NameLocation::Kind::Dynamic", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4852); do { } while (false); do { *((volatile int*) __null)
= 4852; ::abort(); } while (false); } } while (false)
;
4853 lexicalLoc = loc;
4854 }
4855
4856 return emitSetOrInitializeNameAtLocation(name, lexicalLoc, emitRhs, true);
4857}
4858
4859bool
4860BytecodeEmitter::emitScript(ParseNode* body)
4861{
4862 AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, tokenStream(), body);
4863
4864 TDZCheckCache tdzCache(this);
4865 EmitterScope emitterScope(this);
4866 if (sc->isGlobalContext()) {
4867 switchToPrologue();
4868 if (!emitterScope.enterGlobal(this, sc->asGlobalContext()))
4869 return false;
4870 switchToMain();
4871 } else if (sc->isEvalContext()) {
4872 switchToPrologue();
4873 if (!emitterScope.enterEval(this, sc->asEvalContext()))
4874 return false;
4875 switchToMain();
4876 } else {
4877 MOZ_ASSERT(sc->isModuleContext())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(sc->isModuleContext())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sc->isModuleContext()))),
0))) { MOZ_ReportAssertionFailure("sc->isModuleContext()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4877); do { } while (false); do { *((volatile int*) __null)
= 4877; ::abort(); } while (false); } } while (false)
;
4878 if (!emitterScope.enterModule(this, sc->asModuleContext()))
4879 return false;
4880 }
4881
4882 setFunctionBodyEndPos(body->pn_pos);
4883
4884 if (sc->isEvalContext() && !sc->strict() &&
4885 body->isKind(ParseNodeKind::LexicalScope) && !body->isEmptyScope())
4886 {
4887 // Sloppy eval scripts may need to emit DEFFUNs in the prologue. If there is
4888 // an immediately enclosed lexical scope, we need to enter the lexical
4889 // scope in the prologue for the DEFFUNs to pick up the right
4890 // environment chain.
4891 EmitterScope lexicalEmitterScope(this);
4892
4893 switchToPrologue();
4894 if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical, body->scopeBindings()))
4895 return false;
4896 switchToMain();
4897
4898 if (!emitLexicalScopeBody(body->scopeBody()))
4899 return false;
4900
4901 if (!lexicalEmitterScope.leave(this))
4902 return false;
4903 } else {
4904 if (!emitTree(body))
4905 return false;
4906 }
4907
4908 if (!updateSourceCoordNotes(body->pn_pos.end))
4909 return false;
4910
4911 if (!emit1(JSOP_RETRVAL))
4912 return false;
4913
4914 if (!emitterScope.leave(this))
4915 return false;
4916
4917 if (!JSScript::fullyInitFromEmitter(cx, script, this))
4918 return false;
4919
4920 // URL and source map information must be set before firing
4921 // Debugger::onNewScript.
4922 if (!maybeSetDisplayURL() || !maybeSetSourceMap())
4923 return false;
4924
4925 tellDebuggerAboutCompiledScript(cx);
4926
4927 return true;
4928}
4929
4930bool
4931BytecodeEmitter::emitFunctionScript(ParseNode* body)
4932{
4933 FunctionBox* funbox = sc->asFunctionBox();
4934 AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, tokenStream(), funbox);
4935
4936 // The ordering of these EmitterScopes is important. The named lambda
4937 // scope needs to enclose the function scope needs to enclose the extra
4938 // var scope.
4939
4940 Maybe<EmitterScope> namedLambdaEmitterScope;
4941 if (funbox->namedLambdaBindings()) {
4942 namedLambdaEmitterScope.emplace(this);
4943 if (!namedLambdaEmitterScope->enterNamedLambda(this, funbox))
4944 return false;
4945 }
4946
4947 /*
4948 * Emit a prologue for run-once scripts which will deoptimize JIT code
4949 * if the script ends up running multiple times via foo.caller related
4950 * shenanigans.
4951 *
4952 * Also mark the script so that initializers created within it may be
4953 * given more precise types.
4954 */
4955 if (isRunOnceLambda()) {
4956 script->setTreatAsRunOnce();
4957 MOZ_ASSERT(!script->hasRunOnce())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(!script->hasRunOnce())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!script->hasRunOnce()))),
0))) { MOZ_ReportAssertionFailure("!script->hasRunOnce()"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 4957); do { } while (false); do { *((volatile int*) __null)
= 4957; ::abort(); } while (false); } } while (false)
;
4958
4959 switchToPrologue();
4960 if (!emit1(JSOP_RUNONCE))
4961 return false;
4962 switchToMain();
4963 }
4964
4965 setFunctionBodyEndPos(body->pn_pos);
4966 if (!emitTree(body))
4967 return false;
4968
4969 if (!updateSourceCoordNotes(body->pn_pos.end))
4970 return false;
4971
4972 // Always end the script with a JSOP_RETRVAL. Some other parts of the
4973 // codebase depend on this opcode,
4974 // e.g. InterpreterRegs::setToEndOfScript.
4975 if (!emit1(JSOP_RETRVAL))
4976 return false;
4977
4978 if (namedLambdaEmitterScope) {
4979 if (!namedLambdaEmitterScope->leave(this))
4980 return false;
4981 namedLambdaEmitterScope.reset();
4982 }
4983
4984 if (!JSScript::fullyInitFromEmitter(cx, script, this))
4985 return false;
4986
4987 // URL and source map information must be set before firing
4988 // Debugger::onNewScript. Only top-level functions need this, as compiling
4989 // the outer scripts of nested functions already processed the source.
4990 if (emitterMode != LazyFunction && !parent) {
4991 if (!maybeSetDisplayURL() || !maybeSetSourceMap())
4992 return false;
4993
4994 tellDebuggerAboutCompiledScript(cx);
4995 }
4996
4997 return true;
4998}
4999
5000template <typename NameEmitter>
5001bool
5002BytecodeEmitter::emitDestructuringDeclsWithEmitter(ParseNode* pattern, NameEmitter emitName)
5003{
5004 if (pattern->isKind(ParseNodeKind::Array)) {
5005 for (ParseNode* element = pattern->pn_headpn_u.list.head; element; element = element->pn_next) {
5006 if (element->isKind(ParseNodeKind::Elision))
5007 continue;
5008 ParseNode* target = element;
5009 if (element->isKind(ParseNodeKind::Spread)) {
5010 target = element->pn_kidpn_u.unary.kid;
5011 }
5012 if (target->isKind(ParseNodeKind::Assign))
5013 target = target->pn_leftpn_u.binary.left;
5014 if (target->isKind(ParseNodeKind::Name)) {
5015 if (!emitName(this, target))
5016 return false;
5017 } else {
5018 if (!emitDestructuringDeclsWithEmitter(target, emitName))
5019 return false;
5020 }
5021 }
5022 return true;
5023 }
5024
5025 MOZ_ASSERT(pattern->isKind(ParseNodeKind::Object))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(pattern->isKind(ParseNodeKind::Object))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(pattern->isKind(ParseNodeKind::Object)))), 0))) { MOZ_ReportAssertionFailure
("pattern->isKind(ParseNodeKind::Object)", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5025); do { } while (false); do { *((volatile int*) __null)
= 5025; ::abort(); } while (false); } } while (false)
;
5026 for (ParseNode* member = pattern->pn_headpn_u.list.head; member; member = member->pn_next) {
5027 MOZ_ASSERT(member->isKind(ParseNodeKind::MutateProto) ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(member->isKind(ParseNodeKind::MutateProto) || member
->isKind(ParseNodeKind::Colon) || member->isKind(ParseNodeKind
::Shorthand))>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(member->isKind(ParseNodeKind::
MutateProto) || member->isKind(ParseNodeKind::Colon) || member
->isKind(ParseNodeKind::Shorthand)))), 0))) { MOZ_ReportAssertionFailure
("member->isKind(ParseNodeKind::MutateProto) || member->isKind(ParseNodeKind::Colon) || member->isKind(ParseNodeKind::Shorthand)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5029); do { } while (false); do { *((volatile int*) __null)
= 5029; ::abort(); } while (false); } } while (false)
5028 member->isKind(ParseNodeKind::Colon) ||do { static_assert(mozilla::detail::AssertionConditionType<
decltype(member->isKind(ParseNodeKind::MutateProto) || member
->isKind(ParseNodeKind::Colon) || member->isKind(ParseNodeKind
::Shorthand))>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(member->isKind(ParseNodeKind::
MutateProto) || member->isKind(ParseNodeKind::Colon) || member
->isKind(ParseNodeKind::Shorthand)))), 0))) { MOZ_ReportAssertionFailure
("member->isKind(ParseNodeKind::MutateProto) || member->isKind(ParseNodeKind::Colon) || member->isKind(ParseNodeKind::Shorthand)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5029); do { } while (false); do { *((volatile int*) __null)
= 5029; ::abort(); } while (false); } } while (false)
5029 member->isKind(ParseNodeKind::Shorthand))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(member->isKind(ParseNodeKind::MutateProto) || member
->isKind(ParseNodeKind::Colon) || member->isKind(ParseNodeKind
::Shorthand))>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(member->isKind(ParseNodeKind::
MutateProto) || member->isKind(ParseNodeKind::Colon) || member
->isKind(ParseNodeKind::Shorthand)))), 0))) { MOZ_ReportAssertionFailure
("member->isKind(ParseNodeKind::MutateProto) || member->isKind(ParseNodeKind::Colon) || member->isKind(ParseNodeKind::Shorthand)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5029); do { } while (false); do { *((volatile int*) __null)
= 5029; ::abort(); } while (false); } } while (false)
;
5030
5031 ParseNode* target = member->isKind(ParseNodeKind::MutateProto)
5032 ? member->pn_kidpn_u.unary.kid
5033 : member->pn_rightpn_u.binary.right;
5034
5035 if (target->isKind(ParseNodeKind::Assign))
5036 target = target->pn_leftpn_u.binary.left;
5037 if (target->isKind(ParseNodeKind::Name)) {
5038 if (!emitName(this, target))
5039 return false;
5040 } else {
5041 if (!emitDestructuringDeclsWithEmitter(target, emitName))
5042 return false;
5043 }
5044 }
5045 return true;
5046}
5047
5048bool
5049BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target, size_t* emitted)
5050{
5051 *emitted = 0;
5052
5053 if (target->isKind(ParseNodeKind::Spread))
5054 target = target->pn_kidpn_u.unary.kid;
5055 else if (target->isKind(ParseNodeKind::Assign))
5056 target = target->pn_leftpn_u.binary.left;
5057
5058 // No need to recur into ParseNodeKind::Array and
5059 // ParseNodeKind::Object subpatterns here, since
5060 // emitSetOrInitializeDestructuring does the recursion when
5061 // setting or initializing value. Getting reference doesn't recur.
5062 if (target->isKind(ParseNodeKind::Name) ||
5063 target->isKind(ParseNodeKind::Array) ||
5064 target->isKind(ParseNodeKind::Object))
5065 {
5066 return true;
5067 }
5068
5069#ifdef DEBUG1
5070 int depth = stackDepth;
5071#endif
5072
5073 switch (target->getKind()) {
5074 case ParseNodeKind::Dot: {
5075 if (target->as<PropertyAccess>().isSuper()) {
5076 if (!emitSuperPropLHS(&target->as<PropertyAccess>().expression()))
5077 return false;
5078 *emitted = 2;
5079 } else {
5080 if (!emitTree(target->pn_exprpn_u.name.expr))
5081 return false;
5082 *emitted = 1;
5083 }
5084 break;
5085 }
5086
5087 case ParseNodeKind::Elem: {
5088 if (target->as<PropertyByValue>().isSuper()) {
5089 if (!emitSuperElemOperands(target, EmitElemOption::Ref))
5090 return false;
5091 *emitted = 3;
5092 } else {
5093 if (!emitElemOperands(target, EmitElemOption::Ref))
5094 return false;
5095 *emitted = 2;
5096 }
5097 break;
5098 }
5099
5100 case ParseNodeKind::Call:
5101 MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget "do { static_assert(mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { MOZ_ReportAssertionFailure
("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Parser::reportIfNotValidSimpleAssignmentTarget "
"rejects function calls as assignment " "targets in destructuring assignments"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5103); do { } while (false); do { *((volatile int*) __null)
= 5103; ::abort(); } while (false); } } while (false)
5102 "rejects function calls as assignment "do { static_assert(mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { MOZ_ReportAssertionFailure
("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Parser::reportIfNotValidSimpleAssignmentTarget "
"rejects function calls as assignment " "targets in destructuring assignments"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5103); do { } while (false); do { *((volatile int*) __null)
= 5103; ::abort(); } while (false); } } while (false)
5103 "targets in destructuring assignments")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { MOZ_ReportAssertionFailure
("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Parser::reportIfNotValidSimpleAssignmentTarget "
"rejects function calls as assignment " "targets in destructuring assignments"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5103); do { } while (false); do { *((volatile int*) __null)
= 5103; ::abort(); } while (false); } } while (false)
;
5104 break;
5105
5106 default:
5107 MOZ_CRASH("emitDestructuringLHSRef: bad lhs kind")do { MOZ_ReportCrash("" "emitDestructuringLHSRef: bad lhs kind"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5107); do { } while (false); do { *((volatile int*) __null)
= 5107; ::abort(); } while (false); } while (false)
;
5108 }
5109
5110 MOZ_ASSERT(stackDepth == depth + int(*emitted))do { static_assert(mozilla::detail::AssertionConditionType<
decltype(stackDepth == depth + int(*emitted))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(stackDepth == depth + int(*emitted
)))), 0))) { MOZ_ReportAssertionFailure("stackDepth == depth + int(*emitted)"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5110); do { } while (false); do { *((volatile int*) __null)
= 5110; ::abort(); } while (false); } } while (false)
;
5111
5112 return true;
5113}
5114
5115bool
5116BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, DestructuringFlavor flav)
5117{
5118 // Now emit the lvalue opcode sequence. If the lvalue is a nested
5119 // destructuring initialiser-form, call ourselves to handle it, then pop
5120 // the matched value. Otherwise emit an lvalue bytecode sequence followed
5121 // by an assignment op.
5122 if (target->isKind(ParseNodeKind::Spread))
5123 target = target->pn_kidpn_u.unary.kid;
5124 else if (target->isKind(ParseNodeKind::Assign))
5125 target = target->pn_leftpn_u.binary.left;
5126 if (target->isKind(ParseNodeKind::Array) || target->isKind(ParseNodeKind::Object)) {
5127 if (!emitDestructuringOps(target, flav))
5128 return false;
5129 // Per its post-condition, emitDestructuringOps has left the
5130 // to-be-destructured value on top of the stack.
5131 if (!emit1(JSOP_POP))
5132 return false;
5133 } else {
5134 switch (target->getKind()) {
5135 case ParseNodeKind::Name: {
5136 auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&,
5137 bool emittedBindOp)
5138 {
5139 if (emittedBindOp) {
5140 // This is like ordinary assignment, but with one
5141 // difference.
5142 //
5143 // In `a = b`, we first determine a binding for `a` (using
5144 // JSOP_BINDNAME or JSOP_BINDGNAME), then we evaluate `b`,
5145 // then a JSOP_SETNAME instruction.
5146 //
5147 // In `[a] = [b]`, per spec, `b` is evaluated first, then
5148 // we determine a binding for `a`. Then we need to do
5149 // assignment-- but the operands are on the stack in the
5150 // wrong order for JSOP_SETPROP, so we have to add a
5151 // JSOP_SWAP.
5152 //
5153 // In the cases where we are emitting a name op, emit a
5154 // swap because of this.
5155 return bce->emit1(JSOP_SWAP);
5156 }
5157
5158 // In cases of emitting a frame slot or environment slot,
5159 // nothing needs be done.
5160 return true;
5161 };
5162
5163 RootedAtom name(cx, target->name());
5164 switch (flav) {
5165 case DestructuringDeclaration:
5166 if (!emitInitializeName(name, emitSwapScopeAndRhs))
5167 return false;
5168 break;
5169
5170 case DestructuringFormalParameterInVarScope: {
5171 // If there's an parameter expression var scope, the
5172 // destructuring declaration needs to initialize the name in
5173 // the function scope. The innermost scope is the var scope,
5174 // and its enclosing scope is the function scope.
5175 EmitterScope* funScope = innermostEmitterScope->enclosingInFrame();
5176 NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
5177 if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true))
5178 return false;
5179 break;
5180 }
5181
5182 case DestructuringAssignment:
5183 if (!emitSetName(name, emitSwapScopeAndRhs))
5184 return false;
5185 break;
5186 }
5187
5188 break;
5189 }
5190
5191 case ParseNodeKind::Dot: {
5192 // The reference is already pushed by emitDestructuringLHSRef.
5193 JSOp setOp;
5194 if (target->as<PropertyAccess>().isSuper())
5195 setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
5196 else
5197 setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
5198 if (!emitAtomOp(target, setOp))
5199 return false;
5200 break;
5201 }
5202
5203 case ParseNodeKind::Elem: {
5204 // The reference is already pushed by emitDestructuringLHSRef.
5205 if (target->as<PropertyByValue>().isSuper()) {
5206 JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
5207 // emitDestructuringLHSRef already did emitSuperElemOperands
5208 // part of emitSuperElemOp. Perform remaining part here.
5209 if (!emitElemOpBase(setOp))
5210 return false;
5211 } else {
5212 JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
5213 if (!emitElemOpBase(setOp))
5214 return false;
5215 }
5216 break;
5217 }
5218
5219 case ParseNodeKind::Call:
5220 MOZ_ASSERT_UNREACHABLE("Parser::reportIfNotValidSimpleAssignmentTarget "do { static_assert(mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { MOZ_ReportAssertionFailure
("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Parser::reportIfNotValidSimpleAssignmentTarget "
"rejects function calls as assignment " "targets in destructuring assignments"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5222); do { } while (false); do { *((volatile int*) __null)
= 5222; ::abort(); } while (false); } } while (false)
5221 "rejects function calls as assignment "do { static_assert(mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { MOZ_ReportAssertionFailure
("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Parser::reportIfNotValidSimpleAssignmentTarget "
"rejects function calls as assignment " "targets in destructuring assignments"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5222); do { } while (false); do { *((volatile int*) __null)
= 5222; ::abort(); } while (false); } } while (false)
5222 "targets in destructuring assignments")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { MOZ_ReportAssertionFailure
("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Parser::reportIfNotValidSimpleAssignmentTarget "
"rejects function calls as assignment " "targets in destructuring assignments"
")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5222); do { } while (false); do { *((volatile int*) __null)
= 5222; ::abort(); } while (false); } } while (false)
;
5223 break;
5224
5225 default:
5226 MOZ_CRASH("emitSetOrInitializeDestructuring: bad lhs kind")do { MOZ_ReportCrash("" "emitSetOrInitializeDestructuring: bad lhs kind"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5226); do { } while (false); do { *((volatile int*) __null)
= 5226; ::abort(); } while (false); } while (false)
;
5227 }
5228
5229 // Pop the assigned value.
5230 if (!emit1(JSOP_POP))
5231 return false;
5232 }
5233
5234 return true;
5235}
5236
5237bool
5238BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = IteratorKind::Sync */,
5239 bool allowSelfHosted /* = false */)
5240{
5241 MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,do { static_assert(mozilla::detail::AssertionConditionType<
decltype(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
))), 0))) { MOZ_ReportAssertionFailure("allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting"
" (" ".next() iteration is prohibited in self-hosted code because it "
"can run user-modifiable iteration code" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5243); do { } while (false); do { *((volatile int*) __null)
= 5243; ::abort(); } while (false); } } while (false)
5242 ".next() iteration is prohibited in self-hosted code because it "do { static_assert(mozilla::detail::AssertionConditionType<
decltype(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
))), 0))) { MOZ_ReportAssertionFailure("allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting"
" (" ".next() iteration is prohibited in self-hosted code because it "
"can run user-modifiable iteration code" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5243); do { } while (false); do { *((volatile int*) __null)
= 5243; ::abort(); } while (false); } } while (false)
5243 "can run user-modifiable iteration code")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
))), 0))) { MOZ_ReportAssertionFailure("allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting"
" (" ".next() iteration is prohibited in self-hosted code because it "
"can run user-modifiable iteration code" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5243); do { } while (false); do { *((volatile int*) __null)
= 5243; ::abort(); } while (false); } } while (false)
;
5244
5245 MOZ_ASSERT(this->stackDepth >= 2)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this->stackDepth >= 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this->stackDepth >= 2)
)), 0))) { MOZ_ReportAssertionFailure("this->stackDepth >= 2"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5245); do { } while (false); do { *((volatile int*) __null)
= 5245; ::abort(); } while (false); } } while (false)
; // ... NEXT ITER
5246
5247 if (!emitCall(JSOP_CALL, 0, pn)) // ... RESULT
5248 return false;
5249
5250 if (iterKind == IteratorKind::Async) {
5251 if (!emitAwait()) // ... RESULT
5252 return false;
5253 }
5254
5255 if (!emitCheckIsObj(CheckIsObjectKind::IteratorNext)) // ... RESULT
5256 return false;
5257 checkTypeSet(JSOP_CALL);
5258 return true;
5259}
5260
5261bool
5262BytecodeEmitter::emitPushNotUndefinedOrNull()
5263{
5264 MOZ_ASSERT(this->stackDepth > 0)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this->stackDepth > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this->stackDepth > 0))
), 0))) { MOZ_ReportAssertionFailure("this->stackDepth > 0"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5264); do { } while (false); do { *((volatile int*) __null)
= 5264; ::abort(); } while (false); } } while (false)
; // V
5265
5266 if (!emit1(JSOP_DUP)) // V V
5267 return false;
5268 if (!emit1(JSOP_UNDEFINED)) // V V UNDEFINED
5269 return false;
5270 if (!emit1(JSOP_STRICTNE)) // V ?NEQL
5271 return false;
5272
5273 JumpList undefinedOrNullJump;
5274 if (!emitJump(JSOP_AND, &undefinedOrNullJump)) // V ?NEQL
5275 return false;
5276
5277 if (!emit1(JSOP_POP)) // V
5278 return false;
5279 if (!emit1(JSOP_DUP)) // V V
5280 return false;
5281 if (!emit1(JSOP_NULL)) // V V NULL
5282 return false;
5283 if (!emit1(JSOP_STRICTNE)) // V ?NEQL
5284 return false;
5285
5286 if (!emitJumpTargetAndPatch(undefinedOrNullJump)) // V NOT-UNDEF-OR-NULL
5287 return false;
5288
5289 return true;
5290}
5291
5292bool
5293BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync */,
5294 CompletionKind completionKind /* = CompletionKind::Normal */,
5295 bool allowSelfHosted /* = false */)
5296{
5297 MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,do { static_assert(mozilla::detail::AssertionConditionType<
decltype(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
))), 0))) { MOZ_ReportAssertionFailure("allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting"
" (" ".close() on iterators is prohibited in self-hosted code because it "
"can run user-modifiable iteration code" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5299); do { } while (false); do { *((volatile int*) __null)
= 5299; ::abort(); } while (false); } } while (false)
5298 ".close() on iterators is prohibited in self-hosted code because it "do { static_assert(mozilla::detail::AssertionConditionType<
decltype(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
))), 0))) { MOZ_ReportAssertionFailure("allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting"
" (" ".close() on iterators is prohibited in self-hosted code because it "
"can run user-modifiable iteration code" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5299); do { } while (false); do { *((volatile int*) __null)
= 5299; ::abort(); } while (false); } } while (false)
5299 "can run user-modifiable iteration code")do { static_assert(mozilla::detail::AssertionConditionType<
decltype(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting
))), 0))) { MOZ_ReportAssertionFailure("allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting"
" (" ".close() on iterators is prohibited in self-hosted code because it "
"can run user-modifiable iteration code" ")", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5299); do { } while (false); do { *((volatile int*) __null)
= 5299; ::abort(); } while (false); } } while (false)
;
5300
5301 // Generate inline logic corresponding to IteratorClose (ES 7.4.6).
5302 //
5303 // Callers need to ensure that the iterator object is at the top of the
5304 // stack.
5305
5306 if (!emit1(JSOP_DUP)) // ... ITER ITER
5307 return false;
5308
5309 // Step 3.
5310 //
5311 // Get the "return" method.
5312 if (!emitAtomOp(cx->names().return_, JSOP_CALLPROP)) // ... ITER RET
5313 return false;
5314
5315 // Step 4.
5316 //
5317 // Do nothing if "return" is undefined or null.
5318 IfThenElseEmitter ifReturnMethodIsDefined(this);
5319 if (!emitPushNotUndefinedOrNull()) // ... ITER RET NOT-UNDEF-OR-NULL
5320 return false;
5321
5322 if (!ifReturnMethodIsDefined.emitIfElse()) // ... ITER RET
5323 return false;
5324
5325 if (completionKind == CompletionKind::Throw) {
5326 // 7.4.6 IteratorClose ( iterator, completion )
5327 // ...
5328 // 3. Let return be ? GetMethod(iterator, "return").
5329 // 4. If return is undefined, return Completion(completion).
5330 // 5. Let innerResult be Call(return, iterator, « »).
5331 // 6. If completion.[[Type]] is throw, return Completion(completion).
5332 // 7. If innerResult.[[Type]] is throw, return
5333 // Completion(innerResult).
5334 //
5335 // For CompletionKind::Normal case, JSOP_CALL for step 5 checks if RET
5336 // is callable, and throws if not. Since step 6 doesn't match and
5337 // error handling in step 3 and step 7 can be merged.
5338 //
5339 // For CompletionKind::Throw case, an error thrown by JSOP_CALL for
5340 // step 5 is ignored by try-catch. So we should check if RET is
5341 // callable here, outside of try-catch, and the throw immediately if
5342 // not.
5343 CheckIsCallableKind kind = CheckIsCallableKind::IteratorReturn;
5344 if (!emitCheckIsCallable(kind)) // ... ITER RET
5345 return false;
5346 }
5347
5348 // Steps 5, 8.
5349 //
5350 // Call "return" if it is not undefined or null, and check that it returns
5351 // an Object.
5352 if (!emit1(JSOP_SWAP)) // ... RET ITER
5353 return false;
5354
5355 Maybe<TryEmitter> tryCatch;
5356
5357 if (completionKind == CompletionKind::Throw) {
5358 tryCatch.emplace(this, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
5359 TryEmitter::DontUseControl);
5360
5361 // Mutate stack to balance stack for try-catch.
5362 if (!emit1(JSOP_UNDEFINED)) // ... RET ITER UNDEF
5363 return false;
5364 if (!tryCatch->emitTry()) // ... RET ITER UNDEF
5365 return false;
5366 if (!emitDupAt(2)) // ... RET ITER UNDEF RET
5367 return false;
5368 if (!emitDupAt(2)) // ... RET ITER UNDEF RET ITER
5369 return false;
5370 }
5371
5372 if (!emitCall(JSOP_CALL, 0)) // ... ... RESULT
5373 return false;
5374 checkTypeSet(JSOP_CALL);
5375
5376 if (iterKind == IteratorKind::Async) {
5377 if (completionKind != CompletionKind::Throw) {
5378 // Await clobbers rval, so save the current rval.
5379 if (!emit1(JSOP_GETRVAL)) // ... ... RESULT RVAL
5380 return false;
5381 if (!emit1(JSOP_SWAP)) // ... ... RVAL RESULT
5382 return false;
5383 }
5384 if (!emitAwait()) // ... ... RVAL? RESULT
5385 return false;
5386 }
5387
5388 if (completionKind == CompletionKind::Throw) {
5389 if (!emit1(JSOP_SWAP)) // ... RET ITER RESULT UNDEF
5390 return false;
5391 if (!emit1(JSOP_POP)) // ... RET ITER RESULT
5392 return false;
5393
5394 if (!tryCatch->emitCatch()) // ... RET ITER RESULT
5395 return false;
5396
5397 // Just ignore the exception thrown by call and await.
5398 if (!emit1(JSOP_EXCEPTION)) // ... RET ITER RESULT EXC
5399 return false;
5400 if (!emit1(JSOP_POP)) // ... RET ITER RESULT
5401 return false;
5402
5403 if (!tryCatch->emitEnd()) // ... RET ITER RESULT
5404 return false;
5405
5406 // Restore stack.
5407 if (!emit2(JSOP_UNPICK, 2)) // ... RESULT RET ITER
5408 return false;
5409 if (!emitPopN(2)) // ... RESULT
5410 return false;
5411 } else {
5412 if (!emitCheckIsObj(CheckIsObjectKind::IteratorReturn)) // ... RVAL? RESULT
5413 return false;
5414
5415 if (iterKind == IteratorKind::Async) {
5416 if (!emit1(JSOP_SWAP)) // ... RESULT RVAL
5417 return false;
5418 if (!emit1(JSOP_SETRVAL)) // ... RESULT
5419 return false;
5420 }
5421 }
5422
5423 if (!ifReturnMethodIsDefined.emitElse()) // ... ITER RET
5424 return false;
5425
5426 if (!emit1(JSOP_POP)) // ... ITER
5427 return false;
5428
5429 if (!ifReturnMethodIsDefined.emitEnd())
5430 return false;
5431
5432 return emit1(JSOP_POP); // ...
5433}
5434
5435template <typename InnerEmitter>
5436bool
5437BytecodeEmitter::wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth, InnerEmitter emitter)
5438{
5439 MOZ_ASSERT(this->stackDepth >= iterDepth)do { static_assert(mozilla::detail::AssertionConditionType<
decltype(this->stackDepth >= iterDepth)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(this->stackDepth >= iterDepth
))), 0))) { MOZ_ReportAssertionFailure("this->stackDepth >= iterDepth"
, "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5439); do { } while (false); do { *((volatile int*) __null)
= 5439; ::abort(); } while (false); } } while (false)
;
5440
5441 // Pad a nop at the beginning of the bytecode covered by the trynote so
5442 // that when unwinding environments, we may unwind to the scope
5443 // corresponding to the pc *before* the start, in case the first bytecode
5444 // emitted by |emitter| is the start of an inner scope. See comment above
5445 // UnwindEnvironmentToTryPc.
5446 if (!emit1(JSOP_TRY_DESTRUCTURING_ITERCLOSE))
5447 return false;
5448
5449 ptrdiff_t start = offset();
5450 if (!emitter(this))
5451 return false;
5452 ptrdiff_t end = offset();
5453 if (start != end)
5454 return tryNoteList.append(JSTRY_DESTRUCTURING_ITERCLOSE, iterDepth, start, end);
5455 return true;
5456}
5457
5458bool
5459BytecodeEmitter::emitDefault(ParseNode* defaultExpr, ParseNode* pattern)
5460{
5461 if (!emit1(JSOP_DUP)) // VALUE VALUE
5462 return false;
5463 if (!emit1(JSOP_UNDEFINED)) // VALUE VALUE UNDEFINED
5464 return false;
5465 if (!emit1(JSOP_STRICTEQ)) // VALUE EQL?
5466 return false;
5467 // Emit source note to enable ion compilation.
5468 if (!newSrcNote(SRC_IF))
5469 return false;
5470 JumpList jump;
5471 if (!emitJump(JSOP_IFEQ, &jump)) // VALUE
5472 return false;
5473 if (!emit1(JSOP_POP)) // .
5474 return false;
5475 if (!emitInitializerInBranch(defaultExpr, pattern)) // DEFAULTVALUE
5476 return false;
5477 if (!emitJumpTargetAndPatch(jump))
5478 return false;
5479 return true;
5480}
5481
5482bool
5483BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name)
5484{
5485 MOZ_ASSERT(maybeFun->isDirectRHSAnonFunction())do { static_assert(mozilla::detail::AssertionConditionType<
decltype(maybeFun->isDirectRHSAnonFunction())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(maybeFun->isDirectRHSAnonFunction()))), 0))) { MOZ_ReportAssertionFailure
("maybeFun->isDirectRHSAnonFunction()", "/data/jenkins/workspace/firefox-scan-build/js/src/frontend/BytecodeEmitter.cpp"
, 5485); do { } while (false); do { *((volatile int*) __null)
= 5485; ::abort(); } while (false); } } while (false)
;
5486
5487 if (maybeFun->isKind(ParseNodeKind::Function)) {
5488 // Function doesn't have 'name' property at this point.
5489 // Set function's name at compile time.
5490 JSFunction* fun = maybeFun->pn_funboxpn_u.name.funbox->function();