Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp
Warning:line 1826, column 5
Value stored to 'valueOffset' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_js_src_jit1.cpp -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 -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D WASM_SUPPORTS_HUGE_MEMORY -D JS_CACHEIR_SPEW -D JS_STRUCTURED_SPEW -D JS_HAS_CTYPES -D FFI_BUILDING -D EXPORT_JS_API -D MOZ_HAS_MOZGLUE -D MOZ_SUPPORT_LEAKCHECKING -I /var/lib/jenkins/workspace/firefox-scan-build/js/src/jit -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src -I /var/lib/jenkins/workspace/firefox-scan-build/js/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-09-22-115206-3586786-1 -x c++ Unified_cpp_js_src_jit1.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "jit/BaselineIC.h"
8
9#include "mozilla/DebugOnly.h"
10#include "mozilla/Sprintf.h"
11
12#include "jstypes.h"
13
14#include "builtin/Eval.h"
15#include "jit/BaselineCacheIRCompiler.h"
16#include "jit/CacheIRGenerator.h"
17#include "jit/CacheIRHealth.h"
18#include "jit/JitFrames.h"
19#include "jit/JitRuntime.h"
20#include "jit/JitSpewer.h"
21#include "jit/Linker.h"
22#include "jit/PerfSpewer.h"
23#include "jit/SharedICHelpers.h"
24#include "jit/SharedICRegisters.h"
25#include "jit/VMFunctions.h"
26#include "js/Conversions.h"
27#include "js/friend/ErrorMessages.h" // JSMSG_*
28#include "vm/BytecodeIterator.h"
29#include "vm/BytecodeLocation.h"
30#include "vm/BytecodeUtil.h"
31#include "vm/EqualityOperations.h"
32#include "vm/JSFunction.h"
33#include "vm/JSScript.h"
34#include "vm/Opcodes.h"
35#include "vm/TypeofEqOperand.h" // TypeofEqOperand
36#ifdef MOZ_VTUNE1
37# include "vtune/VTuneWrapper.h"
38#endif
39
40#include "jit/MacroAssembler-inl.h"
41#include "jit/SharedICHelpers-inl.h"
42#include "jit/VMFunctionList-inl.h"
43#include "vm/BytecodeIterator-inl.h"
44#include "vm/BytecodeLocation-inl.h"
45#include "vm/EnvironmentObject-inl.h"
46#include "vm/Interpreter-inl.h"
47#include "vm/JSScript-inl.h"
48
49using mozilla::DebugOnly;
50
51namespace js {
52namespace jit {
53
54// Class used to emit all Baseline IC fallback code when initializing the
55// JitRuntime.
56class MOZ_RAII FallbackICCodeCompiler final {
57 BaselineICFallbackCode& code;
58 MacroAssembler& masm;
59
60 JSContext* cx;
61 bool inStubFrame_ = false;
62
63#ifdef DEBUG1
64 bool entersStubFrame_ = false;
65 uint32_t framePushedAtEnterStubFrame_ = 0;
66#endif
67
68 [[nodiscard]] bool emitCall(bool isSpread, bool isConstructing);
69 [[nodiscard]] bool emitGetElem(bool hasReceiver);
70 [[nodiscard]] bool emitGetProp(bool hasReceiver);
71
72 public:
73 FallbackICCodeCompiler(JSContext* cx, BaselineICFallbackCode& code,
74 MacroAssembler& masm)
75 : code(code), masm(masm), cx(cx) {}
76
77#define DEF_METHOD(kind) [[nodiscard]] bool emit_##kind();
78 IC_BASELINE_FALLBACK_CODE_KIND_LIST(DEF_METHOD)DEF_METHOD(NewArray) DEF_METHOD(NewObject) DEF_METHOD(ToBool)
DEF_METHOD(UnaryArith) DEF_METHOD(Call) DEF_METHOD(CallConstructing
) DEF_METHOD(SpreadCall) DEF_METHOD(SpreadCallConstructing) DEF_METHOD
(GetElem) DEF_METHOD(GetElemSuper) DEF_METHOD(SetElem) DEF_METHOD
(In) DEF_METHOD(HasOwn) DEF_METHOD(CheckPrivateField) DEF_METHOD
(GetName) DEF_METHOD(BindName) DEF_METHOD(GetIntrinsic) DEF_METHOD
(SetProp) DEF_METHOD(GetIterator) DEF_METHOD(OptimizeSpreadCall
) DEF_METHOD(InstanceOf) DEF_METHOD(TypeOf) DEF_METHOD(TypeOfEq
) DEF_METHOD(ToPropertyKey) DEF_METHOD(Rest) DEF_METHOD(BinaryArith
) DEF_METHOD(Compare) DEF_METHOD(GetProp) DEF_METHOD(GetPropSuper
) DEF_METHOD(CloseIter) DEF_METHOD(OptimizeGetIterator)
79#undef DEF_METHOD
80
81 void pushCallArguments(MacroAssembler& masm,
82 AllocatableGeneralRegisterSet regs, Register argcReg,
83 bool isConstructing);
84
85 // Push a payload specialized per compiler needed to execute stubs.
86 void PushStubPayload(MacroAssembler& masm, Register scratch);
87 void pushStubPayload(MacroAssembler& masm, Register scratch);
88
89 // Emits a tail call to a VMFunction wrapper.
90 [[nodiscard]] bool tailCallVMInternal(MacroAssembler& masm, VMFunctionId id);
91
92 template <typename Fn, Fn fn>
93 [[nodiscard]] bool tailCallVM(MacroAssembler& masm);
94
95 // Emits a normal (non-tail) call to a VMFunction wrapper.
96 [[nodiscard]] bool callVMInternal(MacroAssembler& masm, VMFunctionId id);
97
98 template <typename Fn, Fn fn>
99 [[nodiscard]] bool callVM(MacroAssembler& masm);
100
101 // A stub frame is used when a stub wants to call into the VM without
102 // performing a tail call. This is required for the return address
103 // to pc mapping to work.
104 void enterStubFrame(MacroAssembler& masm, Register scratch);
105 void assumeStubFrame();
106 void leaveStubFrame(MacroAssembler& masm);
107};
108
109AllocatableGeneralRegisterSet BaselineICAvailableGeneralRegs(size_t numInputs) {
110 AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
111 MOZ_ASSERT(!regs.has(FramePointer))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!regs.has(FramePointer))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!regs.has(FramePointer)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!regs.has(FramePointer)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(FramePointer)"
")"); do { *((volatile int*)__null) = 111; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
112#if defined(JS_CODEGEN_ARM)
113 MOZ_ASSERT(!regs.has(ICTailCallReg))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!regs.has(ICTailCallReg))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!regs.has(ICTailCallReg)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!regs.has(ICTailCallReg)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(ICTailCallReg)"
")"); do { *((volatile int*)__null) = 113; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
114 regs.take(BaselineSecondScratchReg);
115#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
116 MOZ_ASSERT(!regs.has(ICTailCallReg))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!regs.has(ICTailCallReg))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!regs.has(ICTailCallReg)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!regs.has(ICTailCallReg)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 116); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(ICTailCallReg)"
")"); do { *((volatile int*)__null) = 116; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
117 MOZ_ASSERT(!regs.has(BaselineSecondScratchReg))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!regs.has(BaselineSecondScratchReg))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!regs.has(BaselineSecondScratchReg
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!regs.has(BaselineSecondScratchReg)", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 117); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(BaselineSecondScratchReg)"
")"); do { *((volatile int*)__null) = 117; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
118#elif defined(JS_CODEGEN_ARM64)
119 MOZ_ASSERT(!regs.has(PseudoStackPointer))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!regs.has(PseudoStackPointer))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!regs.has(PseudoStackPointer
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!regs.has(PseudoStackPointer)", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 119); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(PseudoStackPointer)"
")"); do { *((volatile int*)__null) = 119; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
120 MOZ_ASSERT(!regs.has(RealStackPointer))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!regs.has(RealStackPointer))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!regs.has(RealStackPointer))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!regs.has(RealStackPointer)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 120); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(RealStackPointer)"
")"); do { *((volatile int*)__null) = 120; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
121 MOZ_ASSERT(!regs.has(ICTailCallReg))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!regs.has(ICTailCallReg))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!regs.has(ICTailCallReg)))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!regs.has(ICTailCallReg)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 121); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(ICTailCallReg)"
")"); do { *((volatile int*)__null) = 121; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
122#endif
123 regs.take(ICStubReg);
124
125 switch (numInputs) {
126 case 0:
127 break;
128 case 1:
129 regs.take(R0);
130 break;
131 case 2:
132 regs.take(R0);
133 regs.take(R1);
134 break;
135 default:
136 MOZ_CRASH("Invalid numInputs")do { do { } while (false); MOZ_ReportCrash("" "Invalid numInputs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 136); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid numInputs"
")"); do { *((volatile int*)__null) = 136; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
137 }
138
139 return regs;
140}
141
142static jsbytecode* StubOffsetToPc(const ICFallbackStub* stub,
143 const JSScript* script) {
144 return script->offsetToPC(stub->pcOffset());
145}
146
147#ifdef JS_JITSPEW1
148void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...) {
149 if (JitSpewEnabled(JitSpew_BaselineICFallback)) {
150 RootedScript script(cx, GetTopJitJSScript(cx));
151 jsbytecode* pc = StubOffsetToPc(stub, script);
152
153 char fmtbuf[100];
154 va_list args;
155 va_start(args, fmt)__builtin_va_start(args, fmt);
156 (void)VsprintfLiteral(fmtbuf, fmt, args);
157 va_end(args)__builtin_va_end(args);
158
159 JitSpew(
160 JitSpew_BaselineICFallback,
161 "Fallback hit for (%s:%u:%u) (pc=%zu,line=%u,uses=%u,stubs=%zu): %s",
162 script->filename(), script->lineno(), script->column().oneOriginValue(),
163 script->pcToOffset(pc), PCToLineNumber(script, pc),
164 script->getWarmUpCount(), stub->numOptimizedStubs(), fmtbuf);
165 }
166}
167#endif // JS_JITSPEW
168
169void ICEntry::trace(JSTracer* trc) {
170 ICStub* stub = firstStub();
171
172 // Trace CacheIR stubs.
173 while (!stub->isFallback()) {
174 stub->toCacheIRStub()->trace(trc);
175 stub = stub->toCacheIRStub()->next();
176 }
177
178 // Fallback stubs use runtime-wide trampoline code we don't need to trace.
179 MOZ_ASSERT(stub->usesTrampolineCode())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(stub->usesTrampolineCode())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(stub->usesTrampolineCode(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("stub->usesTrampolineCode()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 179); AnnotateMozCrashReason("MOZ_ASSERT" "(" "stub->usesTrampolineCode()"
")"); do { *((volatile int*)__null) = 179; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
180}
181
182inline ICFallbackStub* GetFallbackStub(ICEntry* entry) {
183 ICStub* stub = entry->firstStub();
184 while (!stub->isFallback()) {
185 stub = stub->toCacheIRStub()->next();
186 }
187 return stub->toFallbackStub();
188}
189
190bool ICEntry::traceWeak(JSTracer* trc) {
191 // Trace CacheIR stubs and remove those containing weak pointers to dead GC
192 // things. Prebarriers are not necessary because this happens as part of GC.
193
194 ICFallbackStub* fallbackStub = GetFallbackStub(this);
195
196 ICStub* stub = firstStub();
197 ICCacheIRStub* prev = nullptr;
198 bool allSurvived = true;
199 while (!stub->isFallback()) {
200 ICCacheIRStub* cacheIRStub = stub->toCacheIRStub();
201 if (!cacheIRStub->traceWeak(trc)) {
202 fallbackStub->unlinkStubUnbarriered(this, prev, cacheIRStub);
203 allSurvived = false;
204 } else {
205 prev = cacheIRStub;
206 }
207
208 stub = cacheIRStub->next();
209 MOZ_ASSERT_IF(prev, prev->next() == stub)do { if (prev) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(prev->next() == stub)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prev->next() == stub))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("prev->next() == stub"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 209); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prev->next() == stub"
")"); do { *((volatile int*)__null) = 209; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
210 }
211
212 // Clear the folded stubs flag if we know for sure that there are none
213 // left. The flag will remain set if we have removed all folded stubs but
214 // other stubs remain.
215 if (fallbackStub->numOptimizedStubs() == 0 &&
216 fallbackStub->mayHaveFoldedStub()) {
217 fallbackStub->clearMayHaveFoldedStub();
218 }
219
220#ifdef DEBUG1
221 size_t count = 0;
222 for (ICStub* stub = firstStub(); stub != fallbackStub;
223 stub = stub->toCacheIRStub()->next()) {
224 count++;
225 }
226 MOZ_ASSERT(count == fallbackStub->state().numOptimizedStubs())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(count == fallbackStub->state().numOptimizedStubs(
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(count == fallbackStub->state().numOptimizedStubs(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("count == fallbackStub->state().numOptimizedStubs()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 226); AnnotateMozCrashReason("MOZ_ASSERT" "(" "count == fallbackStub->state().numOptimizedStubs()"
")"); do { *((volatile int*)__null) = 226; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
227#endif
228
229 return allSurvived;
230}
231
232// constexpr table mapping JSOp to BaselineICFallbackKind. Each value in the
233// table is either a fallback kind or a sentinel value (NoICValue) indicating
234// the JSOp is not a JOF_IC op.
235class MOZ_STATIC_CLASS OpToFallbackKindTable {
236 static_assert(sizeof(BaselineICFallbackKind) == sizeof(uint8_t));
237 uint8_t table_[JSOP_LIMIT] = {};
238
239 constexpr void setKind(JSOp op, BaselineICFallbackKind kind) {
240 MOZ_ASSERT(uint8_t(kind) != NoICValue)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(uint8_t(kind) != NoICValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(uint8_t(kind) != NoICValue))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("uint8_t(kind) != NoICValue"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 240); AnnotateMozCrashReason("MOZ_ASSERT" "(" "uint8_t(kind) != NoICValue"
")"); do { *((volatile int*)__null) = 240; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
241 table_[size_t(op)] = uint8_t(kind);
242 }
243
244 public:
245 static constexpr uint8_t NoICValue = uint8_t(BaselineICFallbackKind::Count);
246
247 uint8_t lookup(JSOp op) const { return table_[size_t(op)]; }
248
249 constexpr OpToFallbackKindTable() {
250 for (size_t i = 0; i < JSOP_LIMIT; i++) {
251 table_[i] = NoICValue;
252 }
253
254 setKind(JSOp::Not, BaselineICFallbackKind::ToBool);
255 setKind(JSOp::And, BaselineICFallbackKind::ToBool);
256 setKind(JSOp::Or, BaselineICFallbackKind::ToBool);
257 setKind(JSOp::JumpIfTrue, BaselineICFallbackKind::ToBool);
258 setKind(JSOp::JumpIfFalse, BaselineICFallbackKind::ToBool);
259
260 setKind(JSOp::BitNot, BaselineICFallbackKind::UnaryArith);
261 setKind(JSOp::Pos, BaselineICFallbackKind::UnaryArith);
262 setKind(JSOp::Neg, BaselineICFallbackKind::UnaryArith);
263 setKind(JSOp::Inc, BaselineICFallbackKind::UnaryArith);
264 setKind(JSOp::Dec, BaselineICFallbackKind::UnaryArith);
265 setKind(JSOp::ToNumeric, BaselineICFallbackKind::UnaryArith);
266
267 setKind(JSOp::BitOr, BaselineICFallbackKind::BinaryArith);
268 setKind(JSOp::BitXor, BaselineICFallbackKind::BinaryArith);
269 setKind(JSOp::BitAnd, BaselineICFallbackKind::BinaryArith);
270 setKind(JSOp::Lsh, BaselineICFallbackKind::BinaryArith);
271 setKind(JSOp::Rsh, BaselineICFallbackKind::BinaryArith);
272 setKind(JSOp::Ursh, BaselineICFallbackKind::BinaryArith);
273 setKind(JSOp::Add, BaselineICFallbackKind::BinaryArith);
274 setKind(JSOp::Sub, BaselineICFallbackKind::BinaryArith);
275 setKind(JSOp::Mul, BaselineICFallbackKind::BinaryArith);
276 setKind(JSOp::Div, BaselineICFallbackKind::BinaryArith);
277 setKind(JSOp::Mod, BaselineICFallbackKind::BinaryArith);
278 setKind(JSOp::Pow, BaselineICFallbackKind::BinaryArith);
279
280 setKind(JSOp::Eq, BaselineICFallbackKind::Compare);
281 setKind(JSOp::Ne, BaselineICFallbackKind::Compare);
282 setKind(JSOp::Lt, BaselineICFallbackKind::Compare);
283 setKind(JSOp::Le, BaselineICFallbackKind::Compare);
284 setKind(JSOp::Gt, BaselineICFallbackKind::Compare);
285 setKind(JSOp::Ge, BaselineICFallbackKind::Compare);
286 setKind(JSOp::StrictEq, BaselineICFallbackKind::Compare);
287 setKind(JSOp::StrictNe, BaselineICFallbackKind::Compare);
288
289 setKind(JSOp::NewArray, BaselineICFallbackKind::NewArray);
290
291 setKind(JSOp::NewObject, BaselineICFallbackKind::NewObject);
292 setKind(JSOp::NewInit, BaselineICFallbackKind::NewObject);
293
294 setKind(JSOp::InitElem, BaselineICFallbackKind::SetElem);
295 setKind(JSOp::InitHiddenElem, BaselineICFallbackKind::SetElem);
296 setKind(JSOp::InitLockedElem, BaselineICFallbackKind::SetElem);
297 setKind(JSOp::InitElemInc, BaselineICFallbackKind::SetElem);
298 setKind(JSOp::SetElem, BaselineICFallbackKind::SetElem);
299 setKind(JSOp::StrictSetElem, BaselineICFallbackKind::SetElem);
300
301 setKind(JSOp::InitProp, BaselineICFallbackKind::SetProp);
302 setKind(JSOp::InitLockedProp, BaselineICFallbackKind::SetProp);
303 setKind(JSOp::InitHiddenProp, BaselineICFallbackKind::SetProp);
304 setKind(JSOp::InitGLexical, BaselineICFallbackKind::SetProp);
305 setKind(JSOp::SetProp, BaselineICFallbackKind::SetProp);
306 setKind(JSOp::StrictSetProp, BaselineICFallbackKind::SetProp);
307 setKind(JSOp::SetName, BaselineICFallbackKind::SetProp);
308 setKind(JSOp::StrictSetName, BaselineICFallbackKind::SetProp);
309 setKind(JSOp::SetGName, BaselineICFallbackKind::SetProp);
310 setKind(JSOp::StrictSetGName, BaselineICFallbackKind::SetProp);
311
312 setKind(JSOp::GetProp, BaselineICFallbackKind::GetProp);
313 setKind(JSOp::GetBoundName, BaselineICFallbackKind::GetProp);
314
315 setKind(JSOp::GetPropSuper, BaselineICFallbackKind::GetPropSuper);
316
317 setKind(JSOp::GetElem, BaselineICFallbackKind::GetElem);
318
319 setKind(JSOp::GetElemSuper, BaselineICFallbackKind::GetElemSuper);
320
321 setKind(JSOp::In, BaselineICFallbackKind::In);
322
323 setKind(JSOp::HasOwn, BaselineICFallbackKind::HasOwn);
324
325 setKind(JSOp::CheckPrivateField, BaselineICFallbackKind::CheckPrivateField);
326
327 setKind(JSOp::GetName, BaselineICFallbackKind::GetName);
328 setKind(JSOp::GetGName, BaselineICFallbackKind::GetName);
329
330 setKind(JSOp::BindName, BaselineICFallbackKind::BindName);
331 setKind(JSOp::BindUnqualifiedName, BaselineICFallbackKind::BindName);
332 setKind(JSOp::BindUnqualifiedGName, BaselineICFallbackKind::BindName);
333
334 setKind(JSOp::GetIntrinsic, BaselineICFallbackKind::GetIntrinsic);
335
336 setKind(JSOp::Call, BaselineICFallbackKind::Call);
337 setKind(JSOp::CallContent, BaselineICFallbackKind::Call);
338 setKind(JSOp::CallIgnoresRv, BaselineICFallbackKind::Call);
339 setKind(JSOp::CallIter, BaselineICFallbackKind::Call);
340 setKind(JSOp::CallContentIter, BaselineICFallbackKind::Call);
341 setKind(JSOp::Eval, BaselineICFallbackKind::Call);
342 setKind(JSOp::StrictEval, BaselineICFallbackKind::Call);
343
344 setKind(JSOp::SuperCall, BaselineICFallbackKind::CallConstructing);
345 setKind(JSOp::New, BaselineICFallbackKind::CallConstructing);
346 setKind(JSOp::NewContent, BaselineICFallbackKind::CallConstructing);
347
348 setKind(JSOp::SpreadCall, BaselineICFallbackKind::SpreadCall);
349 setKind(JSOp::SpreadEval, BaselineICFallbackKind::SpreadCall);
350 setKind(JSOp::StrictSpreadEval, BaselineICFallbackKind::SpreadCall);
351
352 setKind(JSOp::SpreadSuperCall,
353 BaselineICFallbackKind::SpreadCallConstructing);
354 setKind(JSOp::SpreadNew, BaselineICFallbackKind::SpreadCallConstructing);
355
356 setKind(JSOp::Instanceof, BaselineICFallbackKind::InstanceOf);
357
358 setKind(JSOp::Typeof, BaselineICFallbackKind::TypeOf);
359 setKind(JSOp::TypeofExpr, BaselineICFallbackKind::TypeOf);
360
361 setKind(JSOp::TypeofEq, BaselineICFallbackKind::TypeOfEq);
362
363 setKind(JSOp::ToPropertyKey, BaselineICFallbackKind::ToPropertyKey);
364
365 setKind(JSOp::Iter, BaselineICFallbackKind::GetIterator);
366
367 setKind(JSOp::OptimizeSpreadCall,
368 BaselineICFallbackKind::OptimizeSpreadCall);
369
370 setKind(JSOp::Rest, BaselineICFallbackKind::Rest);
371
372 setKind(JSOp::CloseIter, BaselineICFallbackKind::CloseIter);
373 setKind(JSOp::OptimizeGetIterator,
374 BaselineICFallbackKind::OptimizeGetIterator);
375 }
376};
377
378static constexpr OpToFallbackKindTable FallbackKindTable;
379
380void ICScript::initICEntries(JSContext* cx, JSScript* script) {
381 MOZ_ASSERT(cx->zone()->jitZone())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cx->zone()->jitZone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(cx->zone()->jitZone())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("cx->zone()->jitZone()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "cx->zone()->jitZone()"
")"); do { *((volatile int*)__null) = 381; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
382 MOZ_ASSERT(jit::IsBaselineInterpreterEnabled() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(jit::IsBaselineInterpreterEnabled() || jit::IsPortableBaselineInterpreterEnabled
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(jit::IsBaselineInterpreterEnabled() || jit::IsPortableBaselineInterpreterEnabled
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("jit::IsBaselineInterpreterEnabled() || jit::IsPortableBaselineInterpreterEnabled()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jit::IsBaselineInterpreterEnabled() || jit::IsPortableBaselineInterpreterEnabled()"
")"); do { *((volatile int*)__null) = 383; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
383 jit::IsPortableBaselineInterpreterEnabled())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(jit::IsBaselineInterpreterEnabled() || jit::IsPortableBaselineInterpreterEnabled
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(jit::IsBaselineInterpreterEnabled() || jit::IsPortableBaselineInterpreterEnabled
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("jit::IsBaselineInterpreterEnabled() || jit::IsPortableBaselineInterpreterEnabled()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jit::IsBaselineInterpreterEnabled() || jit::IsPortableBaselineInterpreterEnabled()"
")"); do { *((volatile int*)__null) = 383; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
384
385 MOZ_ASSERT(numICEntries() == script->numICEntries())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(numICEntries() == script->numICEntries())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(numICEntries() == script->numICEntries()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("numICEntries() == script->numICEntries()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 385); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numICEntries() == script->numICEntries()"
")"); do { *((volatile int*)__null) = 385; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
386
387 // Index of the next ICEntry to initialize.
388 uint32_t icEntryIndex = 0;
389
390 const BaselineICFallbackCode& fallbackCode =
391 cx->runtime()->jitRuntime()->baselineICFallbackCode();
392
393 // For JOF_IC ops: initialize ICEntries and fallback stubs.
394 for (BytecodeLocation loc : js::AllBytecodesIterable(script)) {
395 JSOp op = loc.getOp();
396
397 // Assert the frontend stored the correct IC index in jump target ops.
398 MOZ_ASSERT_IF(BytecodeIsJumpTarget(op), loc.icIndex() == icEntryIndex)do { if (BytecodeIsJumpTarget(op)) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(loc.icIndex() ==
icEntryIndex)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(loc.icIndex() == icEntryIndex))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("loc.icIndex() == icEntryIndex"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 398); AnnotateMozCrashReason("MOZ_ASSERT" "(" "loc.icIndex() == icEntryIndex"
")"); do { *((volatile int*)__null) = 398; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
399
400 uint8_t tableValue = FallbackKindTable.lookup(op);
401
402 if (tableValue == OpToFallbackKindTable::NoICValue) {
403 MOZ_ASSERT(!BytecodeOpHasIC(op),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!BytecodeOpHasIC(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!BytecodeOpHasIC(op)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!BytecodeOpHasIC(op)"
" (" "Missing entry in OpToFallbackKindTable for JOF_IC op" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!BytecodeOpHasIC(op)"
") (" "Missing entry in OpToFallbackKindTable for JOF_IC op"
")"); do { *((volatile int*)__null) = 404; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
404 "Missing entry in OpToFallbackKindTable for JOF_IC op")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!BytecodeOpHasIC(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!BytecodeOpHasIC(op)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!BytecodeOpHasIC(op)"
" (" "Missing entry in OpToFallbackKindTable for JOF_IC op" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!BytecodeOpHasIC(op)"
") (" "Missing entry in OpToFallbackKindTable for JOF_IC op"
")"); do { *((volatile int*)__null) = 404; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
405 continue;
406 }
407
408 MOZ_ASSERT(BytecodeOpHasIC(op),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(BytecodeOpHasIC(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(BytecodeOpHasIC(op)))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("BytecodeOpHasIC(op)"
" (" "Unexpected fallback kind for non-JOF_IC op" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 409); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BytecodeOpHasIC(op)"
") (" "Unexpected fallback kind for non-JOF_IC op" ")"); do {
*((volatile int*)__null) = 409; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
409 "Unexpected fallback kind for non-JOF_IC op")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(BytecodeOpHasIC(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(BytecodeOpHasIC(op)))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("BytecodeOpHasIC(op)"
" (" "Unexpected fallback kind for non-JOF_IC op" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 409); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BytecodeOpHasIC(op)"
") (" "Unexpected fallback kind for non-JOF_IC op" ")"); do {
*((volatile int*)__null) = 409; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
410
411 BaselineICFallbackKind kind = BaselineICFallbackKind(tableValue);
412 TrampolinePtr stubCode = !jit::IsPortableBaselineInterpreterEnabled()
413 ? fallbackCode.addr(kind)
414 : TrampolinePtr();
415
416 // Initialize the ICEntry and ICFallbackStub.
417 uint32_t offset = loc.bytecodeToOffset(script);
418 ICEntry& entryRef = this->icEntry(icEntryIndex);
419 ICFallbackStub* stub = fallbackStub(icEntryIndex);
420 icEntryIndex++;
421 new (&entryRef) ICEntry(stub);
422 new (stub) ICFallbackStub(offset, stubCode);
423 }
424
425 // Assert all ICEntries have been initialized.
426 MOZ_ASSERT(icEntryIndex == numICEntries())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(icEntryIndex == numICEntries())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(icEntryIndex == numICEntries
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("icEntryIndex == numICEntries()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 426); AnnotateMozCrashReason("MOZ_ASSERT" "(" "icEntryIndex == numICEntries()"
")"); do { *((volatile int*)__null) = 426; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
427}
428
429bool ICSupportsPolymorphicTypeData(JSOp op) {
430 MOZ_ASSERT(BytecodeOpHasIC(op))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(BytecodeOpHasIC(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(BytecodeOpHasIC(op)))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("BytecodeOpHasIC(op)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 430); AnnotateMozCrashReason("MOZ_ASSERT" "(" "BytecodeOpHasIC(op)"
")"); do { *((volatile int*)__null) = 430; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
431 BaselineICFallbackKind kind =
432 BaselineICFallbackKind(FallbackKindTable.lookup(op));
433 switch (kind) {
434 case BaselineICFallbackKind::ToBool:
435 case BaselineICFallbackKind::TypeOf:
436 case BaselineICFallbackKind::TypeOfEq:
437 return true;
438 default:
439 return false;
440 }
441}
442
443bool ICCacheIRStub::makesGCCalls() const { return stubInfo()->makesGCCalls(); }
444
445void ICFallbackStub::trackNotAttached() { state().trackNotAttached(); }
446
447// When we enter a baseline fallback stub, if a Warp compilation
448// exists that transpiled that IC, we notify that compilation. This
449// helps the bailout code tell whether a bailing instruction hoisted
450// by LICM would have been executed anyway.
451static void MaybeNotifyWarp(JSScript* script, ICFallbackStub* stub) {
452 if (stub->state().usedByTranspiler() && script->hasIonScript()) {
453 script->ionScript()->noteBaselineFallback();
454 }
455}
456
457void ICCacheIRStub::trace(JSTracer* trc) {
458 if (hasJitCode()) {
459 JitCode* stubJitCode = jitCode();
460 TraceManuallyBarrieredEdge(trc, &stubJitCode, "baseline-ic-stub-code");
461 }
462
463 TraceCacheIRStub(trc, this, stubInfo());
464}
465
466bool ICCacheIRStub::traceWeak(JSTracer* trc) {
467 return TraceWeakCacheIRStub(trc, this, stubInfo());
468}
469
470static void MaybeTransition(JSContext* cx, BaselineFrame* frame,
471 ICFallbackStub* stub) {
472 if (stub->state().shouldTransition()) {
473 if (!TryFoldingStubs(cx, stub, frame->script(), frame->icScript())) {
474 cx->recoverFromOutOfMemory();
475 }
476 if (stub->state().maybeTransition()) {
477 ICEntry* icEntry = frame->icScript()->icEntryForStub(stub);
478#ifdef JS_CACHEIR_SPEW1
479 if (cx->spewer().enabled(cx, frame->script(),
480 SpewChannel::CacheIRHealthReport)) {
481 CacheIRHealth cih;
482 RootedScript script(cx, frame->script());
483 cih.healthReportForIC(cx, icEntry, stub, script,
484 SpewContext::Transition);
485 }
486#endif
487 stub->discardStubs(cx->zone(), icEntry);
488 }
489 }
490}
491
492// This helper handles ICState updates/transitions while attaching CacheIR
493// stubs.
494template <typename IRGenerator, typename... Args>
495static void TryAttachStub(const char* name, JSContext* cx, BaselineFrame* frame,
496 ICFallbackStub* stub, Args&&... args) {
497 MaybeTransition(cx, frame, stub);
498
499 if (stub->state().canAttachStub()) {
500 RootedScript script(cx, frame->script());
501 ICScript* icScript = frame->icScript();
502 jsbytecode* pc = StubOffsetToPc(stub, script);
503 bool attached = false;
504 IRGenerator gen(cx, script, pc, stub->state(), std::forward<Args>(args)...);
505 switch (gen.tryAttachStub()) {
506 case AttachDecision::Attach: {
507 ICAttachResult result =
508 AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
509 script, icScript, stub, gen.stubName());
510 if (result == ICAttachResult::Attached) {
511 attached = true;
512 JitSpew(JitSpew_BaselineIC, " Attached %s CacheIR stub", name);
513 }
514 } break;
515 case AttachDecision::NoAction:
516 break;
517 case AttachDecision::TemporarilyUnoptimizable:
518 case AttachDecision::Deferred:
519 MOZ_ASSERT_UNREACHABLE("Not expected in generic TryAttachStub")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Not expected in generic TryAttachStub" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Not expected in generic TryAttachStub"
")"); do { *((volatile int*)__null) = 519; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
520 break;
521 }
522 if (!attached) {
523 stub->trackNotAttached();
524 }
525 }
526}
527
528void ICFallbackStub::unlinkStub(Zone* zone, ICEntry* icEntry,
529 ICCacheIRStub* prev, ICCacheIRStub* stub) {
530 // We are removing edges from ICStub to gcthings. Perform a barrier to let the
531 // GC know about those edges.
532 PreWriteBarrier(zone, stub);
533
534 unlinkStubUnbarriered(icEntry, prev, stub);
535}
536
537void ICFallbackStub::unlinkStubUnbarriered(ICEntry* icEntry,
538 ICCacheIRStub* prev,
539 ICCacheIRStub* stub) {
540 if (prev) {
541 MOZ_ASSERT(prev->next() == stub)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prev->next() == stub)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prev->next() == stub))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("prev->next() == stub"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 541); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prev->next() == stub"
")"); do { *((volatile int*)__null) = 541; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
542 prev->setNext(stub->next());
543 } else {
544 MOZ_ASSERT(icEntry->firstStub() == stub)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(icEntry->firstStub() == stub)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(icEntry->firstStub() == stub
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"icEntry->firstStub() == stub", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 544); AnnotateMozCrashReason("MOZ_ASSERT" "(" "icEntry->firstStub() == stub"
")"); do { *((volatile int*)__null) = 544; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
545 icEntry->setFirstStub(stub->next());
546 }
547
548 state_.trackUnlinkedStub();
549
550#ifdef DEBUG1
551 // Poison stub code to ensure we don't call this stub again. However, if
552 // this stub can make calls, a pointer to it may be stored in a stub frame
553 // on the stack, so we can't touch the stubCode_ or GC will crash when
554 // tracing this pointer.
555 if (!stub->makesGCCalls()) {
556 stub->stubCode_ = (uint8_t*)0xbad;
557 }
558#endif
559}
560
561void ICFallbackStub::discardStubs(Zone* zone, ICEntry* icEntry) {
562 ICStub* stub = icEntry->firstStub();
563 while (stub != this) {
564 unlinkStub(zone, icEntry, /* prev = */ nullptr, stub->toCacheIRStub());
565 stub = stub->toCacheIRStub()->next();
566 }
567 clearMayHaveFoldedStub();
568}
569
570static void InitMacroAssemblerForICStub(StackMacroAssembler& masm) {
571#ifndef JS_USE_LINK_REGISTER
572 // The first value contains the return addres,
573 // which we pull into ICTailCallReg for tail calls.
574 masm.adjustFrame(sizeof(intptr_t));
575#endif
576#ifdef JS_CODEGEN_ARM
577 masm.setSecondScratchReg(BaselineSecondScratchReg);
578#endif
579}
580
581bool FallbackICCodeCompiler::tailCallVMInternal(MacroAssembler& masm,
582 VMFunctionId id) {
583 TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
584 const VMFunctionData& fun = GetVMFunction(id);
585 uint32_t argSize = fun.explicitStackSlots() * sizeof(void*);
586 EmitBaselineTailCallVM(code, masm, argSize);
587 return true;
588}
589
590bool FallbackICCodeCompiler::callVMInternal(MacroAssembler& masm,
591 VMFunctionId id) {
592 MOZ_ASSERT(inStubFrame_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inStubFrame_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(inStubFrame_))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("inStubFrame_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 592); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inStubFrame_"
")"); do { *((volatile int*)__null) = 592; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
593
594 TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id);
595
596 EmitBaselineCallVM(code, masm);
597 return true;
598}
599
600template <typename Fn, Fn fn>
601bool FallbackICCodeCompiler::callVM(MacroAssembler& masm) {
602 VMFunctionId id = VMFunctionToId<Fn, fn>::id;
603 return callVMInternal(masm, id);
604}
605
606template <typename Fn, Fn fn>
607bool FallbackICCodeCompiler::tailCallVM(MacroAssembler& masm) {
608 VMFunctionId id = VMFunctionToId<Fn, fn>::id;
609 return tailCallVMInternal(masm, id);
610}
611
612void FallbackICCodeCompiler::enterStubFrame(MacroAssembler& masm,
613 Register scratch) {
614 EmitBaselineEnterStubFrame(masm, scratch);
615#ifdef DEBUG1
616 framePushedAtEnterStubFrame_ = masm.framePushed();
617#endif
618
619 MOZ_ASSERT(!inStubFrame_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inStubFrame_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inStubFrame_))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!inStubFrame_",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 619); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inStubFrame_"
")"); do { *((volatile int*)__null) = 619; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
620 inStubFrame_ = true;
621
622#ifdef DEBUG1
623 entersStubFrame_ = true;
624#endif
625}
626
627void FallbackICCodeCompiler::assumeStubFrame() {
628 MOZ_ASSERT(!inStubFrame_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!inStubFrame_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!inStubFrame_))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!inStubFrame_",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!inStubFrame_"
")"); do { *((volatile int*)__null) = 628; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
629 inStubFrame_ = true;
630
631#ifdef DEBUG1
632 entersStubFrame_ = true;
633
634 // |framePushed| isn't tracked precisely in ICStubs, so simply assume it to
635 // be the stub frame layout and the pushed ICStub* so that assertions don't
636 // fail in leaveStubFrame
637 framePushedAtEnterStubFrame_ =
638 BaselineStubFrameLayout::Size() + sizeof(ICStub*);
639#endif
640}
641
642void FallbackICCodeCompiler::leaveStubFrame(MacroAssembler& masm) {
643 MOZ_ASSERT(entersStubFrame_ && inStubFrame_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(entersStubFrame_ && inStubFrame_)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(entersStubFrame_ && inStubFrame_))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("entersStubFrame_ && inStubFrame_"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 643); AnnotateMozCrashReason("MOZ_ASSERT" "(" "entersStubFrame_ && inStubFrame_"
")"); do { *((volatile int*)__null) = 643; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
644 inStubFrame_ = false;
645
646#ifdef DEBUG1
647 masm.setFramePushed(framePushedAtEnterStubFrame_);
648#endif
649 EmitBaselineLeaveStubFrame(masm);
650}
651
652void FallbackICCodeCompiler::pushStubPayload(MacroAssembler& masm,
653 Register scratch) {
654 if (inStubFrame_) {
655 masm.loadPtr(Address(FramePointer, 0), scratch);
656 masm.pushBaselineFramePtr(scratch, scratch);
657 } else {
658 masm.pushBaselineFramePtr(FramePointer, scratch);
659 }
660}
661
662void FallbackICCodeCompiler::PushStubPayload(MacroAssembler& masm,
663 Register scratch) {
664 pushStubPayload(masm, scratch);
665 masm.adjustFrame(sizeof(intptr_t));
666}
667
668//
669// ToBool_Fallback
670//
671
672bool DoToBoolFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
673 HandleValue arg, MutableHandleValue ret) {
674 stub->incrementEnteredCount();
675 MaybeNotifyWarp(frame->outerScript(), stub);
676 FallbackICSpew(cx, stub, "ToBool");
677
678 TryAttachStub<ToBoolIRGenerator>("ToBool", cx, frame, stub, arg);
679
680 bool cond = ToBoolean(arg);
681 ret.setBoolean(cond);
682
683 return true;
684}
685
686bool FallbackICCodeCompiler::emit_ToBool() {
687 static_assert(R0 == JSReturnOperand);
688
689 // Restore the tail call register.
690 EmitRestoreTailCallReg(masm);
691
692 // Push arguments.
693 masm.pushValue(R0);
694 masm.push(ICStubReg);
695 pushStubPayload(masm, R0.scratchReg());
696
697 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
698 MutableHandleValue);
699 return tailCallVM<Fn, DoToBoolFallback>(masm);
700}
701
702//
703// GetElem_Fallback
704//
705
706bool DoGetElemFallback(JSContext* cx, BaselineFrame* frame,
707 ICFallbackStub* stub, HandleValue lhs, HandleValue rhs,
708 MutableHandleValue res) {
709 stub->incrementEnteredCount();
710 MaybeNotifyWarp(frame->outerScript(), stub);
711 FallbackICSpew(cx, stub, "GetElem");
712
713#ifdef DEBUG1
714 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
715 MOZ_ASSERT(JSOp(*pc) == JSOp::GetElem)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JSOp(*pc) == JSOp::GetElem)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JSOp(*pc) == JSOp::GetElem))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("JSOp(*pc) == JSOp::GetElem"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 715); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JSOp(*pc) == JSOp::GetElem"
")"); do { *((volatile int*)__null) = 715; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
716#endif
717
718 TryAttachStub<GetPropIRGenerator>("GetElem", cx, frame, stub,
719 CacheKind::GetElem, lhs, rhs);
720
721 if (!GetElementOperation(cx, lhs, rhs, res)) {
722 return false;
723 }
724
725 return true;
726}
727
728bool DoGetElemSuperFallback(JSContext* cx, BaselineFrame* frame,
729 ICFallbackStub* stub, HandleValue lhs,
730 HandleValue rhs, HandleValue receiver,
731 MutableHandleValue res) {
732 stub->incrementEnteredCount();
733 MaybeNotifyWarp(frame->outerScript(), stub);
734
735 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
736
737 JSOp op = JSOp(*pc);
738 FallbackICSpew(cx, stub, "GetElemSuper(%s)", CodeName(op));
739
740 MOZ_ASSERT(op == JSOp::GetElemSuper)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::GetElemSuper)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::GetElemSuper))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::GetElemSuper"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 740); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetElemSuper"
")"); do { *((volatile int*)__null) = 740; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
741
742 // |lhs| is [[HomeObject]].[[Prototype]] which must be an Object or null.
743 MOZ_ASSERT(lhs.isObjectOrNull())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs.isObjectOrNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs.isObjectOrNull()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("lhs.isObjectOrNull()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 743); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs.isObjectOrNull()"
")"); do { *((volatile int*)__null) = 743; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
744
745 int lhsIndex = -1;
746 RootedObject lhsObj(
747 cx, ToObjectFromStackForPropertyAccess(cx, lhs, lhsIndex, rhs));
748 if (!lhsObj) {
749 return false;
750 }
751
752 TryAttachStub<GetPropIRGenerator>("GetElemSuper", cx, frame, stub,
753 CacheKind::GetElemSuper, lhs, rhs);
754
755 return GetObjectElementOperation(cx, op, lhsObj, receiver, rhs, res);
756}
757
758bool FallbackICCodeCompiler::emitGetElem(bool hasReceiver) {
759 static_assert(R0 == JSReturnOperand);
760
761 // Restore the tail call register.
762 EmitRestoreTailCallReg(masm);
763
764 // Super property getters use a |this| that differs from base object
765 if (hasReceiver) {
766 // State: receiver in R0, index in R1, obj on the stack
767
768 // Ensure stack is fully synced for the expression decompiler.
769 // We need: receiver, index, obj
770 masm.pushValue(R0);
771 masm.pushValue(R1);
772 masm.pushValue(Address(masm.getStackPointer(), sizeof(Value) * 2));
773
774 // Push arguments.
775 masm.pushValue(R0); // Receiver
776 masm.pushValue(R1); // Index
777 masm.pushValue(Address(masm.getStackPointer(), sizeof(Value) * 5)); // Obj
778 masm.push(ICStubReg);
779 masm.pushBaselineFramePtr(FramePointer, R0.scratchReg());
780
781 using Fn =
782 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
783 HandleValue, HandleValue, MutableHandleValue);
784 if (!tailCallVM<Fn, DoGetElemSuperFallback>(masm)) {
785 return false;
786 }
787 } else {
788 // Ensure stack is fully synced for the expression decompiler.
789 masm.pushValue(R0);
790 masm.pushValue(R1);
791
792 // Push arguments.
793 masm.pushValue(R1);
794 masm.pushValue(R0);
795 masm.push(ICStubReg);
796 masm.pushBaselineFramePtr(FramePointer, R0.scratchReg());
797
798 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*,
799 HandleValue, HandleValue, MutableHandleValue);
800 if (!tailCallVM<Fn, DoGetElemFallback>(masm)) {
801 return false;
802 }
803 }
804
805 // This is the resume point used when bailout rewrites call stack to undo
806 // Ion inlined frames. The return address pushed onto reconstructed stack
807 // will point here.
808 assumeStubFrame();
809 if (hasReceiver) {
810 code.initBailoutReturnOffset(BailoutReturnKind::GetElemSuper,
811 masm.currentOffset());
812 } else {
813 code.initBailoutReturnOffset(BailoutReturnKind::GetElem,
814 masm.currentOffset());
815 }
816
817 leaveStubFrame(masm);
818
819 EmitReturnFromIC(masm);
820 return true;
821}
822
823bool FallbackICCodeCompiler::emit_GetElem() {
824 return emitGetElem(/* hasReceiver = */ false);
825}
826
827bool FallbackICCodeCompiler::emit_GetElemSuper() {
828 return emitGetElem(/* hasReceiver = */ true);
829}
830
831bool DoSetElemFallback(JSContext* cx, BaselineFrame* frame,
832 ICFallbackStub* stub, Value* stack, HandleValue objv,
833 HandleValue index, HandleValue rhs) {
834 using DeferType = SetPropIRGenerator::DeferType;
835
836 stub->incrementEnteredCount();
837 MaybeNotifyWarp(frame->outerScript(), stub);
838
839 RootedScript script(cx, frame->script());
840 RootedScript outerScript(cx, script);
841 jsbytecode* pc = StubOffsetToPc(stub, script);
842 JSOp op = JSOp(*pc);
843 FallbackICSpew(cx, stub, "SetElem(%s)", CodeName(JSOp(*pc)));
844
845 MOZ_ASSERT(op == JSOp::SetElem || op == JSOp::StrictSetElem ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetElem || op == JSOp::StrictSetElem || op
== JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp
::InitLockedElem || op == JSOp::InitElemInc)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::SetElem || op ==
JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem
|| op == JSOp::InitLockedElem || op == JSOp::InitElemInc))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::SetElem || op == JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp::InitLockedElem || op == JSOp::InitElemInc"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 847); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetElem || op == JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp::InitLockedElem || op == JSOp::InitElemInc"
")"); do { *((volatile int*)__null) = 847; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
846 op == JSOp::InitElem || op == JSOp::InitHiddenElem ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetElem || op == JSOp::StrictSetElem || op
== JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp
::InitLockedElem || op == JSOp::InitElemInc)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::SetElem || op ==
JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem
|| op == JSOp::InitLockedElem || op == JSOp::InitElemInc))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::SetElem || op == JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp::InitLockedElem || op == JSOp::InitElemInc"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 847); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetElem || op == JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp::InitLockedElem || op == JSOp::InitElemInc"
")"); do { *((volatile int*)__null) = 847; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
847 op == JSOp::InitLockedElem || op == JSOp::InitElemInc)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetElem || op == JSOp::StrictSetElem || op
== JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp
::InitLockedElem || op == JSOp::InitElemInc)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::SetElem || op ==
JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem
|| op == JSOp::InitLockedElem || op == JSOp::InitElemInc))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::SetElem || op == JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp::InitLockedElem || op == JSOp::InitElemInc"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 847); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetElem || op == JSOp::StrictSetElem || op == JSOp::InitElem || op == JSOp::InitHiddenElem || op == JSOp::InitLockedElem || op == JSOp::InitElemInc"
")"); do { *((volatile int*)__null) = 847; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
848
849 int objvIndex = -3;
850 RootedObject obj(
851 cx, ToObjectFromStackForPropertyAccess(cx, objv, objvIndex, index));
852 if (!obj) {
853 return false;
854 }
855
856 Rooted<Shape*> oldShape(cx, obj->shape());
857
858 DeferType deferType = DeferType::None;
859 bool attached = false;
860
861 MaybeTransition(cx, frame, stub);
862
863 if (stub->state().canAttachStub()) {
864 ICScript* icScript = frame->icScript();
865 SetPropIRGenerator gen(cx, script, pc, CacheKind::SetElem, stub->state(),
866 objv, index, rhs);
867 switch (gen.tryAttachStub()) {
868 case AttachDecision::Attach: {
869 ICAttachResult result = AttachBaselineCacheIRStub(
870 cx, gen.writerRef(), gen.cacheKind(), frame->script(), icScript,
871 stub, gen.stubName());
872 if (result == ICAttachResult::Attached) {
873 attached = true;
874 JitSpew(JitSpew_BaselineIC, " Attached SetElem CacheIR stub");
875 }
876 } break;
877 case AttachDecision::NoAction:
878 break;
879 case AttachDecision::TemporarilyUnoptimizable:
880 attached = true;
881 break;
882 case AttachDecision::Deferred:
883 deferType = gen.deferType();
884 MOZ_ASSERT(deferType != DeferType::None)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(deferType != DeferType::None)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(deferType != DeferType::None
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"deferType != DeferType::None", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 884); AnnotateMozCrashReason("MOZ_ASSERT" "(" "deferType != DeferType::None"
")"); do { *((volatile int*)__null) = 884; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
885 break;
886 }
887 if (deferType == DeferType::None && !attached) {
888 stub->trackNotAttached();
889 }
890 }
891
892 if (op == JSOp::InitElem || op == JSOp::InitHiddenElem ||
893 op == JSOp::InitLockedElem) {
894 if (!InitElemOperation(cx, pc, obj, index, rhs)) {
895 return false;
896 }
897 } else if (op == JSOp::InitElemInc) {
898 if (!InitElemIncOperation(cx, obj.as<ArrayObject>(), index.toInt32(),
899 rhs)) {
900 return false;
901 }
902 } else {
903 if (!SetObjectElementWithReceiver(cx, obj, index, rhs, objv,
904 JSOp(*pc) == JSOp::StrictSetElem)) {
905 return false;
906 }
907 }
908
909 if (stack) {
910 // Overwrite the object on the stack (pushed for the decompiler) with the
911 // rhs.
912 MOZ_ASSERT(stack[2] == objv)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(stack[2] == objv)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(stack[2] == objv))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("stack[2] == objv"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "stack[2] == objv"
")"); do { *((volatile int*)__null) = 912; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
913 stack[2] = rhs;
914 }
915
916 if (attached) {
917 return true;
918 }
919
920 // The SetObjectElement call might have entered this IC recursively, so try
921 // to transition.
922 MaybeTransition(cx, frame, stub);
923
924 bool canAttachStub = stub->state().canAttachStub();
925
926 if (deferType != DeferType::None && canAttachStub) {
927 SetPropIRGenerator gen(cx, script, pc, CacheKind::SetElem, stub->state(),
928 objv, index, rhs);
929
930 MOZ_ASSERT(deferType == DeferType::AddSlot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(deferType == DeferType::AddSlot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(deferType == DeferType::AddSlot
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"deferType == DeferType::AddSlot", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 930); AnnotateMozCrashReason("MOZ_ASSERT" "(" "deferType == DeferType::AddSlot"
")"); do { *((volatile int*)__null) = 930; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
931 AttachDecision decision = gen.tryAttachAddSlotStub(oldShape);
932
933 switch (decision) {
934 case AttachDecision::Attach: {
935 ICScript* icScript = frame->icScript();
936 ICAttachResult result = AttachBaselineCacheIRStub(
937 cx, gen.writerRef(), gen.cacheKind(), frame->script(), icScript,
938 stub, gen.stubName());
939 if (result == ICAttachResult::Attached) {
940 attached = true;
941 JitSpew(JitSpew_BaselineIC, " Attached SetElem CacheIR stub");
942 }
943 } break;
944 case AttachDecision::NoAction:
945 gen.trackAttached(IRGenerator::NotAttached);
946 break;
947 case AttachDecision::TemporarilyUnoptimizable:
948 case AttachDecision::Deferred:
949 MOZ_ASSERT_UNREACHABLE("Invalid attach result")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Invalid attach result" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 949); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Invalid attach result" ")"); do {
*((volatile int*)__null) = 949; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
950 break;
951 }
952 if (!attached) {
953 stub->trackNotAttached();
954 }
955 }
956
957 return true;
958}
959
960bool FallbackICCodeCompiler::emit_SetElem() {
961 static_assert(R0 == JSReturnOperand);
962
963 EmitRestoreTailCallReg(masm);
964
965 // State: R0: object, R1: index, stack: rhs.
966 // For the decompiler, the stack has to be: object, index, rhs,
967 // so we push the index, then overwrite the rhs Value with R0
968 // and push the rhs value.
969 masm.pushValue(R1);
970 masm.loadValue(Address(masm.getStackPointer(), sizeof(Value)), R1);
971 masm.storeValue(R0, Address(masm.getStackPointer(), sizeof(Value)));
972 masm.pushValue(R1);
973
974 // Push arguments.
975 masm.pushValue(R1); // RHS
976
977 // Push index. On x86 and ARM two push instructions are emitted so use a
978 // separate register to store the old stack pointer.
979 masm.moveStackPtrTo(R1.scratchReg());
980 masm.pushValue(Address(R1.scratchReg(), 2 * sizeof(Value)));
981 masm.pushValue(R0); // Object.
982
983 // Push pointer to stack values, so that the stub can overwrite the object
984 // (pushed for the decompiler) with the rhs.
985 masm.computeEffectiveAddress(
986 Address(masm.getStackPointer(), 3 * sizeof(Value)), R0.scratchReg());
987 masm.push(R0.scratchReg());
988
989 masm.push(ICStubReg);
990 pushStubPayload(masm, R0.scratchReg());
991
992 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, Value*,
993 HandleValue, HandleValue, HandleValue);
994 return tailCallVM<Fn, DoSetElemFallback>(masm);
995}
996
997//
998// In_Fallback
999//
1000
1001bool DoInFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
1002 HandleValue key, HandleValue objValue,
1003 MutableHandleValue res) {
1004 stub->incrementEnteredCount();
1005 MaybeNotifyWarp(frame->outerScript(), stub);
1006 FallbackICSpew(cx, stub, "In");
1007
1008 if (!objValue.isObject()) {
1009 ReportInNotObjectError(cx, key, objValue);
1010 return false;
1011 }
1012
1013 TryAttachStub<HasPropIRGenerator>("In", cx, frame, stub, CacheKind::In, key,
1014 objValue);
1015
1016 RootedObject obj(cx, &objValue.toObject());
1017 bool cond = false;
1018 if (!OperatorIn(cx, key, obj, &cond)) {
1019 return false;
1020 }
1021 res.setBoolean(cond);
1022
1023 return true;
1024}
1025
1026bool FallbackICCodeCompiler::emit_In() {
1027 EmitRestoreTailCallReg(masm);
1028
1029 // Sync for the decompiler.
1030 masm.pushValue(R0);
1031 masm.pushValue(R1);
1032
1033 // Push arguments.
1034 masm.pushValue(R1);
1035 masm.pushValue(R0);
1036 masm.push(ICStubReg);
1037 pushStubPayload(masm, R0.scratchReg());
1038
1039 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1040 HandleValue, MutableHandleValue);
1041 return tailCallVM<Fn, DoInFallback>(masm);
1042}
1043
1044//
1045// HasOwn_Fallback
1046//
1047
1048bool DoHasOwnFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
1049 HandleValue keyValue, HandleValue objValue,
1050 MutableHandleValue res) {
1051 stub->incrementEnteredCount();
1052 MaybeNotifyWarp(frame->outerScript(), stub);
1053 FallbackICSpew(cx, stub, "HasOwn");
1054
1055 TryAttachStub<HasPropIRGenerator>("HasOwn", cx, frame, stub,
1056 CacheKind::HasOwn, keyValue, objValue);
1057
1058 bool found;
1059 if (!HasOwnProperty(cx, objValue, keyValue, &found)) {
1060 return false;
1061 }
1062
1063 res.setBoolean(found);
1064 return true;
1065}
1066
1067bool FallbackICCodeCompiler::emit_HasOwn() {
1068 EmitRestoreTailCallReg(masm);
1069
1070 // Sync for the decompiler.
1071 masm.pushValue(R0);
1072 masm.pushValue(R1);
1073
1074 // Push arguments.
1075 masm.pushValue(R1);
1076 masm.pushValue(R0);
1077 masm.push(ICStubReg);
1078 pushStubPayload(masm, R0.scratchReg());
1079
1080 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1081 HandleValue, MutableHandleValue);
1082 return tailCallVM<Fn, DoHasOwnFallback>(masm);
1083}
1084
1085//
1086// CheckPrivate_Fallback
1087//
1088
1089bool DoCheckPrivateFieldFallback(JSContext* cx, BaselineFrame* frame,
1090 ICFallbackStub* stub, HandleValue objValue,
1091 HandleValue keyValue, MutableHandleValue res) {
1092 stub->incrementEnteredCount();
1093 MaybeNotifyWarp(frame->outerScript(), stub);
1094
1095 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
1096
1097 FallbackICSpew(cx, stub, "CheckPrivateField");
1098
1099 MOZ_ASSERT(keyValue.isSymbol() && keyValue.toSymbol()->isPrivateName())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(keyValue.isSymbol() && keyValue.toSymbol()->
isPrivateName())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(keyValue.isSymbol() &&
keyValue.toSymbol()->isPrivateName()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("keyValue.isSymbol() && keyValue.toSymbol()->isPrivateName()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "keyValue.isSymbol() && keyValue.toSymbol()->isPrivateName()"
")"); do { *((volatile int*)__null) = 1099; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1100
1101 TryAttachStub<CheckPrivateFieldIRGenerator>("CheckPrivate", cx, frame, stub,
1102 CacheKind::CheckPrivateField,
1103 keyValue, objValue);
1104
1105 bool result;
1106 if (!CheckPrivateFieldOperation(cx, pc, objValue, keyValue, &result)) {
1107 return false;
1108 }
1109
1110 res.setBoolean(result);
1111 return true;
1112}
1113
1114bool FallbackICCodeCompiler::emit_CheckPrivateField() {
1115 EmitRestoreTailCallReg(masm);
1116
1117 // Sync for the decompiler.
1118 masm.pushValue(R0);
1119 masm.pushValue(R1);
1120
1121 // Push arguments.
1122 masm.pushValue(R1);
1123 masm.pushValue(R0);
1124 masm.push(ICStubReg);
1125 pushStubPayload(masm, R0.scratchReg());
1126
1127 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1128 HandleValue, MutableHandleValue);
1129 return tailCallVM<Fn, DoCheckPrivateFieldFallback>(masm);
1130}
1131
1132//
1133// GetName_Fallback
1134//
1135
1136bool DoGetNameFallback(JSContext* cx, BaselineFrame* frame,
1137 ICFallbackStub* stub, HandleObject envChain,
1138 MutableHandleValue res) {
1139 stub->incrementEnteredCount();
1140 MaybeNotifyWarp(frame->outerScript(), stub);
1141
1142 RootedScript script(cx, frame->script());
1143 jsbytecode* pc = StubOffsetToPc(stub, script);
1144 mozilla::DebugOnly<JSOp> op = JSOp(*pc);
1145 FallbackICSpew(cx, stub, "GetName(%s)", CodeName(JSOp(*pc)));
1146
1147 MOZ_ASSERT(op == JSOp::GetName || op == JSOp::GetGName)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::GetName || op == JSOp::GetGName)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(op == JSOp::GetName || op == JSOp::GetGName))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("op == JSOp::GetName || op == JSOp::GetGName"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetName || op == JSOp::GetGName"
")"); do { *((volatile int*)__null) = 1147; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1148
1149 Rooted<PropertyName*> name(cx, script->getName(pc));
1150
1151 TryAttachStub<GetNameIRGenerator>("GetName", cx, frame, stub, envChain, name);
1152
1153 static_assert(JSOpLength_GetGName == JSOpLength_GetName,
1154 "Otherwise our check for JSOp::Typeof isn't ok");
1155 if (IsTypeOfNameOp(JSOp(pc[JSOpLength_GetGName]))) {
1156 if (!GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, res)) {
1157 return false;
1158 }
1159 } else {
1160 if (!GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, res)) {
1161 return false;
1162 }
1163 }
1164
1165 return true;
1166}
1167
1168bool FallbackICCodeCompiler::emit_GetName() {
1169 static_assert(R0 == JSReturnOperand);
1170
1171 EmitRestoreTailCallReg(masm);
1172
1173 masm.push(R0.scratchReg());
1174 masm.push(ICStubReg);
1175 pushStubPayload(masm, R0.scratchReg());
1176
1177 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleObject,
1178 MutableHandleValue);
1179 return tailCallVM<Fn, DoGetNameFallback>(masm);
1180}
1181
1182//
1183// BindName_Fallback
1184//
1185
1186bool DoBindNameFallback(JSContext* cx, BaselineFrame* frame,
1187 ICFallbackStub* stub, HandleObject envChain,
1188 MutableHandleValue res) {
1189 stub->incrementEnteredCount();
1190 MaybeNotifyWarp(frame->outerScript(), stub);
1191
1192 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
1193 JSOp op = JSOp(*pc);
1194 FallbackICSpew(cx, stub, "BindName(%s)", CodeName(JSOp(*pc)));
1195
1196 MOZ_ASSERT(op == JSOp::BindName || op == JSOp::BindUnqualifiedName ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::BindName || op == JSOp::BindUnqualifiedName
|| op == JSOp::BindUnqualifiedGName)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::BindName || op ==
JSOp::BindUnqualifiedName || op == JSOp::BindUnqualifiedGName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"op == JSOp::BindName || op == JSOp::BindUnqualifiedName || op == JSOp::BindUnqualifiedGName"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1197); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::BindName || op == JSOp::BindUnqualifiedName || op == JSOp::BindUnqualifiedGName"
")"); do { *((volatile int*)__null) = 1197; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1197 op == JSOp::BindUnqualifiedGName)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::BindName || op == JSOp::BindUnqualifiedName
|| op == JSOp::BindUnqualifiedGName)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::BindName || op ==
JSOp::BindUnqualifiedName || op == JSOp::BindUnqualifiedGName
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"op == JSOp::BindName || op == JSOp::BindUnqualifiedName || op == JSOp::BindUnqualifiedGName"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1197); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::BindName || op == JSOp::BindUnqualifiedName || op == JSOp::BindUnqualifiedGName"
")"); do { *((volatile int*)__null) = 1197; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1198
1199 Rooted<PropertyName*> name(cx, frame->script()->getName(pc));
1200
1201 TryAttachStub<BindNameIRGenerator>("BindName", cx, frame, stub, envChain,
1202 name);
1203
1204 JSObject* env;
1205 if (op == JSOp::BindName) {
1206 env = LookupNameWithGlobalDefault(cx, name, envChain);
1207 } else {
1208 env = LookupNameUnqualified(cx, name, envChain);
1209 }
1210 if (!env) {
1211 return false;
1212 }
1213
1214 res.setObject(*env);
1215 return true;
1216}
1217
1218bool FallbackICCodeCompiler::emit_BindName() {
1219 static_assert(R0 == JSReturnOperand);
1220
1221 EmitRestoreTailCallReg(masm);
1222
1223 masm.push(R0.scratchReg());
1224 masm.push(ICStubReg);
1225 pushStubPayload(masm, R0.scratchReg());
1226
1227 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleObject,
1228 MutableHandleValue);
1229 return tailCallVM<Fn, DoBindNameFallback>(masm);
1230}
1231
1232//
1233// GetIntrinsic_Fallback
1234//
1235
1236bool DoGetIntrinsicFallback(JSContext* cx, BaselineFrame* frame,
1237 ICFallbackStub* stub, MutableHandleValue res) {
1238 stub->incrementEnteredCount();
1239 MaybeNotifyWarp(frame->outerScript(), stub);
1240
1241 RootedScript script(cx, frame->script());
1242 jsbytecode* pc = StubOffsetToPc(stub, script);
1243 mozilla::DebugOnly<JSOp> op = JSOp(*pc);
1244 FallbackICSpew(cx, stub, "GetIntrinsic(%s)", CodeName(JSOp(*pc)));
1245
1246 MOZ_ASSERT(op == JSOp::GetIntrinsic)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::GetIntrinsic)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::GetIntrinsic))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::GetIntrinsic"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetIntrinsic"
")"); do { *((volatile int*)__null) = 1246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1247
1248 if (!GetIntrinsicOperation(cx, script, pc, res)) {
1249 return false;
1250 }
1251
1252 TryAttachStub<GetIntrinsicIRGenerator>("GetIntrinsic", cx, frame, stub, res);
1253
1254 return true;
1255}
1256
1257bool FallbackICCodeCompiler::emit_GetIntrinsic() {
1258 EmitRestoreTailCallReg(masm);
1259
1260 masm.push(ICStubReg);
1261 pushStubPayload(masm, R0.scratchReg());
1262
1263 using Fn =
1264 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, MutableHandleValue);
1265 return tailCallVM<Fn, DoGetIntrinsicFallback>(masm);
1266}
1267
1268//
1269// GetProp_Fallback
1270//
1271
1272bool DoGetPropFallback(JSContext* cx, BaselineFrame* frame,
1273 ICFallbackStub* stub, MutableHandleValue val,
1274 MutableHandleValue res) {
1275 stub->incrementEnteredCount();
1276 MaybeNotifyWarp(frame->outerScript(), stub);
1277
1278 RootedScript script(cx, frame->script());
1279 jsbytecode* pc = StubOffsetToPc(stub, script);
1280 JSOp op = JSOp(*pc);
1281 FallbackICSpew(cx, stub, "GetProp(%s)", CodeName(op));
1282
1283 MOZ_ASSERT(op == JSOp::GetProp || op == JSOp::GetBoundName)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::GetProp || op == JSOp::GetBoundName)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(op == JSOp::GetProp || op == JSOp::GetBoundName))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::GetProp || op == JSOp::GetBoundName"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1283); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetProp || op == JSOp::GetBoundName"
")"); do { *((volatile int*)__null) = 1283; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1284
1285 Rooted<PropertyName*> name(cx, script->getName(pc));
1286 RootedValue idVal(cx, StringValue(name));
1287
1288 TryAttachStub<GetPropIRGenerator>("GetProp", cx, frame, stub,
1289 CacheKind::GetProp, val, idVal);
1290
1291 if (op == JSOp::GetBoundName) {
1292 RootedObject env(cx, &val.toObject());
1293 RootedId id(cx, NameToId(name));
1294 return GetNameBoundInEnvironment(cx, env, id, res);
1295 }
1296
1297 MOZ_ASSERT(op == JSOp::GetProp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::GetProp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::GetProp))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::GetProp"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1297); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetProp"
")"); do { *((volatile int*)__null) = 1297; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1298 if (!GetProperty(cx, val, name, res)) {
1299 return false;
1300 }
1301
1302 return true;
1303}
1304
1305bool DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame,
1306 ICFallbackStub* stub, HandleValue receiver,
1307 MutableHandleValue val, MutableHandleValue res) {
1308 stub->incrementEnteredCount();
1309 MaybeNotifyWarp(frame->outerScript(), stub);
1310
1311 RootedScript script(cx, frame->script());
1312 jsbytecode* pc = StubOffsetToPc(stub, script);
1313 FallbackICSpew(cx, stub, "GetPropSuper(%s)", CodeName(JSOp(*pc)));
1314
1315 MOZ_ASSERT(JSOp(*pc) == JSOp::GetPropSuper)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JSOp(*pc) == JSOp::GetPropSuper)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JSOp(*pc) == JSOp::GetPropSuper
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"JSOp(*pc) == JSOp::GetPropSuper", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1315); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JSOp(*pc) == JSOp::GetPropSuper"
")"); do { *((volatile int*)__null) = 1315; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1316
1317 Rooted<PropertyName*> name(cx, script->getName(pc));
1318 RootedValue idVal(cx, StringValue(name));
1319
1320 // |val| is [[HomeObject]].[[Prototype]] which must be an Object or null.
1321 MOZ_ASSERT(val.isObjectOrNull())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(val.isObjectOrNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(val.isObjectOrNull()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("val.isObjectOrNull()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1321); AnnotateMozCrashReason("MOZ_ASSERT" "(" "val.isObjectOrNull()"
")"); do { *((volatile int*)__null) = 1321; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1322
1323 int valIndex = -1;
1324 RootedObject valObj(
1325 cx, ToObjectFromStackForPropertyAccess(cx, val, valIndex, name));
1326 if (!valObj) {
1327 return false;
1328 }
1329
1330 TryAttachStub<GetPropIRGenerator>("GetPropSuper", cx, frame, stub,
1331 CacheKind::GetPropSuper, val, idVal);
1332
1333 if (!GetProperty(cx, valObj, receiver, name, res)) {
1334 return false;
1335 }
1336
1337 return true;
1338}
1339
1340bool FallbackICCodeCompiler::emitGetProp(bool hasReceiver) {
1341 static_assert(R0 == JSReturnOperand);
1342
1343 EmitRestoreTailCallReg(masm);
1344
1345 // Super property getters use a |this| that differs from base object
1346 if (hasReceiver) {
1347 // Push arguments.
1348 masm.pushValue(R0);
1349 masm.pushValue(R1);
1350 masm.push(ICStubReg);
1351 masm.pushBaselineFramePtr(FramePointer, R0.scratchReg());
1352
1353 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*,
1354 HandleValue, MutableHandleValue, MutableHandleValue);
1355 if (!tailCallVM<Fn, DoGetPropSuperFallback>(masm)) {
1356 return false;
1357 }
1358 } else {
1359 // Ensure stack is fully synced for the expression decompiler.
1360 masm.pushValue(R0);
1361
1362 // Push arguments.
1363 masm.pushValue(R0);
1364 masm.push(ICStubReg);
1365 masm.pushBaselineFramePtr(FramePointer, R0.scratchReg());
1366
1367 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*,
1368 MutableHandleValue, MutableHandleValue);
1369 if (!tailCallVM<Fn, DoGetPropFallback>(masm)) {
1370 return false;
1371 }
1372 }
1373
1374 // This is the resume point used when bailout rewrites call stack to undo
1375 // Ion inlined frames. The return address pushed onto reconstructed stack
1376 // will point here.
1377 assumeStubFrame();
1378 if (hasReceiver) {
1379 code.initBailoutReturnOffset(BailoutReturnKind::GetPropSuper,
1380 masm.currentOffset());
1381 } else {
1382 code.initBailoutReturnOffset(BailoutReturnKind::GetProp,
1383 masm.currentOffset());
1384 }
1385
1386 leaveStubFrame(masm);
1387
1388 EmitReturnFromIC(masm);
1389 return true;
1390}
1391
1392bool FallbackICCodeCompiler::emit_GetProp() {
1393 return emitGetProp(/* hasReceiver = */ false);
1394}
1395
1396bool FallbackICCodeCompiler::emit_GetPropSuper() {
1397 return emitGetProp(/* hasReceiver = */ true);
1398}
1399
1400//
1401// SetProp_Fallback
1402//
1403
1404bool DoSetPropFallback(JSContext* cx, BaselineFrame* frame,
1405 ICFallbackStub* stub, Value* stack, HandleValue lhs,
1406 HandleValue rhs) {
1407 using DeferType = SetPropIRGenerator::DeferType;
1408
1409 stub->incrementEnteredCount();
1410 MaybeNotifyWarp(frame->outerScript(), stub);
1411
1412 RootedScript script(cx, frame->script());
1413 jsbytecode* pc = StubOffsetToPc(stub, script);
1414 JSOp op = JSOp(*pc);
1415 FallbackICSpew(cx, stub, "SetProp(%s)", CodeName(op));
1416
1417 MOZ_ASSERT(op == JSOp::SetProp || op == JSOp::StrictSetProp ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetProp || op == JSOp::StrictSetProp || op
== JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::
SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp
|| op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp ||
op == JSOp::InitGLexical)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::SetProp || op ==
JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName
|| op == JSOp::SetGName || op == JSOp::StrictSetGName || op ==
JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::
InitHiddenProp || op == JSOp::InitGLexical))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
")"); do { *((volatile int*)__null) = 1421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1418 op == JSOp::SetName || op == JSOp::StrictSetName ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetProp || op == JSOp::StrictSetProp || op
== JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::
SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp
|| op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp ||
op == JSOp::InitGLexical)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::SetProp || op ==
JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName
|| op == JSOp::SetGName || op == JSOp::StrictSetGName || op ==
JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::
InitHiddenProp || op == JSOp::InitGLexical))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
")"); do { *((volatile int*)__null) = 1421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1419 op == JSOp::SetGName || op == JSOp::StrictSetGName ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetProp || op == JSOp::StrictSetProp || op
== JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::
SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp
|| op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp ||
op == JSOp::InitGLexical)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::SetProp || op ==
JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName
|| op == JSOp::SetGName || op == JSOp::StrictSetGName || op ==
JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::
InitHiddenProp || op == JSOp::InitGLexical))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
")"); do { *((volatile int*)__null) = 1421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1420 op == JSOp::InitProp || op == JSOp::InitLockedProp ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetProp || op == JSOp::StrictSetProp || op
== JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::
SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp
|| op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp ||
op == JSOp::InitGLexical)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::SetProp || op ==
JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName
|| op == JSOp::SetGName || op == JSOp::StrictSetGName || op ==
JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::
InitHiddenProp || op == JSOp::InitGLexical))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
")"); do { *((volatile int*)__null) = 1421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1421 op == JSOp::InitHiddenProp || op == JSOp::InitGLexical)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetProp || op == JSOp::StrictSetProp || op
== JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::
SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp
|| op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp ||
op == JSOp::InitGLexical)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op == JSOp::SetProp || op ==
JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName
|| op == JSOp::SetGName || op == JSOp::StrictSetGName || op ==
JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::
InitHiddenProp || op == JSOp::InitGLexical))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetProp || op == JSOp::StrictSetProp || op == JSOp::SetName || op == JSOp::StrictSetName || op == JSOp::SetGName || op == JSOp::StrictSetGName || op == JSOp::InitProp || op == JSOp::InitLockedProp || op == JSOp::InitHiddenProp || op == JSOp::InitGLexical"
")"); do { *((volatile int*)__null) = 1421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1422
1423 Rooted<PropertyName*> name(cx, script->getName(pc));
1424 RootedId id(cx, NameToId(name));
1425
1426 int lhsIndex = stack ? -2 : JSDVG_IGNORE_STACK0;
1427 RootedObject obj(cx,
1428 ToObjectFromStackForPropertyAccess(cx, lhs, lhsIndex, id));
1429 if (!obj) {
1430 return false;
1431 }
1432 Rooted<Shape*> oldShape(cx, obj->shape());
1433
1434 DeferType deferType = DeferType::None;
1435 bool attached = false;
1436 MaybeTransition(cx, frame, stub);
1437
1438 if (stub->state().canAttachStub()) {
1439 RootedValue idVal(cx, StringValue(name));
1440 SetPropIRGenerator gen(cx, script, pc, CacheKind::SetProp, stub->state(),
1441 lhs, idVal, rhs);
1442 switch (gen.tryAttachStub()) {
1443 case AttachDecision::Attach: {
1444 ICScript* icScript = frame->icScript();
1445 ICAttachResult result = AttachBaselineCacheIRStub(
1446 cx, gen.writerRef(), gen.cacheKind(), frame->script(), icScript,
1447 stub, gen.stubName());
1448 if (result == ICAttachResult::Attached) {
1449 attached = true;
1450 JitSpew(JitSpew_BaselineIC, " Attached SetProp CacheIR stub");
1451 }
1452 } break;
1453 case AttachDecision::NoAction:
1454 break;
1455 case AttachDecision::TemporarilyUnoptimizable:
1456 attached = true;
1457 break;
1458 case AttachDecision::Deferred:
1459 deferType = gen.deferType();
1460 MOZ_ASSERT(deferType != DeferType::None)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(deferType != DeferType::None)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(deferType != DeferType::None
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"deferType != DeferType::None", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1460); AnnotateMozCrashReason("MOZ_ASSERT" "(" "deferType != DeferType::None"
")"); do { *((volatile int*)__null) = 1460; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1461 break;
1462 }
1463 if (deferType == DeferType::None && !attached) {
1464 stub->trackNotAttached();
1465 }
1466 }
1467
1468 if (op == JSOp::InitProp || op == JSOp::InitLockedProp ||
1469 op == JSOp::InitHiddenProp) {
1470 if (!InitPropertyOperation(cx, pc, obj, name, rhs)) {
1471 return false;
1472 }
1473 } else if (op == JSOp::SetName || op == JSOp::StrictSetName ||
1474 op == JSOp::SetGName || op == JSOp::StrictSetGName) {
1475 if (!SetNameOperation(cx, script, pc, obj, rhs)) {
1476 return false;
1477 }
1478 } else if (op == JSOp::InitGLexical) {
1479 ExtensibleLexicalEnvironmentObject* lexicalEnv;
1480 if (script->hasNonSyntacticScope()) {
1481 lexicalEnv = &NearestEnclosingExtensibleLexicalEnvironment(
1482 frame->environmentChain());
1483 } else {
1484 lexicalEnv = &cx->global()->lexicalEnvironment();
1485 }
1486 InitGlobalLexicalOperation(cx, lexicalEnv, script, pc, rhs);
1487 } else {
1488 MOZ_ASSERT(op == JSOp::SetProp || op == JSOp::StrictSetProp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::SetProp || op == JSOp::StrictSetProp)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(op == JSOp::SetProp || op == JSOp::StrictSetProp))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("op == JSOp::SetProp || op == JSOp::StrictSetProp"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1488); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetProp || op == JSOp::StrictSetProp"
")"); do { *((volatile int*)__null) = 1488; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1489
1490 ObjectOpResult result;
1491 if (!SetProperty(cx, obj, id, rhs, lhs, result) ||
1492 !result.checkStrictModeError(cx, obj, id, op == JSOp::StrictSetProp)) {
1493 return false;
1494 }
1495 }
1496
1497 if (stack) {
1498 // Overwrite the LHS on the stack (pushed for the decompiler) with the RHS.
1499 MOZ_ASSERT(stack[1] == lhs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(stack[1] == lhs)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(stack[1] == lhs))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("stack[1] == lhs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1499); AnnotateMozCrashReason("MOZ_ASSERT" "(" "stack[1] == lhs"
")"); do { *((volatile int*)__null) = 1499; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1500 stack[1] = rhs;
1501 }
1502
1503 if (attached) {
1504 return true;
1505 }
1506
1507 // The SetProperty call might have entered this IC recursively, so try
1508 // to transition.
1509 MaybeTransition(cx, frame, stub);
1510
1511 bool canAttachStub = stub->state().canAttachStub();
1512
1513 if (deferType != DeferType::None && canAttachStub) {
1514 RootedValue idVal(cx, StringValue(name));
1515 SetPropIRGenerator gen(cx, script, pc, CacheKind::SetProp, stub->state(),
1516 lhs, idVal, rhs);
1517
1518 MOZ_ASSERT(deferType == DeferType::AddSlot)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(deferType == DeferType::AddSlot)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(deferType == DeferType::AddSlot
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"deferType == DeferType::AddSlot", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1518); AnnotateMozCrashReason("MOZ_ASSERT" "(" "deferType == DeferType::AddSlot"
")"); do { *((volatile int*)__null) = 1518; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1519 AttachDecision decision = gen.tryAttachAddSlotStub(oldShape);
1520
1521 switch (decision) {
1522 case AttachDecision::Attach: {
1523 ICScript* icScript = frame->icScript();
1524 ICAttachResult result = AttachBaselineCacheIRStub(
1525 cx, gen.writerRef(), gen.cacheKind(), frame->script(), icScript,
1526 stub, gen.stubName());
1527 if (result == ICAttachResult::Attached) {
1528 attached = true;
1529 JitSpew(JitSpew_BaselineIC, " Attached SetElem CacheIR stub");
1530 }
1531 } break;
1532 case AttachDecision::NoAction:
1533 gen.trackAttached(IRGenerator::NotAttached);
1534 break;
1535 case AttachDecision::TemporarilyUnoptimizable:
1536 case AttachDecision::Deferred:
1537 MOZ_ASSERT_UNREACHABLE("Invalid attach result")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Invalid attach result" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1537); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Invalid attach result" ")"); do {
*((volatile int*)__null) = 1537; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1538 break;
1539 }
1540 if (!attached) {
1541 stub->trackNotAttached();
1542 }
1543 }
1544
1545 return true;
1546}
1547
1548bool FallbackICCodeCompiler::emit_SetProp() {
1549 static_assert(R0 == JSReturnOperand);
1550
1551 EmitRestoreTailCallReg(masm);
1552
1553 // Ensure stack is fully synced for the expression decompiler.
1554 // Overwrite the RHS value on top of the stack with the object, then push
1555 // the RHS in R1 on top of that.
1556 masm.storeValue(R0, Address(masm.getStackPointer(), 0));
1557 masm.pushValue(R1);
1558
1559 // Push arguments.
1560 masm.pushValue(R1);
1561 masm.pushValue(R0);
1562
1563 // Push pointer to stack values, so that the stub can overwrite the object
1564 // (pushed for the decompiler) with the RHS.
1565 masm.computeEffectiveAddress(
1566 Address(masm.getStackPointer(), 2 * sizeof(Value)), R0.scratchReg());
1567 masm.push(R0.scratchReg());
1568
1569 masm.push(ICStubReg);
1570 pushStubPayload(masm, R0.scratchReg());
1571
1572 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, Value*,
1573 HandleValue, HandleValue);
1574 if (!tailCallVM<Fn, DoSetPropFallback>(masm)) {
1575 return false;
1576 }
1577
1578 // This is the resume point used when bailout rewrites call stack to undo
1579 // Ion inlined frames. The return address pushed onto reconstructed stack
1580 // will point here.
1581 assumeStubFrame();
1582 code.initBailoutReturnOffset(BailoutReturnKind::SetProp,
1583 masm.currentOffset());
1584
1585 leaveStubFrame(masm);
1586 EmitReturnFromIC(masm);
1587
1588 return true;
1589}
1590
1591//
1592// Call_Fallback
1593//
1594
1595bool DoCallFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
1596 uint32_t argc, Value* vp, MutableHandleValue res) {
1597 stub->incrementEnteredCount();
1598 MaybeNotifyWarp(frame->outerScript(), stub);
1599
1600 RootedScript script(cx, frame->script());
1601 jsbytecode* pc = StubOffsetToPc(stub, script);
1602 JSOp op = JSOp(*pc);
1603 FallbackICSpew(cx, stub, "Call(%s)", CodeName(op));
1604
1605 MOZ_ASSERT(argc == GET_ARGC(pc))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(argc == GET_ARGC(pc))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(argc == GET_ARGC(pc)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("argc == GET_ARGC(pc)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1605); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc == GET_ARGC(pc)"
")"); do { *((volatile int*)__null) = 1605; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1606 bool constructing =
1607 (op == JSOp::New || op == JSOp::NewContent || op == JSOp::SuperCall);
1608 bool ignoresReturnValue = (op == JSOp::CallIgnoresRv);
1609
1610 // Ensure vp array is rooted - we may GC in here.
1611 size_t numValues = argc + 2 + constructing;
1612 RootedExternalValueArray vpRoot(cx, numValues, vp);
1613
1614 CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues,
1615 constructing, ignoresReturnValue);
1616 RootedValue callee(cx, vp[0]);
1617 RootedValue newTarget(cx, constructing ? callArgs.newTarget() : NullValue());
1618
1619 // Transition stub state to megamorphic or generic if warranted.
1620 MaybeTransition(cx, frame, stub);
1621
1622 bool canAttachStub = stub->state().canAttachStub();
1623 bool handled = false;
1624
1625 // Only bother to try optimizing JSOp::Call with CacheIR if the chain is still
1626 // allowed to attach stubs.
1627 if (canAttachStub) {
1628 HandleValueArray args = HandleValueArray::fromMarkedLocation(argc, vp + 2);
1629 CallIRGenerator gen(cx, script, pc, op, stub->state(), frame, argc, callee,
1630 callArgs.thisv(), newTarget, args);
1631 switch (gen.tryAttachStub()) {
1632 case AttachDecision::NoAction:
1633 break;
1634 case AttachDecision::Attach: {
1635 ICScript* icScript = frame->icScript();
1636 ICAttachResult result =
1637 AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
1638 script, icScript, stub, gen.stubName());
1639 if (result == ICAttachResult::Attached) {
1640 handled = true;
1641 JitSpew(JitSpew_BaselineIC, " Attached Call CacheIR stub");
1642 }
1643 } break;
1644 case AttachDecision::TemporarilyUnoptimizable:
1645 handled = true;
1646 break;
1647 case AttachDecision::Deferred:
1648 MOZ_CRASH("No deferred Call stubs")do { do { } while (false); MOZ_ReportCrash("" "No deferred Call stubs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1648); AnnotateMozCrashReason("MOZ_CRASH(" "No deferred Call stubs"
")"); do { *((volatile int*)__null) = 1648; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1649 }
1650 if (!handled) {
1651 stub->trackNotAttached();
1652 }
1653 }
1654
1655 if (constructing) {
1656 if (!ConstructFromStack(cx, callArgs)) {
1657 return false;
1658 }
1659 res.set(callArgs.rval());
1660 } else if ((op == JSOp::Eval || op == JSOp::StrictEval) &&
1661 cx->global()->valueIsEval(callee)) {
1662 if (!DirectEval(cx, callArgs.get(0), res)) {
1663 return false;
1664 }
1665 } else {
1666 MOZ_ASSERT(op == JSOp::Call || op == JSOp::CallContent ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::Call || op == JSOp::CallContent || op ==
JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter
|| op == JSOp::Eval || op == JSOp::StrictEval)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(op == JSOp::Call || op == JSOp::CallContent || op == JSOp::
CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter
|| op == JSOp::Eval || op == JSOp::StrictEval))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("op == JSOp::Call || op == JSOp::CallContent || op == JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter || op == JSOp::Eval || op == JSOp::StrictEval"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::Call || op == JSOp::CallContent || op == JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter || op == JSOp::Eval || op == JSOp::StrictEval"
")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1667 op == JSOp::CallIgnoresRv || op == JSOp::CallIter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::Call || op == JSOp::CallContent || op ==
JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter
|| op == JSOp::Eval || op == JSOp::StrictEval)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(op == JSOp::Call || op == JSOp::CallContent || op == JSOp::
CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter
|| op == JSOp::Eval || op == JSOp::StrictEval))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("op == JSOp::Call || op == JSOp::CallContent || op == JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter || op == JSOp::Eval || op == JSOp::StrictEval"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::Call || op == JSOp::CallContent || op == JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter || op == JSOp::Eval || op == JSOp::StrictEval"
")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1668 op == JSOp::CallContentIter || op == JSOp::Eval ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::Call || op == JSOp::CallContent || op ==
JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter
|| op == JSOp::Eval || op == JSOp::StrictEval)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(op == JSOp::Call || op == JSOp::CallContent || op == JSOp::
CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter
|| op == JSOp::Eval || op == JSOp::StrictEval))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("op == JSOp::Call || op == JSOp::CallContent || op == JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter || op == JSOp::Eval || op == JSOp::StrictEval"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::Call || op == JSOp::CallContent || op == JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter || op == JSOp::Eval || op == JSOp::StrictEval"
")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1669 op == JSOp::StrictEval)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op == JSOp::Call || op == JSOp::CallContent || op ==
JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter
|| op == JSOp::Eval || op == JSOp::StrictEval)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(op == JSOp::Call || op == JSOp::CallContent || op == JSOp::
CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter
|| op == JSOp::Eval || op == JSOp::StrictEval))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("op == JSOp::Call || op == JSOp::CallContent || op == JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter || op == JSOp::Eval || op == JSOp::StrictEval"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::Call || op == JSOp::CallContent || op == JSOp::CallIgnoresRv || op == JSOp::CallIter || op == JSOp::CallContentIter || op == JSOp::Eval || op == JSOp::StrictEval"
")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1670 if ((op == JSOp::CallIter || op == JSOp::CallContentIter) &&
1671 callee.isPrimitive()) {
1672 MOZ_ASSERT(argc == 0, "thisv must be on top of the stack")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(argc == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(argc == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("argc == 0" " (" "thisv must be on top of the stack"
")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc == 0" ") ("
"thisv must be on top of the stack" ")"); do { *((volatile int
*)__null) = 1672; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1673 ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, callArgs.thisv(), nullptr);
1674 return false;
1675 }
1676
1677 if (!CallFromStack(cx, callArgs)) {
1678 return false;
1679 }
1680
1681 res.set(callArgs.rval());
1682 }
1683
1684 return true;
1685}
1686
1687bool DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame,
1688 ICFallbackStub* stub, Value* vp,
1689 MutableHandleValue res) {
1690 stub->incrementEnteredCount();
1691 MaybeNotifyWarp(frame->outerScript(), stub);
1692
1693 RootedScript script(cx, frame->script());
1694 jsbytecode* pc = StubOffsetToPc(stub, script);
1695 JSOp op = JSOp(*pc);
1696 bool constructing = (op == JSOp::SpreadNew || op == JSOp::SpreadSuperCall);
1697 FallbackICSpew(cx, stub, "SpreadCall(%s)", CodeName(op));
1698
1699 // Ensure vp array is rooted - we may GC in here.
1700 RootedExternalValueArray vpRoot(cx, 3 + constructing, vp);
1701
1702 RootedValue callee(cx, vp[0]);
1703 RootedValue thisv(cx, vp[1]);
1704 RootedValue arr(cx, vp[2]);
1705 RootedValue newTarget(cx, constructing ? vp[3] : NullValue());
1706
1707 // Transition stub state to megamorphic or generic if warranted.
1708 MaybeTransition(cx, frame, stub);
1709
1710 // Try attaching a call stub.
1711 bool handled = false;
1712 if (op != JSOp::SpreadEval && op != JSOp::StrictSpreadEval &&
1713 stub->state().canAttachStub()) {
1714 // Try CacheIR first:
1715 Rooted<ArrayObject*> aobj(cx, &arr.toObject().as<ArrayObject>());
1716 MOZ_ASSERT(IsPackedArray(aobj))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsPackedArray(aobj))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsPackedArray(aobj)))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("IsPackedArray(aobj)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1716); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPackedArray(aobj)"
")"); do { *((volatile int*)__null) = 1716; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1717
1718 HandleValueArray args = HandleValueArray::fromMarkedLocation(
1719 aobj->length(), aobj->getDenseElements());
1720 CallIRGenerator gen(cx, script, pc, op, stub->state(), frame, 1, callee,
1721 thisv, newTarget, args);
1722 switch (gen.tryAttachStub()) {
1723 case AttachDecision::NoAction:
1724 break;
1725 case AttachDecision::Attach: {
1726 ICScript* icScript = frame->icScript();
1727 ICAttachResult result =
1728 AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
1729 script, icScript, stub, gen.stubName());
1730
1731 if (result == ICAttachResult::Attached) {
1732 handled = true;
1733 JitSpew(JitSpew_BaselineIC, " Attached Spread Call CacheIR stub");
1734 }
1735 } break;
1736 case AttachDecision::TemporarilyUnoptimizable:
1737 handled = true;
1738 break;
1739 case AttachDecision::Deferred:
1740 MOZ_ASSERT_UNREACHABLE("No deferred optimizations for spread calls")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"No deferred optimizations for spread calls" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1740); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "No deferred optimizations for spread calls"
")"); do { *((volatile int*)__null) = 1740; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1741 break;
1742 }
1743 if (!handled) {
1744 stub->trackNotAttached();
1745 }
1746 }
1747
1748 return SpreadCallOperation(cx, script, pc, thisv, callee, arr, newTarget,
1749 res);
1750}
1751
1752void FallbackICCodeCompiler::pushCallArguments(
1753 MacroAssembler& masm, AllocatableGeneralRegisterSet regs, Register argcReg,
1754 bool isConstructing) {
1755 MOZ_ASSERT(!regs.has(argcReg))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!regs.has(argcReg))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!regs.has(argcReg)))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!regs.has(argcReg)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1755); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(argcReg)"
")"); do { *((volatile int*)__null) = 1755; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1756
1757 // argPtr initially points to the last argument.
1758 Register argPtr = regs.takeAny();
1759 masm.mov(FramePointer, argPtr);
1760
1761 // Skip 3 pointers pushed on top of the arguments: the frame descriptor,
1762 // return address, and old frame pointer.
1763 size_t valueOffset = BaselineStubFrameLayout::Size();
1764
1765 // We have to push |this|, callee, new.target (if constructing) and argc
1766 // arguments. Handle the number of Values we know statically first.
1767
1768 size_t numNonArgValues = 2 + isConstructing;
1769 for (size_t i = 0; i < numNonArgValues; i++) {
1770 masm.pushValue(Address(argPtr, valueOffset));
1771 valueOffset += sizeof(Value);
1772 }
1773
1774 // If there are no arguments we're done.
1775 Label done;
1776 masm.branchTest32(Assembler::Zero, argcReg, argcReg, &done);
1777
1778 // Push argc Values.
1779 Label loop;
1780 Register count = regs.takeAny();
1781 masm.addPtr(Imm32(valueOffset), argPtr);
1782 masm.move32(argcReg, count);
1783 masm.bind(&loop);
1784 {
1785 masm.pushValue(Address(argPtr, 0));
1786 masm.addPtr(Imm32(sizeof(Value)), argPtr);
1787
1788 masm.branchSub32(Assembler::NonZero, Imm32(1), count, &loop);
1789 }
1790 masm.bind(&done);
1791}
1792
1793bool FallbackICCodeCompiler::emitCall(bool isSpread, bool isConstructing) {
1794 static_assert(R0 == JSReturnOperand);
1795
1796 // Values are on the stack left-to-right. Calling convention wants them
1797 // right-to-left so duplicate them on the stack in reverse order.
1798 // |this| and callee are pushed last.
1799
1800 AllocatableGeneralRegisterSet regs = BaselineICAvailableGeneralRegs(0);
1801
1802 if (MOZ_UNLIKELY(isSpread)(__builtin_expect(!!(isSpread), 0))) {
1803 // Push a stub frame so that we can perform a non-tail call.
1804 enterStubFrame(masm, R1.scratchReg());
1805
1806 // Use FramePointer instead of StackPointer because it's not affected by
1807 // the stack pushes below.
1808
1809 // newTarget
1810 uint32_t valueOffset = BaselineStubFrameLayout::Size();
1811 if (isConstructing) {
1812 masm.pushValue(Address(FramePointer, valueOffset));
1813 valueOffset += sizeof(Value);
1814 }
1815
1816 // array
1817 masm.pushValue(Address(FramePointer, valueOffset));
1818 valueOffset += sizeof(Value);
1819
1820 // this
1821 masm.pushValue(Address(FramePointer, valueOffset));
1822 valueOffset += sizeof(Value);
1823
1824 // callee
1825 masm.pushValue(Address(FramePointer, valueOffset));
1826 valueOffset += sizeof(Value);
Value stored to 'valueOffset' is never read
1827
1828 masm.push(masm.getStackPointer());
1829 masm.push(ICStubReg);
1830
1831 PushStubPayload(masm, R0.scratchReg());
1832
1833 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, Value*,
1834 MutableHandleValue);
1835 if (!callVM<Fn, DoSpreadCallFallback>(masm)) {
1836 return false;
1837 }
1838
1839 leaveStubFrame(masm);
1840 EmitReturnFromIC(masm);
1841
1842 // SpreadCall is not yet supported in Ion, so do not generate asmcode for
1843 // bailout.
1844 return true;
1845 }
1846
1847 // Push a stub frame so that we can perform a non-tail call.
1848 enterStubFrame(masm, R1.scratchReg());
1849
1850 regs.take(R0.scratchReg()); // argc.
1851
1852 pushCallArguments(masm, regs, R0.scratchReg(), isConstructing);
1853
1854 masm.push(masm.getStackPointer());
1855 masm.push(R0.scratchReg());
1856 masm.push(ICStubReg);
1857
1858 PushStubPayload(masm, R0.scratchReg());
1859
1860 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, uint32_t,
1861 Value*, MutableHandleValue);
1862 if (!callVM<Fn, DoCallFallback>(masm)) {
1863 return false;
1864 }
1865
1866 leaveStubFrame(masm);
1867 EmitReturnFromIC(masm);
1868
1869 // This is the resume point used when bailout rewrites call stack to undo
1870 // Ion inlined frames. The return address pushed onto reconstructed stack
1871 // will point here.
1872 assumeStubFrame();
1873
1874 MOZ_ASSERT(!isSpread)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isSpread)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isSpread))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!isSpread", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 1874); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isSpread" ")"
); do { *((volatile int*)__null) = 1874; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1875
1876 if (isConstructing) {
1877 code.initBailoutReturnOffset(BailoutReturnKind::New, masm.currentOffset());
1878 } else {
1879 code.initBailoutReturnOffset(BailoutReturnKind::Call, masm.currentOffset());
1880 }
1881
1882 // Load passed-in ThisV into R1 just in case it's needed. Need to do this
1883 // before we leave the stub frame since that info will be lost.
1884 // Current stack: [...., ThisV, CalleeToken, Descriptor ]
1885 size_t thisvOffset =
1886 JitFrameLayout::offsetOfThis() - JitFrameLayout::bytesPoppedAfterCall();
1887 masm.loadValue(Address(masm.getStackPointer(), thisvOffset), R1);
1888
1889 leaveStubFrame(masm);
1890
1891 // If this is a |constructing| call, if the callee returns a non-object, we
1892 // replace it with the |this| object passed in.
1893 if (isConstructing) {
1894 static_assert(JSReturnOperand == R0);
1895 Label skipThisReplace;
1896
1897 masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
1898 masm.moveValue(R1, R0);
1899#ifdef DEBUG1
1900 masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
1901 masm.assumeUnreachable("Failed to return object in constructing call.");
1902#endif
1903 masm.bind(&skipThisReplace);
1904 }
1905
1906 EmitReturnFromIC(masm);
1907 return true;
1908}
1909
1910bool FallbackICCodeCompiler::emit_Call() {
1911 return emitCall(/* isSpread = */ false, /* isConstructing = */ false);
1912}
1913
1914bool FallbackICCodeCompiler::emit_CallConstructing() {
1915 return emitCall(/* isSpread = */ false, /* isConstructing = */ true);
1916}
1917
1918bool FallbackICCodeCompiler::emit_SpreadCall() {
1919 return emitCall(/* isSpread = */ true, /* isConstructing = */ false);
1920}
1921
1922bool FallbackICCodeCompiler::emit_SpreadCallConstructing() {
1923 return emitCall(/* isSpread = */ true, /* isConstructing = */ true);
1924}
1925
1926//
1927// GetIterator_Fallback
1928//
1929
1930bool DoGetIteratorFallback(JSContext* cx, BaselineFrame* frame,
1931 ICFallbackStub* stub, HandleValue value,
1932 MutableHandleValue res) {
1933 stub->incrementEnteredCount();
1934 MaybeNotifyWarp(frame->outerScript(), stub);
1935 FallbackICSpew(cx, stub, "GetIterator");
1936
1937 TryAttachStub<GetIteratorIRGenerator>("GetIterator", cx, frame, stub, value);
1938
1939 PropertyIteratorObject* iterObj = ValueToIterator(cx, value);
1940 if (!iterObj) {
1941 return false;
1942 }
1943
1944 res.setObject(*iterObj);
1945 return true;
1946}
1947
1948bool FallbackICCodeCompiler::emit_GetIterator() {
1949 EmitRestoreTailCallReg(masm);
1950
1951 // Sync stack for the decompiler.
1952 masm.pushValue(R0);
1953
1954 masm.pushValue(R0);
1955 masm.push(ICStubReg);
1956 pushStubPayload(masm, R0.scratchReg());
1957
1958 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1959 MutableHandleValue);
1960 return tailCallVM<Fn, DoGetIteratorFallback>(masm);
1961}
1962
1963//
1964// OptimizeSpreadCall_Fallback
1965//
1966
1967bool DoOptimizeSpreadCallFallback(JSContext* cx, BaselineFrame* frame,
1968 ICFallbackStub* stub, HandleValue value,
1969 MutableHandleValue res) {
1970 stub->incrementEnteredCount();
1971 MaybeNotifyWarp(frame->outerScript(), stub);
1972 FallbackICSpew(cx, stub, "OptimizeSpreadCall");
1973
1974 TryAttachStub<OptimizeSpreadCallIRGenerator>("OptimizeSpreadCall", cx, frame,
1975 stub, value);
1976
1977 return OptimizeSpreadCall(cx, value, res);
1978}
1979
1980bool FallbackICCodeCompiler::emit_OptimizeSpreadCall() {
1981 EmitRestoreTailCallReg(masm);
1982
1983 masm.pushValue(R0);
1984 masm.push(ICStubReg);
1985 pushStubPayload(masm, R0.scratchReg());
1986
1987 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1988 MutableHandleValue);
1989 return tailCallVM<Fn, DoOptimizeSpreadCallFallback>(masm);
1990}
1991
1992//
1993// InstanceOf_Fallback
1994//
1995
1996bool DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame,
1997 ICFallbackStub* stub, HandleValue lhs,
1998 HandleValue rhs, MutableHandleValue res) {
1999 stub->incrementEnteredCount();
2000 MaybeNotifyWarp(frame->outerScript(), stub);
2001 FallbackICSpew(cx, stub, "InstanceOf");
2002
2003 if (!rhs.isObject()) {
2004 ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rhs, nullptr);
2005 return false;
2006 }
2007
2008 RootedObject obj(cx, &rhs.toObject());
2009 bool cond = false;
2010 if (!InstanceofOperator(cx, obj, lhs, &cond)) {
2011 return false;
2012 }
2013
2014 res.setBoolean(cond);
2015
2016 if (!obj->is<JSFunction>()) {
2017 // ensure we've recorded at least one failure, so we can detect there was a
2018 // non-optimizable case
2019 if (!stub->state().hasFailures()) {
2020 stub->trackNotAttached();
2021 }
2022 return true;
2023 }
2024
2025 TryAttachStub<InstanceOfIRGenerator>("InstanceOf", cx, frame, stub, lhs, obj);
2026 return true;
2027}
2028
2029bool FallbackICCodeCompiler::emit_InstanceOf() {
2030 EmitRestoreTailCallReg(masm);
2031
2032 // Sync stack for the decompiler.
2033 masm.pushValue(R0);
2034 masm.pushValue(R1);
2035
2036 masm.pushValue(R1);
2037 masm.pushValue(R0);
2038 masm.push(ICStubReg);
2039 pushStubPayload(masm, R0.scratchReg());
2040
2041 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2042 HandleValue, MutableHandleValue);
2043 return tailCallVM<Fn, DoInstanceOfFallback>(masm);
2044}
2045
2046//
2047// TypeOf_Fallback
2048//
2049
2050bool DoTypeOfFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
2051 HandleValue val, MutableHandleValue res) {
2052 stub->incrementEnteredCount();
2053 MaybeNotifyWarp(frame->outerScript(), stub);
2054 FallbackICSpew(cx, stub, "TypeOf");
2055
2056 TryAttachStub<TypeOfIRGenerator>("TypeOf", cx, frame, stub, val);
2057
2058 JSType type = js::TypeOfValue(val);
2059 RootedString string(cx, TypeName(type, cx->names()));
2060 res.setString(string);
2061 return true;
2062}
2063
2064bool FallbackICCodeCompiler::emit_TypeOf() {
2065 EmitRestoreTailCallReg(masm);
2066
2067 masm.pushValue(R0);
2068 masm.push(ICStubReg);
2069 pushStubPayload(masm, R0.scratchReg());
2070
2071 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2072 MutableHandleValue);
2073 return tailCallVM<Fn, DoTypeOfFallback>(masm);
2074}
2075
2076//
2077// TypeOfEq_Fallback
2078//
2079
2080bool DoTypeOfEqFallback(JSContext* cx, BaselineFrame* frame,
2081 ICFallbackStub* stub, HandleValue val,
2082 MutableHandleValue res) {
2083 stub->incrementEnteredCount();
2084 MaybeNotifyWarp(frame->outerScript(), stub);
2085 FallbackICSpew(cx, stub, "TypeOfEq");
2086
2087 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2088 auto operand = TypeofEqOperand::fromRawValue(GET_UINT8(pc));
2089 JSType type = operand.type();
2090 JSOp compareOp = operand.compareOp();
2091
2092 TryAttachStub<TypeOfEqIRGenerator>("TypeOfEq", cx, frame, stub, val, type,
2093 compareOp);
2094
2095 bool result = js::TypeOfValue(val) == type;
2096 if (compareOp == JSOp::Ne) {
2097 result = !result;
2098 }
2099 res.setBoolean(result);
2100 return true;
2101}
2102
2103bool FallbackICCodeCompiler::emit_TypeOfEq() {
2104 EmitRestoreTailCallReg(masm);
2105
2106 masm.pushValue(R0);
2107 masm.push(ICStubReg);
2108 pushStubPayload(masm, R0.scratchReg());
2109
2110 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2111 MutableHandleValue);
2112 return tailCallVM<Fn, DoTypeOfEqFallback>(masm);
2113}
2114
2115//
2116// ToPropertyKey_Fallback
2117//
2118
2119bool DoToPropertyKeyFallback(JSContext* cx, BaselineFrame* frame,
2120 ICFallbackStub* stub, HandleValue val,
2121 MutableHandleValue res) {
2122 stub->incrementEnteredCount();
2123 MaybeNotifyWarp(frame->outerScript(), stub);
2124 FallbackICSpew(cx, stub, "ToPropertyKey");
2125
2126 TryAttachStub<ToPropertyKeyIRGenerator>("ToPropertyKey", cx, frame, stub,
2127 val);
2128
2129 return ToPropertyKeyOperation(cx, val, res);
2130}
2131
2132bool FallbackICCodeCompiler::emit_ToPropertyKey() {
2133 EmitRestoreTailCallReg(masm);
2134
2135 masm.pushValue(R0);
2136 masm.push(ICStubReg);
2137 pushStubPayload(masm, R0.scratchReg());
2138
2139 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2140 MutableHandleValue);
2141 return tailCallVM<Fn, DoToPropertyKeyFallback>(masm);
2142}
2143
2144//
2145// Rest_Fallback
2146//
2147
2148bool DoRestFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
2149 MutableHandleValue res) {
2150 unsigned numFormals = frame->numFormalArgs() - 1;
2151 unsigned numActuals = frame->numActualArgs();
2152 unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
2153 Value* rest = frame->argv() + numFormals;
2154
2155 ArrayObject* obj = NewDenseCopiedArray(cx, numRest, rest);
2156 if (!obj) {
2157 return false;
2158 }
2159 res.setObject(*obj);
2160 return true;
2161}
2162
2163bool FallbackICCodeCompiler::emit_Rest() {
2164 EmitRestoreTailCallReg(masm);
2165
2166 masm.push(ICStubReg);
2167 pushStubPayload(masm, R0.scratchReg());
2168
2169 using Fn =
2170 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, MutableHandleValue);
2171 return tailCallVM<Fn, DoRestFallback>(masm);
2172}
2173
2174//
2175// UnaryArith_Fallback
2176//
2177
2178bool DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame,
2179 ICFallbackStub* stub, HandleValue val,
2180 MutableHandleValue res) {
2181 stub->incrementEnteredCount();
2182 MaybeNotifyWarp(frame->outerScript(), stub);
2183
2184 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2185 JSOp op = JSOp(*pc);
2186 FallbackICSpew(cx, stub, "UnaryArith(%s)", CodeName(op));
2187
2188 switch (op) {
2189 case JSOp::BitNot: {
2190 res.set(val);
2191 if (!BitNot(cx, res, res)) {
2192 return false;
2193 }
2194 break;
2195 }
2196 case JSOp::Pos: {
2197 res.set(val);
2198 if (!ToNumber(cx, res)) {
2199 return false;
2200 }
2201 break;
2202 }
2203 case JSOp::Neg: {
2204 res.set(val);
2205 if (!NegOperation(cx, res, res)) {
2206 return false;
2207 }
2208 break;
2209 }
2210 case JSOp::Inc: {
2211 if (!IncOperation(cx, val, res)) {
2212 return false;
2213 }
2214 break;
2215 }
2216 case JSOp::Dec: {
2217 if (!DecOperation(cx, val, res)) {
2218 return false;
2219 }
2220 break;
2221 }
2222 case JSOp::ToNumeric: {
2223 res.set(val);
2224 if (!ToNumeric(cx, res)) {
2225 return false;
2226 }
2227 break;
2228 }
2229 default:
2230 MOZ_CRASH("Unexpected op")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 2230); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op" ")"
); do { *((volatile int*)__null) = 2230; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2231 }
2232 MOZ_ASSERT(res.isNumeric())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(res.isNumeric())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(res.isNumeric()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("res.isNumeric()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 2232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "res.isNumeric()"
")"); do { *((volatile int*)__null) = 2232; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2233
2234 TryAttachStub<UnaryArithIRGenerator>("UnaryArith", cx, frame, stub, op, val,
2235 res);
2236 return true;
2237}
2238
2239bool FallbackICCodeCompiler::emit_UnaryArith() {
2240 static_assert(R0 == JSReturnOperand);
2241
2242 // Restore the tail call register.
2243 EmitRestoreTailCallReg(masm);
2244
2245 // Ensure stack is fully synced for the expression decompiler.
2246 masm.pushValue(R0);
2247
2248 // Push arguments.
2249 masm.pushValue(R0);
2250 masm.push(ICStubReg);
2251 pushStubPayload(masm, R0.scratchReg());
2252
2253 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2254 MutableHandleValue);
2255 return tailCallVM<Fn, DoUnaryArithFallback>(masm);
2256}
2257
2258//
2259// BinaryArith_Fallback
2260//
2261
2262bool DoBinaryArithFallback(JSContext* cx, BaselineFrame* frame,
2263 ICFallbackStub* stub, HandleValue lhs,
2264 HandleValue rhs, MutableHandleValue ret) {
2265 stub->incrementEnteredCount();
2266 MaybeNotifyWarp(frame->outerScript(), stub);
2267
2268 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2269 JSOp op = JSOp(*pc);
2270 FallbackICSpew(
2271 cx, stub, "CacheIRBinaryArith(%s,%d,%d)", CodeName(op),
2272 int(lhs.isDouble() ? JSVAL_TYPE_DOUBLE : lhs.extractNonDoubleType()),
2273 int(rhs.isDouble() ? JSVAL_TYPE_DOUBLE : rhs.extractNonDoubleType()));
2274
2275 // Don't pass lhs/rhs directly, we need the original values when
2276 // generating stubs.
2277 RootedValue lhsCopy(cx, lhs);
2278 RootedValue rhsCopy(cx, rhs);
2279
2280 // Perform the arith operation.
2281 switch (op) {
2282 case JSOp::Add:
2283 // Do an add.
2284 if (!AddValues(cx, &lhsCopy, &rhsCopy, ret)) {
2285 return false;
2286 }
2287 break;
2288 case JSOp::Sub:
2289 if (!SubValues(cx, &lhsCopy, &rhsCopy, ret)) {
2290 return false;
2291 }
2292 break;
2293 case JSOp::Mul:
2294 if (!MulValues(cx, &lhsCopy, &rhsCopy, ret)) {
2295 return false;
2296 }
2297 break;
2298 case JSOp::Div:
2299 if (!DivValues(cx, &lhsCopy, &rhsCopy, ret)) {
2300 return false;
2301 }
2302 break;
2303 case JSOp::Mod:
2304 if (!ModValues(cx, &lhsCopy, &rhsCopy, ret)) {
2305 return false;
2306 }
2307 break;
2308 case JSOp::Pow:
2309 if (!PowValues(cx, &lhsCopy, &rhsCopy, ret)) {
2310 return false;
2311 }
2312 break;
2313 case JSOp::BitOr: {
2314 if (!BitOr(cx, &lhsCopy, &rhsCopy, ret)) {
2315 return false;
2316 }
2317 break;
2318 }
2319 case JSOp::BitXor: {
2320 if (!BitXor(cx, &lhsCopy, &rhsCopy, ret)) {
2321 return false;
2322 }
2323 break;
2324 }
2325 case JSOp::BitAnd: {
2326 if (!BitAnd(cx, &lhsCopy, &rhsCopy, ret)) {
2327 return false;
2328 }
2329 break;
2330 }
2331 case JSOp::Lsh: {
2332 if (!BitLsh(cx, &lhsCopy, &rhsCopy, ret)) {
2333 return false;
2334 }
2335 break;
2336 }
2337 case JSOp::Rsh: {
2338 if (!BitRsh(cx, &lhsCopy, &rhsCopy, ret)) {
2339 return false;
2340 }
2341 break;
2342 }
2343 case JSOp::Ursh: {
2344 if (!UrshValues(cx, &lhsCopy, &rhsCopy, ret)) {
2345 return false;
2346 }
2347 break;
2348 }
2349 default:
2350 MOZ_CRASH("Unhandled baseline arith op")do { do { } while (false); MOZ_ReportCrash("" "Unhandled baseline arith op"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 2350); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled baseline arith op"
")"); do { *((volatile int*)__null) = 2350; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2351 }
2352
2353 TryAttachStub<BinaryArithIRGenerator>("BinaryArith", cx, frame, stub, op, lhs,
2354 rhs, ret);
2355 return true;
2356}
2357
2358bool FallbackICCodeCompiler::emit_BinaryArith() {
2359 static_assert(R0 == JSReturnOperand);
2360
2361 // Restore the tail call register.
2362 EmitRestoreTailCallReg(masm);
2363
2364 // Ensure stack is fully synced for the expression decompiler.
2365 masm.pushValue(R0);
2366 masm.pushValue(R1);
2367
2368 // Push arguments.
2369 masm.pushValue(R1);
2370 masm.pushValue(R0);
2371 masm.push(ICStubReg);
2372 pushStubPayload(masm, R0.scratchReg());
2373
2374 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2375 HandleValue, MutableHandleValue);
2376 return tailCallVM<Fn, DoBinaryArithFallback>(masm);
2377}
2378
2379//
2380// Compare_Fallback
2381//
2382bool DoCompareFallback(JSContext* cx, BaselineFrame* frame,
2383 ICFallbackStub* stub, HandleValue lhs, HandleValue rhs,
2384 MutableHandleValue ret) {
2385 stub->incrementEnteredCount();
2386 MaybeNotifyWarp(frame->outerScript(), stub);
2387
2388 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2389 JSOp op = JSOp(*pc);
2390
2391 FallbackICSpew(cx, stub, "Compare(%s)", CodeName(op));
2392
2393 // Don't pass lhs/rhs directly, we need the original values when
2394 // generating stubs.
2395 RootedValue lhsCopy(cx, lhs);
2396 RootedValue rhsCopy(cx, rhs);
2397
2398 // Perform the compare operation.
2399 bool out;
2400 switch (op) {
2401 case JSOp::Lt:
2402 if (!LessThan(cx, &lhsCopy, &rhsCopy, &out)) {
2403 return false;
2404 }
2405 break;
2406 case JSOp::Le:
2407 if (!LessThanOrEqual(cx, &lhsCopy, &rhsCopy, &out)) {
2408 return false;
2409 }
2410 break;
2411 case JSOp::Gt:
2412 if (!GreaterThan(cx, &lhsCopy, &rhsCopy, &out)) {
2413 return false;
2414 }
2415 break;
2416 case JSOp::Ge:
2417 if (!GreaterThanOrEqual(cx, &lhsCopy, &rhsCopy, &out)) {
2418 return false;
2419 }
2420 break;
2421 case JSOp::Eq:
2422 if (!js::LooselyEqual(cx, lhsCopy, rhsCopy, &out)) {
2423 return false;
2424 }
2425 break;
2426 case JSOp::Ne:
2427 if (!js::LooselyEqual(cx, lhsCopy, rhsCopy, &out)) {
2428 return false;
2429 }
2430 out = !out;
2431 break;
2432 case JSOp::StrictEq:
2433 if (!js::StrictlyEqual(cx, lhsCopy, rhsCopy, &out)) {
2434 return false;
2435 }
2436 break;
2437 case JSOp::StrictNe:
2438 if (!js::StrictlyEqual(cx, lhsCopy, rhsCopy, &out)) {
2439 return false;
2440 }
2441 out = !out;
2442 break;
2443 default:
2444 MOZ_ASSERT_UNREACHABLE("Unhandled baseline compare op")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unhandled baseline compare op" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 2444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unhandled baseline compare op" ")"
); do { *((volatile int*)__null) = 2444; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2445 return false;
2446 }
2447
2448 ret.setBoolean(out);
2449
2450 TryAttachStub<CompareIRGenerator>("Compare", cx, frame, stub, op, lhs, rhs);
2451 return true;
2452}
2453
2454bool FallbackICCodeCompiler::emit_Compare() {
2455 static_assert(R0 == JSReturnOperand);
2456
2457 // Restore the tail call register.
2458 EmitRestoreTailCallReg(masm);
2459
2460 // Ensure stack is fully synced for the expression decompiler.
2461 masm.pushValue(R0);
2462 masm.pushValue(R1);
2463
2464 // Push arguments.
2465 masm.pushValue(R1);
2466 masm.pushValue(R0);
2467 masm.push(ICStubReg);
2468 pushStubPayload(masm, R0.scratchReg());
2469
2470 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2471 HandleValue, MutableHandleValue);
2472 return tailCallVM<Fn, DoCompareFallback>(masm);
2473}
2474
2475//
2476// NewArray_Fallback
2477//
2478
2479bool DoNewArrayFallback(JSContext* cx, BaselineFrame* frame,
2480 ICFallbackStub* stub, MutableHandleValue res) {
2481 stub->incrementEnteredCount();
2482 MaybeNotifyWarp(frame->outerScript(), stub);
2483 FallbackICSpew(cx, stub, "NewArray");
2484
2485 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2486
2487 uint32_t length = GET_UINT32(pc);
2488 MOZ_ASSERT(length <= INT32_MAX,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length <= (2147483647))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length <= (2147483647))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("length <= (2147483647)"
" (" "the bytecode emitter must fail to compile code that would "
"produce a length exceeding int32_t range" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 2490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length <= (2147483647)"
") (" "the bytecode emitter must fail to compile code that would "
"produce a length exceeding int32_t range" ")"); do { *((volatile
int*)__null) = 2490; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
2489 "the bytecode emitter must fail to compile code that would "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length <= (2147483647))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length <= (2147483647))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("length <= (2147483647)"
" (" "the bytecode emitter must fail to compile code that would "
"produce a length exceeding int32_t range" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 2490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length <= (2147483647)"
") (" "the bytecode emitter must fail to compile code that would "
"produce a length exceeding int32_t range" ")"); do { *((volatile
int*)__null) = 2490; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
2490 "produce a length exceeding int32_t range")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length <= (2147483647))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length <= (2147483647))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("length <= (2147483647)"
" (" "the bytecode emitter must fail to compile code that would "
"produce a length exceeding int32_t range" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 2490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length <= (2147483647)"
") (" "the bytecode emitter must fail to compile code that would "
"produce a length exceeding int32_t range" ")"); do { *((volatile
int*)__null) = 2490; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2491
2492 Rooted<ArrayObject*> array(cx, NewArrayOperation(cx, length));
2493 if (!array) {
2494 return false;
2495 }
2496
2497 TryAttachStub<NewArrayIRGenerator>("NewArray", cx, frame, stub, JSOp(*pc),
2498 array, frame);
2499
2500 res.setObject(*array);
2501 return true;
2502}
2503
2504bool FallbackICCodeCompiler::emit_NewArray() {
2505 EmitRestoreTailCallReg(masm);
2506
2507 masm.push(ICStubReg); // stub.
2508 masm.pushBaselineFramePtr(FramePointer, R0.scratchReg());
2509
2510 using Fn =
2511 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, MutableHandleValue);
2512 return tailCallVM<Fn, DoNewArrayFallback>(masm);
2513}
2514
2515//
2516// NewObject_Fallback
2517//
2518bool DoNewObjectFallback(JSContext* cx, BaselineFrame* frame,
2519 ICFallbackStub* stub, MutableHandleValue res) {
2520 stub->incrementEnteredCount();
2521 MaybeNotifyWarp(frame->outerScript(), stub);
2522 FallbackICSpew(cx, stub, "NewObject");
2523
2524 RootedScript script(cx, frame->script());
2525 jsbytecode* pc = StubOffsetToPc(stub, script);
2526
2527 RootedObject obj(cx, NewObjectOperation(cx, script, pc));
2528 if (!obj) {
2529 return false;
2530 }
2531
2532 TryAttachStub<NewObjectIRGenerator>("NewObject", cx, frame, stub, JSOp(*pc),
2533 obj, frame);
2534
2535 res.setObject(*obj);
2536 return true;
2537}
2538
2539bool FallbackICCodeCompiler::emit_NewObject() {
2540 EmitRestoreTailCallReg(masm);
2541
2542 masm.push(ICStubReg); // stub.
2543 pushStubPayload(masm, R0.scratchReg());
2544
2545 using Fn =
2546 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, MutableHandleValue);
2547 return tailCallVM<Fn, DoNewObjectFallback>(masm);
2548}
2549
2550//
2551// CloseIter_Fallback
2552//
2553
2554bool DoCloseIterFallback(JSContext* cx, BaselineFrame* frame,
2555 ICFallbackStub* stub, HandleObject iter) {
2556 stub->incrementEnteredCount();
2557 MaybeNotifyWarp(frame->outerScript(), stub);
2558 FallbackICSpew(cx, stub, "CloseIter");
2559
2560 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2561 CompletionKind kind = CompletionKind(GET_UINT8(pc));
2562
2563 TryAttachStub<CloseIterIRGenerator>("CloseIter", cx, frame, stub, iter, kind);
2564
2565 return CloseIterOperation(cx, iter, kind);
2566}
2567
2568bool FallbackICCodeCompiler::emit_CloseIter() {
2569 EmitRestoreTailCallReg(masm);
2570
2571 masm.push(R0.scratchReg());
2572 masm.push(ICStubReg);
2573 pushStubPayload(masm, R0.scratchReg());
2574
2575 using Fn =
2576 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleObject);
2577 return tailCallVM<Fn, DoCloseIterFallback>(masm);
2578}
2579
2580//
2581// OptimizeGetIterator_Fallback
2582//
2583
2584bool DoOptimizeGetIteratorFallback(JSContext* cx, BaselineFrame* frame,
2585 ICFallbackStub* stub, HandleValue value,
2586 MutableHandleValue res) {
2587 stub->incrementEnteredCount();
2588 MaybeNotifyWarp(frame->outerScript(), stub);
2589 FallbackICSpew(cx, stub, "OptimizeGetIterator");
2590
2591 TryAttachStub<OptimizeGetIteratorIRGenerator>("OptimizeGetIterator", cx,
2592 frame, stub, value);
2593
2594 bool result;
2595 if (!OptimizeGetIterator(cx, value, &result)) {
2596 return false;
2597 }
2598 res.setBoolean(result);
2599 return true;
2600}
2601
2602bool FallbackICCodeCompiler::emit_OptimizeGetIterator() {
2603 EmitRestoreTailCallReg(masm);
2604
2605 masm.pushValue(R0);
2606 masm.push(ICStubReg);
2607 pushStubPayload(masm, R0.scratchReg());
2608
2609 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2610 MutableHandleValue);
2611 return tailCallVM<Fn, DoOptimizeGetIteratorFallback>(masm);
2612}
2613
2614bool JitRuntime::generateBaselineICFallbackCode(JSContext* cx) {
2615 TempAllocator temp(&cx->tempLifoAlloc());
2616 StackMacroAssembler masm(cx, temp);
2617 PerfSpewerRangeRecorder rangeRecorder(masm);
2618 AutoCreatedBy acb(masm, "JitRuntime::generateBaselineICFallbackCode");
2619
2620 BaselineICFallbackCode& fallbackCode = baselineICFallbackCode_.ref();
2621 FallbackICCodeCompiler compiler(cx, fallbackCode, masm);
2622
2623 JitSpew(JitSpew_Codegen, "# Emitting Baseline IC fallback code");
2624
2625#define EMIT_CODE(kind) \
2626 { \
2627 AutoCreatedBy acb(masm, "kind=" #kind); \
2628 uint32_t offset = startTrampolineCode(masm); \
2629 InitMacroAssemblerForICStub(masm); \
2630 if (!compiler.emit_##kind()) { \
2631 return false; \
2632 } \
2633 fallbackCode.initOffset(BaselineICFallbackKind::kind, offset); \
2634 rangeRecorder.recordOffset("BaselineICFallback: " #kind); \
2635 }
2636 IC_BASELINE_FALLBACK_CODE_KIND_LIST(EMIT_CODE)EMIT_CODE(NewArray) EMIT_CODE(NewObject) EMIT_CODE(ToBool) EMIT_CODE
(UnaryArith) EMIT_CODE(Call) EMIT_CODE(CallConstructing) EMIT_CODE
(SpreadCall) EMIT_CODE(SpreadCallConstructing) EMIT_CODE(GetElem
) EMIT_CODE(GetElemSuper) EMIT_CODE(SetElem) EMIT_CODE(In) EMIT_CODE
(HasOwn) EMIT_CODE(CheckPrivateField) EMIT_CODE(GetName) EMIT_CODE
(BindName) EMIT_CODE(GetIntrinsic) EMIT_CODE(SetProp) EMIT_CODE
(GetIterator) EMIT_CODE(OptimizeSpreadCall) EMIT_CODE(InstanceOf
) EMIT_CODE(TypeOf) EMIT_CODE(TypeOfEq) EMIT_CODE(ToPropertyKey
) EMIT_CODE(Rest) EMIT_CODE(BinaryArith) EMIT_CODE(Compare) EMIT_CODE
(GetProp) EMIT_CODE(GetPropSuper) EMIT_CODE(CloseIter) EMIT_CODE
(OptimizeGetIterator)
2637#undef EMIT_CODE
2638
2639 Linker linker(masm);
2640 JitCode* code = linker.newCode(cx, CodeKind::Other);
2641 if (!code) {
2642 return false;
2643 }
2644
2645 rangeRecorder.collectRangesForJitCode(code);
2646
2647#ifdef MOZ_VTUNE1
2648 vtune::MarkStub(code, "BaselineICFallback");
2649#endif
2650
2651 fallbackCode.initCode(code);
2652 return true;
2653}
2654
2655} // namespace jit
2656} // namespace js