Bug Summary

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