Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp
Warning:line 1812, 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/js/src/js-confdefs.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 -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/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../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-05-16-034744-15991-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 }
887
888 if (op == JSOp::InitElem || op == JSOp::InitHiddenElem ||
889 op == JSOp::InitLockedElem) {
890 if (!InitElemOperation(cx, pc, obj, index, rhs)) {
891 return false;
892 }
893 } else if (op == JSOp::InitElemInc) {
894 if (!InitElemIncOperation(cx, obj.as<ArrayObject>(), index.toInt32(),
895 rhs)) {
896 return false;
897 }
898 } else {
899 if (!SetObjectElementWithReceiver(cx, obj, index, rhs, objv,
900 JSOp(*pc) == JSOp::StrictSetElem)) {
901 return false;
902 }
903 }
904
905 if (stack) {
906 // Overwrite the object on the stack (pushed for the decompiler) with the
907 // rhs.
908 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"
, 908); AnnotateMozCrashReason("MOZ_ASSERT" "(" "stack[2] == objv"
")"); do { *((volatile int*)__null) = 908; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
909 stack[2] = rhs;
910 }
911
912 if (attached) {
913 return true;
914 }
915
916 // The SetObjectElement call might have entered this IC recursively, so try
917 // to transition.
918 MaybeTransition(cx, frame, stub);
919
920 bool canAttachStub = stub->state().canAttachStub();
921
922 if (deferType != DeferType::None && canAttachStub) {
923 SetPropIRGenerator gen(cx, script, pc, CacheKind::SetElem, stub->state(),
924 objv, index, rhs);
925
926 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"
, 926); AnnotateMozCrashReason("MOZ_ASSERT" "(" "deferType == DeferType::AddSlot"
")"); do { *((volatile int*)__null) = 926; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
927 AttachDecision decision = gen.tryAttachAddSlotStub(oldShape);
928
929 switch (decision) {
930 case AttachDecision::Attach: {
931 ICScript* icScript = frame->icScript();
932 ICAttachResult result = AttachBaselineCacheIRStub(
933 cx, gen.writerRef(), gen.cacheKind(), frame->script(), icScript,
934 stub, gen.stubName());
935 if (result == ICAttachResult::Attached) {
936 attached = true;
937 JitSpew(JitSpew_BaselineIC, " Attached SetElem CacheIR stub");
938 }
939 } break;
940 case AttachDecision::NoAction:
941 gen.trackAttached(IRGenerator::NotAttached);
942 break;
943 case AttachDecision::TemporarilyUnoptimizable:
944 case AttachDecision::Deferred:
945 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"
, 945); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Invalid attach result" ")"); do {
*((volatile int*)__null) = 945; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
946 break;
947 }
948 }
949 if (!attached && canAttachStub) {
950 stub->trackNotAttached();
951 }
952 return true;
953}
954
955bool FallbackICCodeCompiler::emit_SetElem() {
956 static_assert(R0 == JSReturnOperand);
957
958 EmitRestoreTailCallReg(masm);
959
960 // State: R0: object, R1: index, stack: rhs.
961 // For the decompiler, the stack has to be: object, index, rhs,
962 // so we push the index, then overwrite the rhs Value with R0
963 // and push the rhs value.
964 masm.pushValue(R1);
965 masm.loadValue(Address(masm.getStackPointer(), sizeof(Value)), R1);
966 masm.storeValue(R0, Address(masm.getStackPointer(), sizeof(Value)));
967 masm.pushValue(R1);
968
969 // Push arguments.
970 masm.pushValue(R1); // RHS
971
972 // Push index. On x86 and ARM two push instructions are emitted so use a
973 // separate register to store the old stack pointer.
974 masm.moveStackPtrTo(R1.scratchReg());
975 masm.pushValue(Address(R1.scratchReg(), 2 * sizeof(Value)));
976 masm.pushValue(R0); // Object.
977
978 // Push pointer to stack values, so that the stub can overwrite the object
979 // (pushed for the decompiler) with the rhs.
980 masm.computeEffectiveAddress(
981 Address(masm.getStackPointer(), 3 * sizeof(Value)), R0.scratchReg());
982 masm.push(R0.scratchReg());
983
984 masm.push(ICStubReg);
985 pushStubPayload(masm, R0.scratchReg());
986
987 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, Value*,
988 HandleValue, HandleValue, HandleValue);
989 return tailCallVM<Fn, DoSetElemFallback>(masm);
990}
991
992//
993// In_Fallback
994//
995
996bool DoInFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
997 HandleValue key, HandleValue objValue,
998 MutableHandleValue res) {
999 stub->incrementEnteredCount();
1000 MaybeNotifyWarp(frame->outerScript(), stub);
1001 FallbackICSpew(cx, stub, "In");
1002
1003 if (!objValue.isObject()) {
1004 ReportInNotObjectError(cx, key, objValue);
1005 return false;
1006 }
1007
1008 TryAttachStub<HasPropIRGenerator>("In", cx, frame, stub, CacheKind::In, key,
1009 objValue);
1010
1011 RootedObject obj(cx, &objValue.toObject());
1012 bool cond = false;
1013 if (!OperatorIn(cx, key, obj, &cond)) {
1014 return false;
1015 }
1016 res.setBoolean(cond);
1017
1018 return true;
1019}
1020
1021bool FallbackICCodeCompiler::emit_In() {
1022 EmitRestoreTailCallReg(masm);
1023
1024 // Sync for the decompiler.
1025 masm.pushValue(R0);
1026 masm.pushValue(R1);
1027
1028 // Push arguments.
1029 masm.pushValue(R1);
1030 masm.pushValue(R0);
1031 masm.push(ICStubReg);
1032 pushStubPayload(masm, R0.scratchReg());
1033
1034 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1035 HandleValue, MutableHandleValue);
1036 return tailCallVM<Fn, DoInFallback>(masm);
1037}
1038
1039//
1040// HasOwn_Fallback
1041//
1042
1043bool DoHasOwnFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
1044 HandleValue keyValue, HandleValue objValue,
1045 MutableHandleValue res) {
1046 stub->incrementEnteredCount();
1047 MaybeNotifyWarp(frame->outerScript(), stub);
1048 FallbackICSpew(cx, stub, "HasOwn");
1049
1050 TryAttachStub<HasPropIRGenerator>("HasOwn", cx, frame, stub,
1051 CacheKind::HasOwn, keyValue, objValue);
1052
1053 bool found;
1054 if (!HasOwnProperty(cx, objValue, keyValue, &found)) {
1055 return false;
1056 }
1057
1058 res.setBoolean(found);
1059 return true;
1060}
1061
1062bool FallbackICCodeCompiler::emit_HasOwn() {
1063 EmitRestoreTailCallReg(masm);
1064
1065 // Sync for the decompiler.
1066 masm.pushValue(R0);
1067 masm.pushValue(R1);
1068
1069 // Push arguments.
1070 masm.pushValue(R1);
1071 masm.pushValue(R0);
1072 masm.push(ICStubReg);
1073 pushStubPayload(masm, R0.scratchReg());
1074
1075 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1076 HandleValue, MutableHandleValue);
1077 return tailCallVM<Fn, DoHasOwnFallback>(masm);
1078}
1079
1080//
1081// CheckPrivate_Fallback
1082//
1083
1084bool DoCheckPrivateFieldFallback(JSContext* cx, BaselineFrame* frame,
1085 ICFallbackStub* stub, HandleValue objValue,
1086 HandleValue keyValue, MutableHandleValue res) {
1087 stub->incrementEnteredCount();
1088 MaybeNotifyWarp(frame->outerScript(), stub);
1089
1090 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
1091
1092 FallbackICSpew(cx, stub, "CheckPrivateField");
1093
1094 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"
, 1094); AnnotateMozCrashReason("MOZ_ASSERT" "(" "keyValue.isSymbol() && keyValue.toSymbol()->isPrivateName()"
")"); do { *((volatile int*)__null) = 1094; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1095
1096 TryAttachStub<CheckPrivateFieldIRGenerator>("CheckPrivate", cx, frame, stub,
1097 CacheKind::CheckPrivateField,
1098 keyValue, objValue);
1099
1100 bool result;
1101 if (!CheckPrivateFieldOperation(cx, pc, objValue, keyValue, &result)) {
1102 return false;
1103 }
1104
1105 res.setBoolean(result);
1106 return true;
1107}
1108
1109bool FallbackICCodeCompiler::emit_CheckPrivateField() {
1110 EmitRestoreTailCallReg(masm);
1111
1112 // Sync for the decompiler.
1113 masm.pushValue(R0);
1114 masm.pushValue(R1);
1115
1116 // Push arguments.
1117 masm.pushValue(R1);
1118 masm.pushValue(R0);
1119 masm.push(ICStubReg);
1120 pushStubPayload(masm, R0.scratchReg());
1121
1122 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1123 HandleValue, MutableHandleValue);
1124 return tailCallVM<Fn, DoCheckPrivateFieldFallback>(masm);
1125}
1126
1127//
1128// GetName_Fallback
1129//
1130
1131bool DoGetNameFallback(JSContext* cx, BaselineFrame* frame,
1132 ICFallbackStub* stub, HandleObject envChain,
1133 MutableHandleValue res) {
1134 stub->incrementEnteredCount();
1135 MaybeNotifyWarp(frame->outerScript(), stub);
1136
1137 RootedScript script(cx, frame->script());
1138 jsbytecode* pc = StubOffsetToPc(stub, script);
1139 mozilla::DebugOnly<JSOp> op = JSOp(*pc);
1140 FallbackICSpew(cx, stub, "GetName(%s)", CodeName(JSOp(*pc)));
1141
1142 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"
, 1142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetName || op == JSOp::GetGName"
")"); do { *((volatile int*)__null) = 1142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1143
1144 Rooted<PropertyName*> name(cx, script->getName(pc));
1145
1146 TryAttachStub<GetNameIRGenerator>("GetName", cx, frame, stub, envChain, name);
1147
1148 static_assert(JSOpLength_GetGName == JSOpLength_GetName,
1149 "Otherwise our check for JSOp::Typeof isn't ok");
1150 if (IsTypeOfNameOp(JSOp(pc[JSOpLength_GetGName]))) {
1151 if (!GetEnvironmentName<GetNameMode::TypeOf>(cx, envChain, name, res)) {
1152 return false;
1153 }
1154 } else {
1155 if (!GetEnvironmentName<GetNameMode::Normal>(cx, envChain, name, res)) {
1156 return false;
1157 }
1158 }
1159
1160 return true;
1161}
1162
1163bool FallbackICCodeCompiler::emit_GetName() {
1164 static_assert(R0 == JSReturnOperand);
1165
1166 EmitRestoreTailCallReg(masm);
1167
1168 masm.push(R0.scratchReg());
1169 masm.push(ICStubReg);
1170 pushStubPayload(masm, R0.scratchReg());
1171
1172 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleObject,
1173 MutableHandleValue);
1174 return tailCallVM<Fn, DoGetNameFallback>(masm);
1175}
1176
1177//
1178// BindName_Fallback
1179//
1180
1181bool DoBindNameFallback(JSContext* cx, BaselineFrame* frame,
1182 ICFallbackStub* stub, HandleObject envChain,
1183 MutableHandleValue res) {
1184 stub->incrementEnteredCount();
1185 MaybeNotifyWarp(frame->outerScript(), stub);
1186
1187 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
1188 mozilla::DebugOnly<JSOp> op = JSOp(*pc);
1189 FallbackICSpew(cx, stub, "BindName(%s)", CodeName(JSOp(*pc)));
1190
1191 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"
, 1191); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::BindName || op == JSOp::BindGName"
")"); do { *((volatile int*)__null) = 1191; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1192
1193 Rooted<PropertyName*> name(cx, frame->script()->getName(pc));
1194
1195 TryAttachStub<BindNameIRGenerator>("BindName", cx, frame, stub, envChain,
1196 name);
1197
1198 RootedObject scope(cx);
1199 if (!LookupNameUnqualified(cx, name, envChain, &scope)) {
1200 return false;
1201 }
1202
1203 res.setObject(*scope);
1204 return true;
1205}
1206
1207bool FallbackICCodeCompiler::emit_BindName() {
1208 static_assert(R0 == JSReturnOperand);
1209
1210 EmitRestoreTailCallReg(masm);
1211
1212 masm.push(R0.scratchReg());
1213 masm.push(ICStubReg);
1214 pushStubPayload(masm, R0.scratchReg());
1215
1216 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleObject,
1217 MutableHandleValue);
1218 return tailCallVM<Fn, DoBindNameFallback>(masm);
1219}
1220
1221//
1222// GetIntrinsic_Fallback
1223//
1224
1225bool DoGetIntrinsicFallback(JSContext* cx, BaselineFrame* frame,
1226 ICFallbackStub* stub, MutableHandleValue res) {
1227 stub->incrementEnteredCount();
1228 MaybeNotifyWarp(frame->outerScript(), stub);
1229
1230 RootedScript script(cx, frame->script());
1231 jsbytecode* pc = StubOffsetToPc(stub, script);
1232 mozilla::DebugOnly<JSOp> op = JSOp(*pc);
1233 FallbackICSpew(cx, stub, "GetIntrinsic(%s)", CodeName(JSOp(*pc)));
1234
1235 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"
, 1235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetIntrinsic"
")"); do { *((volatile int*)__null) = 1235; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1236
1237 if (!GetIntrinsicOperation(cx, script, pc, res)) {
1238 return false;
1239 }
1240
1241 TryAttachStub<GetIntrinsicIRGenerator>("GetIntrinsic", cx, frame, stub, res);
1242
1243 return true;
1244}
1245
1246bool FallbackICCodeCompiler::emit_GetIntrinsic() {
1247 EmitRestoreTailCallReg(masm);
1248
1249 masm.push(ICStubReg);
1250 pushStubPayload(masm, R0.scratchReg());
1251
1252 using Fn =
1253 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, MutableHandleValue);
1254 return tailCallVM<Fn, DoGetIntrinsicFallback>(masm);
1255}
1256
1257//
1258// GetProp_Fallback
1259//
1260
1261bool DoGetPropFallback(JSContext* cx, BaselineFrame* frame,
1262 ICFallbackStub* stub, MutableHandleValue val,
1263 MutableHandleValue res) {
1264 stub->incrementEnteredCount();
1265 MaybeNotifyWarp(frame->outerScript(), stub);
1266
1267 RootedScript script(cx, frame->script());
1268 jsbytecode* pc = StubOffsetToPc(stub, script);
1269 JSOp op = JSOp(*pc);
1270 FallbackICSpew(cx, stub, "GetProp(%s)", CodeName(op));
1271
1272 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"
, 1272); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetProp || op == JSOp::GetBoundName"
")"); do { *((volatile int*)__null) = 1272; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1273
1274 Rooted<PropertyName*> name(cx, script->getName(pc));
1275 RootedValue idVal(cx, StringValue(name));
1276
1277 TryAttachStub<GetPropIRGenerator>("GetProp", cx, frame, stub,
1278 CacheKind::GetProp, val, idVal);
1279
1280 if (op == JSOp::GetBoundName) {
1281 RootedObject env(cx, &val.toObject());
1282 RootedId id(cx, NameToId(name));
1283 return GetNameBoundInEnvironment(cx, env, id, res);
1284 }
1285
1286 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"
, 1286); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::GetProp"
")"); do { *((volatile int*)__null) = 1286; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1287 if (!GetProperty(cx, val, name, res)) {
1288 return false;
1289 }
1290
1291 return true;
1292}
1293
1294bool DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame,
1295 ICFallbackStub* stub, HandleValue receiver,
1296 MutableHandleValue val, MutableHandleValue res) {
1297 stub->incrementEnteredCount();
1298 MaybeNotifyWarp(frame->outerScript(), stub);
1299
1300 RootedScript script(cx, frame->script());
1301 jsbytecode* pc = StubOffsetToPc(stub, script);
1302 FallbackICSpew(cx, stub, "GetPropSuper(%s)", CodeName(JSOp(*pc)));
1303
1304 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"
, 1304); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JSOp(*pc) == JSOp::GetPropSuper"
")"); do { *((volatile int*)__null) = 1304; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1305
1306 Rooted<PropertyName*> name(cx, script->getName(pc));
1307 RootedValue idVal(cx, StringValue(name));
1308
1309 // |val| is [[HomeObject]].[[Prototype]] which must be an Object or null.
1310 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"
, 1310); AnnotateMozCrashReason("MOZ_ASSERT" "(" "val.isObjectOrNull()"
")"); do { *((volatile int*)__null) = 1310; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1311
1312 int valIndex = -1;
1313 RootedObject valObj(
1314 cx, ToObjectFromStackForPropertyAccess(cx, val, valIndex, name));
1315 if (!valObj) {
1316 return false;
1317 }
1318
1319 TryAttachStub<GetPropIRGenerator>("GetPropSuper", cx, frame, stub,
1320 CacheKind::GetPropSuper, val, idVal);
1321
1322 if (!GetProperty(cx, valObj, receiver, name, res)) {
1323 return false;
1324 }
1325
1326 return true;
1327}
1328
1329bool FallbackICCodeCompiler::emitGetProp(bool hasReceiver) {
1330 static_assert(R0 == JSReturnOperand);
1331
1332 EmitRestoreTailCallReg(masm);
1333
1334 // Super property getters use a |this| that differs from base object
1335 if (hasReceiver) {
1336 // Push arguments.
1337 masm.pushValue(R0);
1338 masm.pushValue(R1);
1339 masm.push(ICStubReg);
1340 masm.pushBaselineFramePtr(FramePointer, R0.scratchReg());
1341
1342 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*,
1343 HandleValue, MutableHandleValue, MutableHandleValue);
1344 if (!tailCallVM<Fn, DoGetPropSuperFallback>(masm)) {
1345 return false;
1346 }
1347 } else {
1348 // Ensure stack is fully synced for the expression decompiler.
1349 masm.pushValue(R0);
1350
1351 // Push arguments.
1352 masm.pushValue(R0);
1353 masm.push(ICStubReg);
1354 masm.pushBaselineFramePtr(FramePointer, R0.scratchReg());
1355
1356 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*,
1357 MutableHandleValue, MutableHandleValue);
1358 if (!tailCallVM<Fn, DoGetPropFallback>(masm)) {
1359 return false;
1360 }
1361 }
1362
1363 // This is the resume point used when bailout rewrites call stack to undo
1364 // Ion inlined frames. The return address pushed onto reconstructed stack
1365 // will point here.
1366 assumeStubFrame();
1367 if (hasReceiver) {
1368 code.initBailoutReturnOffset(BailoutReturnKind::GetPropSuper,
1369 masm.currentOffset());
1370 } else {
1371 code.initBailoutReturnOffset(BailoutReturnKind::GetProp,
1372 masm.currentOffset());
1373 }
1374
1375 leaveStubFrame(masm);
1376
1377 EmitReturnFromIC(masm);
1378 return true;
1379}
1380
1381bool FallbackICCodeCompiler::emit_GetProp() {
1382 return emitGetProp(/* hasReceiver = */ false);
1383}
1384
1385bool FallbackICCodeCompiler::emit_GetPropSuper() {
1386 return emitGetProp(/* hasReceiver = */ true);
1387}
1388
1389//
1390// SetProp_Fallback
1391//
1392
1393bool DoSetPropFallback(JSContext* cx, BaselineFrame* frame,
1394 ICFallbackStub* stub, Value* stack, HandleValue lhs,
1395 HandleValue rhs) {
1396 using DeferType = SetPropIRGenerator::DeferType;
1397
1398 stub->incrementEnteredCount();
1399 MaybeNotifyWarp(frame->outerScript(), stub);
1400
1401 RootedScript script(cx, frame->script());
1402 jsbytecode* pc = StubOffsetToPc(stub, script);
1403 JSOp op = JSOp(*pc);
1404 FallbackICSpew(cx, stub, "SetProp(%s)", CodeName(op));
1405
1406 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"
, 1410); 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) = 1410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1407 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"
, 1410); 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) = 1410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1408 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"
, 1410); 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) = 1410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1409 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"
, 1410); 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) = 1410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1410 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"
, 1410); 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) = 1410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1411
1412 Rooted<PropertyName*> name(cx, script->getName(pc));
1413 RootedId id(cx, NameToId(name));
1414
1415 int lhsIndex = stack ? -2 : JSDVG_IGNORE_STACK0;
1416 RootedObject obj(cx,
1417 ToObjectFromStackForPropertyAccess(cx, lhs, lhsIndex, id));
1418 if (!obj) {
1419 return false;
1420 }
1421 Rooted<Shape*> oldShape(cx, obj->shape());
1422
1423 DeferType deferType = DeferType::None;
1424 bool attached = false;
1425 MaybeTransition(cx, frame, stub);
1426
1427 if (stub->state().canAttachStub()) {
1428 RootedValue idVal(cx, StringValue(name));
1429 SetPropIRGenerator gen(cx, script, pc, CacheKind::SetProp, stub->state(),
1430 lhs, idVal, rhs);
1431 switch (gen.tryAttachStub()) {
1432 case AttachDecision::Attach: {
1433 ICScript* icScript = frame->icScript();
1434 ICAttachResult result = AttachBaselineCacheIRStub(
1435 cx, gen.writerRef(), gen.cacheKind(), frame->script(), icScript,
1436 stub, gen.stubName());
1437 if (result == ICAttachResult::Attached) {
1438 attached = true;
1439 JitSpew(JitSpew_BaselineIC, " Attached SetProp CacheIR stub");
1440 }
1441 } break;
1442 case AttachDecision::NoAction:
1443 break;
1444 case AttachDecision::TemporarilyUnoptimizable:
1445 attached = true;
1446 break;
1447 case AttachDecision::Deferred:
1448 deferType = gen.deferType();
1449 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"
, 1449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "deferType != DeferType::None"
")"); do { *((volatile int*)__null) = 1449; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1450 break;
1451 }
1452 }
1453
1454 if (op == JSOp::InitProp || op == JSOp::InitLockedProp ||
1455 op == JSOp::InitHiddenProp) {
1456 if (!InitPropertyOperation(cx, pc, obj, name, rhs)) {
1457 return false;
1458 }
1459 } else if (op == JSOp::SetName || op == JSOp::StrictSetName ||
1460 op == JSOp::SetGName || op == JSOp::StrictSetGName) {
1461 if (!SetNameOperation(cx, script, pc, obj, rhs)) {
1462 return false;
1463 }
1464 } else if (op == JSOp::InitGLexical) {
1465 ExtensibleLexicalEnvironmentObject* lexicalEnv;
1466 if (script->hasNonSyntacticScope()) {
1467 lexicalEnv = &NearestEnclosingExtensibleLexicalEnvironment(
1468 frame->environmentChain());
1469 } else {
1470 lexicalEnv = &cx->global()->lexicalEnvironment();
1471 }
1472 InitGlobalLexicalOperation(cx, lexicalEnv, script, pc, rhs);
1473 } else {
1474 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"
, 1474); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op == JSOp::SetProp || op == JSOp::StrictSetProp"
")"); do { *((volatile int*)__null) = 1474; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1475
1476 ObjectOpResult result;
1477 if (!SetProperty(cx, obj, id, rhs, lhs, result) ||
1478 !result.checkStrictModeError(cx, obj, id, op == JSOp::StrictSetProp)) {
1479 return false;
1480 }
1481 }
1482
1483 if (stack) {
1484 // Overwrite the LHS on the stack (pushed for the decompiler) with the RHS.
1485 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"
, 1485); AnnotateMozCrashReason("MOZ_ASSERT" "(" "stack[1] == lhs"
")"); do { *((volatile int*)__null) = 1485; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1486 stack[1] = rhs;
1487 }
1488
1489 if (attached) {
1490 return true;
1491 }
1492
1493 // The SetProperty call might have entered this IC recursively, so try
1494 // to transition.
1495 MaybeTransition(cx, frame, stub);
1496
1497 bool canAttachStub = stub->state().canAttachStub();
1498
1499 if (deferType != DeferType::None && canAttachStub) {
1500 RootedValue idVal(cx, StringValue(name));
1501 SetPropIRGenerator gen(cx, script, pc, CacheKind::SetProp, stub->state(),
1502 lhs, idVal, rhs);
1503
1504 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"
, 1504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "deferType == DeferType::AddSlot"
")"); do { *((volatile int*)__null) = 1504; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1505 AttachDecision decision = gen.tryAttachAddSlotStub(oldShape);
1506
1507 switch (decision) {
1508 case AttachDecision::Attach: {
1509 ICScript* icScript = frame->icScript();
1510 ICAttachResult result = AttachBaselineCacheIRStub(
1511 cx, gen.writerRef(), gen.cacheKind(), frame->script(), icScript,
1512 stub, gen.stubName());
1513 if (result == ICAttachResult::Attached) {
1514 attached = true;
1515 JitSpew(JitSpew_BaselineIC, " Attached SetElem CacheIR stub");
1516 }
1517 } break;
1518 case AttachDecision::NoAction:
1519 gen.trackAttached(IRGenerator::NotAttached);
1520 break;
1521 case AttachDecision::TemporarilyUnoptimizable:
1522 case AttachDecision::Deferred:
1523 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"
, 1523); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Invalid attach result" ")"); do {
*((volatile int*)__null) = 1523; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1524 break;
1525 }
1526 }
1527 if (!attached && canAttachStub) {
1528 stub->trackNotAttached();
1529 }
1530
1531 return true;
1532}
1533
1534bool FallbackICCodeCompiler::emit_SetProp() {
1535 static_assert(R0 == JSReturnOperand);
1536
1537 EmitRestoreTailCallReg(masm);
1538
1539 // Ensure stack is fully synced for the expression decompiler.
1540 // Overwrite the RHS value on top of the stack with the object, then push
1541 // the RHS in R1 on top of that.
1542 masm.storeValue(R0, Address(masm.getStackPointer(), 0));
1543 masm.pushValue(R1);
1544
1545 // Push arguments.
1546 masm.pushValue(R1);
1547 masm.pushValue(R0);
1548
1549 // Push pointer to stack values, so that the stub can overwrite the object
1550 // (pushed for the decompiler) with the RHS.
1551 masm.computeEffectiveAddress(
1552 Address(masm.getStackPointer(), 2 * sizeof(Value)), R0.scratchReg());
1553 masm.push(R0.scratchReg());
1554
1555 masm.push(ICStubReg);
1556 pushStubPayload(masm, R0.scratchReg());
1557
1558 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, Value*,
1559 HandleValue, HandleValue);
1560 if (!tailCallVM<Fn, DoSetPropFallback>(masm)) {
1561 return false;
1562 }
1563
1564 // This is the resume point used when bailout rewrites call stack to undo
1565 // Ion inlined frames. The return address pushed onto reconstructed stack
1566 // will point here.
1567 assumeStubFrame();
1568 code.initBailoutReturnOffset(BailoutReturnKind::SetProp,
1569 masm.currentOffset());
1570
1571 leaveStubFrame(masm);
1572 EmitReturnFromIC(masm);
1573
1574 return true;
1575}
1576
1577//
1578// Call_Fallback
1579//
1580
1581bool DoCallFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
1582 uint32_t argc, Value* vp, MutableHandleValue res) {
1583 stub->incrementEnteredCount();
1584 MaybeNotifyWarp(frame->outerScript(), stub);
1585
1586 RootedScript script(cx, frame->script());
1587 jsbytecode* pc = StubOffsetToPc(stub, script);
1588 JSOp op = JSOp(*pc);
1589 FallbackICSpew(cx, stub, "Call(%s)", CodeName(op));
1590
1591 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"
, 1591); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc == GET_ARGC(pc)"
")"); do { *((volatile int*)__null) = 1591; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1592 bool constructing =
1593 (op == JSOp::New || op == JSOp::NewContent || op == JSOp::SuperCall);
1594 bool ignoresReturnValue = (op == JSOp::CallIgnoresRv);
1595
1596 // Ensure vp array is rooted - we may GC in here.
1597 size_t numValues = argc + 2 + constructing;
1598 RootedExternalValueArray vpRoot(cx, numValues, vp);
1599
1600 CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues,
1601 constructing, ignoresReturnValue);
1602 RootedValue callee(cx, vp[0]);
1603 RootedValue newTarget(cx, constructing ? callArgs.newTarget() : NullValue());
1604
1605 // Transition stub state to megamorphic or generic if warranted.
1606 MaybeTransition(cx, frame, stub);
1607
1608 bool canAttachStub = stub->state().canAttachStub();
1609 bool handled = false;
1610
1611 // Only bother to try optimizing JSOp::Call with CacheIR if the chain is still
1612 // allowed to attach stubs.
1613 if (canAttachStub) {
1614 HandleValueArray args = HandleValueArray::fromMarkedLocation(argc, vp + 2);
1615 CallIRGenerator gen(cx, script, pc, op, stub->state(), argc, callee,
1616 callArgs.thisv(), newTarget, args);
1617 switch (gen.tryAttachStub()) {
1618 case AttachDecision::NoAction:
1619 break;
1620 case AttachDecision::Attach: {
1621 ICScript* icScript = frame->icScript();
1622 ICAttachResult result =
1623 AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
1624 script, icScript, stub, gen.stubName());
1625 if (result == ICAttachResult::Attached) {
1626 handled = true;
1627 JitSpew(JitSpew_BaselineIC, " Attached Call CacheIR stub");
1628 }
1629 } break;
1630 case AttachDecision::TemporarilyUnoptimizable:
1631 handled = true;
1632 break;
1633 case AttachDecision::Deferred:
1634 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"
, 1634); AnnotateMozCrashReason("MOZ_CRASH(" "No deferred Call stubs"
")"); do { *((volatile int*)__null) = 1634; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1635 }
1636 if (!handled) {
1637 stub->trackNotAttached();
1638 }
1639 }
1640
1641 if (constructing) {
1642 if (!ConstructFromStack(cx, callArgs)) {
1643 return false;
1644 }
1645 res.set(callArgs.rval());
1646 } else if ((op == JSOp::Eval || op == JSOp::StrictEval) &&
1647 cx->global()->valueIsEval(callee)) {
1648 if (!DirectEval(cx, callArgs.get(0), res)) {
1649 return false;
1650 }
1651 } else {
1652 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"
, 1655); 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) = 1655; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1653 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"
, 1655); 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) = 1655; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1654 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"
, 1655); 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) = 1655; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1655 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"
, 1655); 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) = 1655; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1656 if ((op == JSOp::CallIter || op == JSOp::CallContentIter) &&
1657 callee.isPrimitive()) {
1658 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"
, 1658); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc == 0" ") ("
"thisv must be on top of the stack" ")"); do { *((volatile int
*)__null) = 1658; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1659 ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, callArgs.thisv(), nullptr);
1660 return false;
1661 }
1662
1663 if (!CallFromStack(cx, callArgs)) {
1664 return false;
1665 }
1666
1667 res.set(callArgs.rval());
1668 }
1669
1670 return true;
1671}
1672
1673bool DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame,
1674 ICFallbackStub* stub, Value* vp,
1675 MutableHandleValue res) {
1676 stub->incrementEnteredCount();
1677 MaybeNotifyWarp(frame->outerScript(), stub);
1678
1679 RootedScript script(cx, frame->script());
1680 jsbytecode* pc = StubOffsetToPc(stub, script);
1681 JSOp op = JSOp(*pc);
1682 bool constructing = (op == JSOp::SpreadNew || op == JSOp::SpreadSuperCall);
1683 FallbackICSpew(cx, stub, "SpreadCall(%s)", CodeName(op));
1684
1685 // Ensure vp array is rooted - we may GC in here.
1686 RootedExternalValueArray vpRoot(cx, 3 + constructing, vp);
1687
1688 RootedValue callee(cx, vp[0]);
1689 RootedValue thisv(cx, vp[1]);
1690 RootedValue arr(cx, vp[2]);
1691 RootedValue newTarget(cx, constructing ? vp[3] : NullValue());
1692
1693 // Transition stub state to megamorphic or generic if warranted.
1694 MaybeTransition(cx, frame, stub);
1695
1696 // Try attaching a call stub.
1697 bool handled = false;
1698 if (op != JSOp::SpreadEval && op != JSOp::StrictSpreadEval &&
1699 stub->state().canAttachStub()) {
1700 // Try CacheIR first:
1701 Rooted<ArrayObject*> aobj(cx, &arr.toObject().as<ArrayObject>());
1702 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"
, 1702); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPackedArray(aobj)"
")"); do { *((volatile int*)__null) = 1702; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1703
1704 HandleValueArray args = HandleValueArray::fromMarkedLocation(
1705 aobj->length(), aobj->getDenseElements());
1706 CallIRGenerator gen(cx, script, pc, op, stub->state(), 1, callee, thisv,
1707 newTarget, args);
1708 switch (gen.tryAttachStub()) {
1709 case AttachDecision::NoAction:
1710 break;
1711 case AttachDecision::Attach: {
1712 ICScript* icScript = frame->icScript();
1713 ICAttachResult result =
1714 AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
1715 script, icScript, stub, gen.stubName());
1716
1717 if (result == ICAttachResult::Attached) {
1718 handled = true;
1719 JitSpew(JitSpew_BaselineIC, " Attached Spread Call CacheIR stub");
1720 }
1721 } break;
1722 case AttachDecision::TemporarilyUnoptimizable:
1723 handled = true;
1724 break;
1725 case AttachDecision::Deferred:
1726 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"
, 1726); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "No deferred optimizations for spread calls"
")"); do { *((volatile int*)__null) = 1726; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1727 break;
1728 }
1729 if (!handled) {
1730 stub->trackNotAttached();
1731 }
1732 }
1733
1734 return SpreadCallOperation(cx, script, pc, thisv, callee, arr, newTarget,
1735 res);
1736}
1737
1738void FallbackICCodeCompiler::pushCallArguments(
1739 MacroAssembler& masm, AllocatableGeneralRegisterSet regs, Register argcReg,
1740 bool isConstructing) {
1741 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"
, 1741); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!regs.has(argcReg)"
")"); do { *((volatile int*)__null) = 1741; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1742
1743 // argPtr initially points to the last argument.
1744 Register argPtr = regs.takeAny();
1745 masm.mov(FramePointer, argPtr);
1746
1747 // Skip 3 pointers pushed on top of the arguments: the frame descriptor,
1748 // return address, and old frame pointer.
1749 size_t valueOffset = BaselineStubFrameLayout::Size();
1750
1751 // We have to push |this|, callee, new.target (if constructing) and argc
1752 // arguments. Handle the number of Values we know statically first.
1753
1754 size_t numNonArgValues = 2 + isConstructing;
1755 for (size_t i = 0; i < numNonArgValues; i++) {
1756 masm.pushValue(Address(argPtr, valueOffset));
1757 valueOffset += sizeof(Value);
1758 }
1759
1760 // If there are no arguments we're done.
1761 Label done;
1762 masm.branchTest32(Assembler::Zero, argcReg, argcReg, &done);
1763
1764 // Push argc Values.
1765 Label loop;
1766 Register count = regs.takeAny();
1767 masm.addPtr(Imm32(valueOffset), argPtr);
1768 masm.move32(argcReg, count);
1769 masm.bind(&loop);
1770 {
1771 masm.pushValue(Address(argPtr, 0));
1772 masm.addPtr(Imm32(sizeof(Value)), argPtr);
1773
1774 masm.branchSub32(Assembler::NonZero, Imm32(1), count, &loop);
1775 }
1776 masm.bind(&done);
1777}
1778
1779bool FallbackICCodeCompiler::emitCall(bool isSpread, bool isConstructing) {
1780 static_assert(R0 == JSReturnOperand);
1781
1782 // Values are on the stack left-to-right. Calling convention wants them
1783 // right-to-left so duplicate them on the stack in reverse order.
1784 // |this| and callee are pushed last.
1785
1786 AllocatableGeneralRegisterSet regs = BaselineICAvailableGeneralRegs(0);
1787
1788 if (MOZ_UNLIKELY(isSpread)(__builtin_expect(!!(isSpread), 0))) {
1789 // Push a stub frame so that we can perform a non-tail call.
1790 enterStubFrame(masm, R1.scratchReg());
1791
1792 // Use FramePointer instead of StackPointer because it's not affected by
1793 // the stack pushes below.
1794
1795 // newTarget
1796 uint32_t valueOffset = BaselineStubFrameLayout::Size();
1797 if (isConstructing) {
1798 masm.pushValue(Address(FramePointer, valueOffset));
1799 valueOffset += sizeof(Value);
1800 }
1801
1802 // array
1803 masm.pushValue(Address(FramePointer, valueOffset));
1804 valueOffset += sizeof(Value);
1805
1806 // this
1807 masm.pushValue(Address(FramePointer, valueOffset));
1808 valueOffset += sizeof(Value);
1809
1810 // callee
1811 masm.pushValue(Address(FramePointer, valueOffset));
1812 valueOffset += sizeof(Value);
Value stored to 'valueOffset' is never read
1813
1814 masm.push(masm.getStackPointer());
1815 masm.push(ICStubReg);
1816
1817 PushStubPayload(masm, R0.scratchReg());
1818
1819 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, Value*,
1820 MutableHandleValue);
1821 if (!callVM<Fn, DoSpreadCallFallback>(masm)) {
1822 return false;
1823 }
1824
1825 leaveStubFrame(masm);
1826 EmitReturnFromIC(masm);
1827
1828 // SpreadCall is not yet supported in Ion, so do not generate asmcode for
1829 // bailout.
1830 return true;
1831 }
1832
1833 // Push a stub frame so that we can perform a non-tail call.
1834 enterStubFrame(masm, R1.scratchReg());
1835
1836 regs.take(R0.scratchReg()); // argc.
1837
1838 pushCallArguments(masm, regs, R0.scratchReg(), isConstructing);
1839
1840 masm.push(masm.getStackPointer());
1841 masm.push(R0.scratchReg());
1842 masm.push(ICStubReg);
1843
1844 PushStubPayload(masm, R0.scratchReg());
1845
1846 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, uint32_t,
1847 Value*, MutableHandleValue);
1848 if (!callVM<Fn, DoCallFallback>(masm)) {
1849 return false;
1850 }
1851
1852 leaveStubFrame(masm);
1853 EmitReturnFromIC(masm);
1854
1855 // This is the resume point used when bailout rewrites call stack to undo
1856 // Ion inlined frames. The return address pushed onto reconstructed stack
1857 // will point here.
1858 assumeStubFrame();
1859
1860 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"
, 1860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isSpread" ")"
); do { *((volatile int*)__null) = 1860; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1861
1862 if (isConstructing) {
1863 code.initBailoutReturnOffset(BailoutReturnKind::New, masm.currentOffset());
1864 } else {
1865 code.initBailoutReturnOffset(BailoutReturnKind::Call, masm.currentOffset());
1866 }
1867
1868 // Load passed-in ThisV into R1 just in case it's needed. Need to do this
1869 // before we leave the stub frame since that info will be lost.
1870 // Current stack: [...., ThisV, CalleeToken, Descriptor ]
1871 size_t thisvOffset =
1872 JitFrameLayout::offsetOfThis() - JitFrameLayout::bytesPoppedAfterCall();
1873 masm.loadValue(Address(masm.getStackPointer(), thisvOffset), R1);
1874
1875 leaveStubFrame(masm);
1876
1877 // If this is a |constructing| call, if the callee returns a non-object, we
1878 // replace it with the |this| object passed in.
1879 if (isConstructing) {
1880 static_assert(JSReturnOperand == R0);
1881 Label skipThisReplace;
1882
1883 masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
1884 masm.moveValue(R1, R0);
1885#ifdef DEBUG1
1886 masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
1887 masm.assumeUnreachable("Failed to return object in constructing call.");
1888#endif
1889 masm.bind(&skipThisReplace);
1890 }
1891
1892 EmitReturnFromIC(masm);
1893 return true;
1894}
1895
1896bool FallbackICCodeCompiler::emit_Call() {
1897 return emitCall(/* isSpread = */ false, /* isConstructing = */ false);
1898}
1899
1900bool FallbackICCodeCompiler::emit_CallConstructing() {
1901 return emitCall(/* isSpread = */ false, /* isConstructing = */ true);
1902}
1903
1904bool FallbackICCodeCompiler::emit_SpreadCall() {
1905 return emitCall(/* isSpread = */ true, /* isConstructing = */ false);
1906}
1907
1908bool FallbackICCodeCompiler::emit_SpreadCallConstructing() {
1909 return emitCall(/* isSpread = */ true, /* isConstructing = */ true);
1910}
1911
1912//
1913// GetIterator_Fallback
1914//
1915
1916bool DoGetIteratorFallback(JSContext* cx, BaselineFrame* frame,
1917 ICFallbackStub* stub, HandleValue value,
1918 MutableHandleValue res) {
1919 stub->incrementEnteredCount();
1920 MaybeNotifyWarp(frame->outerScript(), stub);
1921 FallbackICSpew(cx, stub, "GetIterator");
1922
1923 TryAttachStub<GetIteratorIRGenerator>("GetIterator", cx, frame, stub, value);
1924
1925 PropertyIteratorObject* iterObj = ValueToIterator(cx, value);
1926 if (!iterObj) {
1927 return false;
1928 }
1929
1930 res.setObject(*iterObj);
1931 return true;
1932}
1933
1934bool FallbackICCodeCompiler::emit_GetIterator() {
1935 EmitRestoreTailCallReg(masm);
1936
1937 // Sync stack for the decompiler.
1938 masm.pushValue(R0);
1939
1940 masm.pushValue(R0);
1941 masm.push(ICStubReg);
1942 pushStubPayload(masm, R0.scratchReg());
1943
1944 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1945 MutableHandleValue);
1946 return tailCallVM<Fn, DoGetIteratorFallback>(masm);
1947}
1948
1949//
1950// OptimizeSpreadCall_Fallback
1951//
1952
1953bool DoOptimizeSpreadCallFallback(JSContext* cx, BaselineFrame* frame,
1954 ICFallbackStub* stub, HandleValue value,
1955 MutableHandleValue res) {
1956 stub->incrementEnteredCount();
1957 MaybeNotifyWarp(frame->outerScript(), stub);
1958 FallbackICSpew(cx, stub, "OptimizeSpreadCall");
1959
1960 TryAttachStub<OptimizeSpreadCallIRGenerator>("OptimizeSpreadCall", cx, frame,
1961 stub, value);
1962
1963 return OptimizeSpreadCall(cx, value, res);
1964}
1965
1966bool FallbackICCodeCompiler::emit_OptimizeSpreadCall() {
1967 EmitRestoreTailCallReg(masm);
1968
1969 masm.pushValue(R0);
1970 masm.push(ICStubReg);
1971 pushStubPayload(masm, R0.scratchReg());
1972
1973 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
1974 MutableHandleValue);
1975 return tailCallVM<Fn, DoOptimizeSpreadCallFallback>(masm);
1976}
1977
1978//
1979// InstanceOf_Fallback
1980//
1981
1982bool DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame,
1983 ICFallbackStub* stub, HandleValue lhs,
1984 HandleValue rhs, MutableHandleValue res) {
1985 stub->incrementEnteredCount();
1986 MaybeNotifyWarp(frame->outerScript(), stub);
1987 FallbackICSpew(cx, stub, "InstanceOf");
1988
1989 if (!rhs.isObject()) {
1990 ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rhs, nullptr);
1991 return false;
1992 }
1993
1994 RootedObject obj(cx, &rhs.toObject());
1995 bool cond = false;
1996 if (!InstanceofOperator(cx, obj, lhs, &cond)) {
1997 return false;
1998 }
1999
2000 res.setBoolean(cond);
2001
2002 if (!obj->is<JSFunction>()) {
2003 // ensure we've recorded at least one failure, so we can detect there was a
2004 // non-optimizable case
2005 if (!stub->state().hasFailures()) {
2006 stub->trackNotAttached();
2007 }
2008 return true;
2009 }
2010
2011 TryAttachStub<InstanceOfIRGenerator>("InstanceOf", cx, frame, stub, lhs, obj);
2012 return true;
2013}
2014
2015bool FallbackICCodeCompiler::emit_InstanceOf() {
2016 EmitRestoreTailCallReg(masm);
2017
2018 // Sync stack for the decompiler.
2019 masm.pushValue(R0);
2020 masm.pushValue(R1);
2021
2022 masm.pushValue(R1);
2023 masm.pushValue(R0);
2024 masm.push(ICStubReg);
2025 pushStubPayload(masm, R0.scratchReg());
2026
2027 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2028 HandleValue, MutableHandleValue);
2029 return tailCallVM<Fn, DoInstanceOfFallback>(masm);
2030}
2031
2032//
2033// TypeOf_Fallback
2034//
2035
2036bool DoTypeOfFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
2037 HandleValue val, MutableHandleValue res) {
2038 stub->incrementEnteredCount();
2039 MaybeNotifyWarp(frame->outerScript(), stub);
2040 FallbackICSpew(cx, stub, "TypeOf");
2041
2042 TryAttachStub<TypeOfIRGenerator>("TypeOf", cx, frame, stub, val);
2043
2044 JSType type = js::TypeOfValue(val);
2045 RootedString string(cx, TypeName(type, cx->names()));
2046 res.setString(string);
2047 return true;
2048}
2049
2050bool FallbackICCodeCompiler::emit_TypeOf() {
2051 EmitRestoreTailCallReg(masm);
2052
2053 masm.pushValue(R0);
2054 masm.push(ICStubReg);
2055 pushStubPayload(masm, R0.scratchReg());
2056
2057 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2058 MutableHandleValue);
2059 return tailCallVM<Fn, DoTypeOfFallback>(masm);
2060}
2061
2062//
2063// TypeOfEq_Fallback
2064//
2065
2066bool DoTypeOfEqFallback(JSContext* cx, BaselineFrame* frame,
2067 ICFallbackStub* stub, HandleValue val,
2068 MutableHandleValue res) {
2069 stub->incrementEnteredCount();
2070 MaybeNotifyWarp(frame->outerScript(), stub);
2071 FallbackICSpew(cx, stub, "TypeOfEq");
2072
2073 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2074 auto operand = TypeofEqOperand::fromRawValue(GET_UINT8(pc));
2075 JSType type = operand.type();
2076 JSOp compareOp = operand.compareOp();
2077
2078 TryAttachStub<TypeOfEqIRGenerator>("TypeOfEq", cx, frame, stub, val, type,
2079 compareOp);
2080
2081 bool result = js::TypeOfValue(val) == type;
2082 if (compareOp == JSOp::Ne) {
2083 result = !result;
2084 }
2085 res.setBoolean(result);
2086 return true;
2087}
2088
2089bool FallbackICCodeCompiler::emit_TypeOfEq() {
2090 EmitRestoreTailCallReg(masm);
2091
2092 masm.pushValue(R0);
2093 masm.push(ICStubReg);
2094 pushStubPayload(masm, R0.scratchReg());
2095
2096 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2097 MutableHandleValue);
2098 return tailCallVM<Fn, DoTypeOfEqFallback>(masm);
2099}
2100
2101//
2102// ToPropertyKey_Fallback
2103//
2104
2105bool DoToPropertyKeyFallback(JSContext* cx, BaselineFrame* frame,
2106 ICFallbackStub* stub, HandleValue val,
2107 MutableHandleValue res) {
2108 stub->incrementEnteredCount();
2109 MaybeNotifyWarp(frame->outerScript(), stub);
2110 FallbackICSpew(cx, stub, "ToPropertyKey");
2111
2112 TryAttachStub<ToPropertyKeyIRGenerator>("ToPropertyKey", cx, frame, stub,
2113 val);
2114
2115 return ToPropertyKeyOperation(cx, val, res);
2116}
2117
2118bool FallbackICCodeCompiler::emit_ToPropertyKey() {
2119 EmitRestoreTailCallReg(masm);
2120
2121 masm.pushValue(R0);
2122 masm.push(ICStubReg);
2123 pushStubPayload(masm, R0.scratchReg());
2124
2125 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2126 MutableHandleValue);
2127 return tailCallVM<Fn, DoToPropertyKeyFallback>(masm);
2128}
2129
2130//
2131// Rest_Fallback
2132//
2133
2134bool DoRestFallback(JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub,
2135 MutableHandleValue res) {
2136 unsigned numFormals = frame->numFormalArgs() - 1;
2137 unsigned numActuals = frame->numActualArgs();
2138 unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
2139 Value* rest = frame->argv() + numFormals;
2140
2141 ArrayObject* obj = NewDenseCopiedArray(cx, numRest, rest);
2142 if (!obj) {
2143 return false;
2144 }
2145 res.setObject(*obj);
2146 return true;
2147}
2148
2149bool FallbackICCodeCompiler::emit_Rest() {
2150 EmitRestoreTailCallReg(masm);
2151
2152 masm.push(ICStubReg);
2153 pushStubPayload(masm, R0.scratchReg());
2154
2155 using Fn =
2156 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, MutableHandleValue);
2157 return tailCallVM<Fn, DoRestFallback>(masm);
2158}
2159
2160//
2161// UnaryArith_Fallback
2162//
2163
2164bool DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame,
2165 ICFallbackStub* stub, HandleValue val,
2166 MutableHandleValue res) {
2167 stub->incrementEnteredCount();
2168 MaybeNotifyWarp(frame->outerScript(), stub);
2169
2170 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2171 JSOp op = JSOp(*pc);
2172 FallbackICSpew(cx, stub, "UnaryArith(%s)", CodeName(op));
2173
2174 switch (op) {
2175 case JSOp::BitNot: {
2176 res.set(val);
2177 if (!BitNot(cx, res, res)) {
2178 return false;
2179 }
2180 break;
2181 }
2182 case JSOp::Pos: {
2183 res.set(val);
2184 if (!ToNumber(cx, res)) {
2185 return false;
2186 }
2187 break;
2188 }
2189 case JSOp::Neg: {
2190 res.set(val);
2191 if (!NegOperation(cx, res, res)) {
2192 return false;
2193 }
2194 break;
2195 }
2196 case JSOp::Inc: {
2197 if (!IncOperation(cx, val, res)) {
2198 return false;
2199 }
2200 break;
2201 }
2202 case JSOp::Dec: {
2203 if (!DecOperation(cx, val, res)) {
2204 return false;
2205 }
2206 break;
2207 }
2208 case JSOp::ToNumeric: {
2209 res.set(val);
2210 if (!ToNumeric(cx, res)) {
2211 return false;
2212 }
2213 break;
2214 }
2215 default:
2216 MOZ_CRASH("Unexpected op")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/BaselineIC.cpp"
, 2216); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op" ")"
); do { *((volatile int*)__null) = 2216; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2217 }
2218 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"
, 2218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "res.isNumeric()"
")"); do { *((volatile int*)__null) = 2218; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2219
2220 TryAttachStub<UnaryArithIRGenerator>("UnaryArith", cx, frame, stub, op, val,
2221 res);
2222 return true;
2223}
2224
2225bool FallbackICCodeCompiler::emit_UnaryArith() {
2226 static_assert(R0 == JSReturnOperand);
2227
2228 // Restore the tail call register.
2229 EmitRestoreTailCallReg(masm);
2230
2231 // Ensure stack is fully synced for the expression decompiler.
2232 masm.pushValue(R0);
2233
2234 // Push arguments.
2235 masm.pushValue(R0);
2236 masm.push(ICStubReg);
2237 pushStubPayload(masm, R0.scratchReg());
2238
2239 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2240 MutableHandleValue);
2241 return tailCallVM<Fn, DoUnaryArithFallback>(masm);
2242}
2243
2244//
2245// BinaryArith_Fallback
2246//
2247
2248bool DoBinaryArithFallback(JSContext* cx, BaselineFrame* frame,
2249 ICFallbackStub* stub, HandleValue lhs,
2250 HandleValue rhs, MutableHandleValue ret) {
2251 stub->incrementEnteredCount();
2252 MaybeNotifyWarp(frame->outerScript(), stub);
2253
2254 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2255 JSOp op = JSOp(*pc);
2256 FallbackICSpew(
2257 cx, stub, "CacheIRBinaryArith(%s,%d,%d)", CodeName(op),
2258 int(lhs.isDouble() ? JSVAL_TYPE_DOUBLE : lhs.extractNonDoubleType()),
2259 int(rhs.isDouble() ? JSVAL_TYPE_DOUBLE : rhs.extractNonDoubleType()));
2260
2261 // Don't pass lhs/rhs directly, we need the original values when
2262 // generating stubs.
2263 RootedValue lhsCopy(cx, lhs);
2264 RootedValue rhsCopy(cx, rhs);
2265
2266 // Perform the arith operation.
2267 switch (op) {
2268 case JSOp::Add:
2269 // Do an add.
2270 if (!AddValues(cx, &lhsCopy, &rhsCopy, ret)) {
2271 return false;
2272 }
2273 break;
2274 case JSOp::Sub:
2275 if (!SubValues(cx, &lhsCopy, &rhsCopy, ret)) {
2276 return false;
2277 }
2278 break;
2279 case JSOp::Mul:
2280 if (!MulValues(cx, &lhsCopy, &rhsCopy, ret)) {
2281 return false;
2282 }
2283 break;
2284 case JSOp::Div:
2285 if (!DivValues(cx, &lhsCopy, &rhsCopy, ret)) {
2286 return false;
2287 }
2288 break;
2289 case JSOp::Mod:
2290 if (!ModValues(cx, &lhsCopy, &rhsCopy, ret)) {
2291 return false;
2292 }
2293 break;
2294 case JSOp::Pow:
2295 if (!PowValues(cx, &lhsCopy, &rhsCopy, ret)) {
2296 return false;
2297 }
2298 break;
2299 case JSOp::BitOr: {
2300 if (!BitOr(cx, &lhsCopy, &rhsCopy, ret)) {
2301 return false;
2302 }
2303 break;
2304 }
2305 case JSOp::BitXor: {
2306 if (!BitXor(cx, &lhsCopy, &rhsCopy, ret)) {
2307 return false;
2308 }
2309 break;
2310 }
2311 case JSOp::BitAnd: {
2312 if (!BitAnd(cx, &lhsCopy, &rhsCopy, ret)) {
2313 return false;
2314 }
2315 break;
2316 }
2317 case JSOp::Lsh: {
2318 if (!BitLsh(cx, &lhsCopy, &rhsCopy, ret)) {
2319 return false;
2320 }
2321 break;
2322 }
2323 case JSOp::Rsh: {
2324 if (!BitRsh(cx, &lhsCopy, &rhsCopy, ret)) {
2325 return false;
2326 }
2327 break;
2328 }
2329 case JSOp::Ursh: {
2330 if (!UrshValues(cx, &lhsCopy, &rhsCopy, ret)) {
2331 return false;
2332 }
2333 break;
2334 }
2335 default:
2336 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"
, 2336); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled baseline arith op"
")"); do { *((volatile int*)__null) = 2336; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2337 }
2338
2339 TryAttachStub<BinaryArithIRGenerator>("BinaryArith", cx, frame, stub, op, lhs,
2340 rhs, ret);
2341 return true;
2342}
2343
2344bool FallbackICCodeCompiler::emit_BinaryArith() {
2345 static_assert(R0 == JSReturnOperand);
2346
2347 // Restore the tail call register.
2348 EmitRestoreTailCallReg(masm);
2349
2350 // Ensure stack is fully synced for the expression decompiler.
2351 masm.pushValue(R0);
2352 masm.pushValue(R1);
2353
2354 // Push arguments.
2355 masm.pushValue(R1);
2356 masm.pushValue(R0);
2357 masm.push(ICStubReg);
2358 pushStubPayload(masm, R0.scratchReg());
2359
2360 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2361 HandleValue, MutableHandleValue);
2362 return tailCallVM<Fn, DoBinaryArithFallback>(masm);
2363}
2364
2365//
2366// Compare_Fallback
2367//
2368bool DoCompareFallback(JSContext* cx, BaselineFrame* frame,
2369 ICFallbackStub* stub, HandleValue lhs, HandleValue rhs,
2370 MutableHandleValue ret) {
2371 stub->incrementEnteredCount();
2372 MaybeNotifyWarp(frame->outerScript(), stub);
2373
2374 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2375 JSOp op = JSOp(*pc);
2376
2377 FallbackICSpew(cx, stub, "Compare(%s)", CodeName(op));
2378
2379 // Don't pass lhs/rhs directly, we need the original values when
2380 // generating stubs.
2381 RootedValue lhsCopy(cx, lhs);
2382 RootedValue rhsCopy(cx, rhs);
2383
2384 // Perform the compare operation.
2385 bool out;
2386 switch (op) {
2387 case JSOp::Lt:
2388 if (!LessThan(cx, &lhsCopy, &rhsCopy, &out)) {
2389 return false;
2390 }
2391 break;
2392 case JSOp::Le:
2393 if (!LessThanOrEqual(cx, &lhsCopy, &rhsCopy, &out)) {
2394 return false;
2395 }
2396 break;
2397 case JSOp::Gt:
2398 if (!GreaterThan(cx, &lhsCopy, &rhsCopy, &out)) {
2399 return false;
2400 }
2401 break;
2402 case JSOp::Ge:
2403 if (!GreaterThanOrEqual(cx, &lhsCopy, &rhsCopy, &out)) {
2404 return false;
2405 }
2406 break;
2407 case JSOp::Eq:
2408 if (!js::LooselyEqual(cx, lhsCopy, rhsCopy, &out)) {
2409 return false;
2410 }
2411 break;
2412 case JSOp::Ne:
2413 if (!js::LooselyEqual(cx, lhsCopy, rhsCopy, &out)) {
2414 return false;
2415 }
2416 out = !out;
2417 break;
2418 case JSOp::StrictEq:
2419 if (!js::StrictlyEqual(cx, lhsCopy, rhsCopy, &out)) {
2420 return false;
2421 }
2422 break;
2423 case JSOp::StrictNe:
2424 if (!js::StrictlyEqual(cx, lhsCopy, rhsCopy, &out)) {
2425 return false;
2426 }
2427 out = !out;
2428 break;
2429 default:
2430 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"
, 2430); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unhandled baseline compare op" ")"
); do { *((volatile int*)__null) = 2430; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2431 return false;
2432 }
2433
2434 ret.setBoolean(out);
2435
2436 TryAttachStub<CompareIRGenerator>("Compare", cx, frame, stub, op, lhs, rhs);
2437 return true;
2438}
2439
2440bool FallbackICCodeCompiler::emit_Compare() {
2441 static_assert(R0 == JSReturnOperand);
2442
2443 // Restore the tail call register.
2444 EmitRestoreTailCallReg(masm);
2445
2446 // Ensure stack is fully synced for the expression decompiler.
2447 masm.pushValue(R0);
2448 masm.pushValue(R1);
2449
2450 // Push arguments.
2451 masm.pushValue(R1);
2452 masm.pushValue(R0);
2453 masm.push(ICStubReg);
2454 pushStubPayload(masm, R0.scratchReg());
2455
2456 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2457 HandleValue, MutableHandleValue);
2458 return tailCallVM<Fn, DoCompareFallback>(masm);
2459}
2460
2461//
2462// NewArray_Fallback
2463//
2464
2465bool DoNewArrayFallback(JSContext* cx, BaselineFrame* frame,
2466 ICFallbackStub* stub, MutableHandleValue res) {
2467 stub->incrementEnteredCount();
2468 MaybeNotifyWarp(frame->outerScript(), stub);
2469 FallbackICSpew(cx, stub, "NewArray");
2470
2471 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2472
2473 uint32_t length = GET_UINT32(pc);
2474 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"
, 2476); 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) = 2476; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
2475 "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"
, 2476); 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) = 2476; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
2476 "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"
, 2476); 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) = 2476; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2477
2478 Rooted<ArrayObject*> array(cx, NewArrayOperation(cx, length));
2479 if (!array) {
2480 return false;
2481 }
2482
2483 TryAttachStub<NewArrayIRGenerator>("NewArray", cx, frame, stub, JSOp(*pc),
2484 array, frame);
2485
2486 res.setObject(*array);
2487 return true;
2488}
2489
2490bool FallbackICCodeCompiler::emit_NewArray() {
2491 EmitRestoreTailCallReg(masm);
2492
2493 masm.push(ICStubReg); // stub.
2494 masm.pushBaselineFramePtr(FramePointer, R0.scratchReg());
2495
2496 using Fn =
2497 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, MutableHandleValue);
2498 return tailCallVM<Fn, DoNewArrayFallback>(masm);
2499}
2500
2501//
2502// NewObject_Fallback
2503//
2504bool DoNewObjectFallback(JSContext* cx, BaselineFrame* frame,
2505 ICFallbackStub* stub, MutableHandleValue res) {
2506 stub->incrementEnteredCount();
2507 MaybeNotifyWarp(frame->outerScript(), stub);
2508 FallbackICSpew(cx, stub, "NewObject");
2509
2510 RootedScript script(cx, frame->script());
2511 jsbytecode* pc = StubOffsetToPc(stub, script);
2512
2513 RootedObject obj(cx, NewObjectOperation(cx, script, pc));
2514 if (!obj) {
2515 return false;
2516 }
2517
2518 TryAttachStub<NewObjectIRGenerator>("NewObject", cx, frame, stub, JSOp(*pc),
2519 obj, frame);
2520
2521 res.setObject(*obj);
2522 return true;
2523}
2524
2525bool FallbackICCodeCompiler::emit_NewObject() {
2526 EmitRestoreTailCallReg(masm);
2527
2528 masm.push(ICStubReg); // stub.
2529 pushStubPayload(masm, R0.scratchReg());
2530
2531 using Fn =
2532 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, MutableHandleValue);
2533 return tailCallVM<Fn, DoNewObjectFallback>(masm);
2534}
2535
2536//
2537// CloseIter_Fallback
2538//
2539
2540bool DoCloseIterFallback(JSContext* cx, BaselineFrame* frame,
2541 ICFallbackStub* stub, HandleObject iter) {
2542 stub->incrementEnteredCount();
2543 MaybeNotifyWarp(frame->outerScript(), stub);
2544 FallbackICSpew(cx, stub, "CloseIter");
2545
2546 jsbytecode* pc = StubOffsetToPc(stub, frame->script());
2547 CompletionKind kind = CompletionKind(GET_UINT8(pc));
2548
2549 TryAttachStub<CloseIterIRGenerator>("CloseIter", cx, frame, stub, iter, kind);
2550
2551 return CloseIterOperation(cx, iter, kind);
2552}
2553
2554bool FallbackICCodeCompiler::emit_CloseIter() {
2555 EmitRestoreTailCallReg(masm);
2556
2557 masm.push(R0.scratchReg());
2558 masm.push(ICStubReg);
2559 pushStubPayload(masm, R0.scratchReg());
2560
2561 using Fn =
2562 bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleObject);
2563 return tailCallVM<Fn, DoCloseIterFallback>(masm);
2564}
2565
2566//
2567// OptimizeGetIterator_Fallback
2568//
2569
2570bool DoOptimizeGetIteratorFallback(JSContext* cx, BaselineFrame* frame,
2571 ICFallbackStub* stub, HandleValue value,
2572 MutableHandleValue res) {
2573 stub->incrementEnteredCount();
2574 MaybeNotifyWarp(frame->outerScript(), stub);
2575 FallbackICSpew(cx, stub, "OptimizeGetIterator");
2576
2577 TryAttachStub<OptimizeGetIteratorIRGenerator>("OptimizeGetIterator", cx,
2578 frame, stub, value);
2579
2580 bool result;
2581 if (!OptimizeGetIterator(cx, value, &result)) {
2582 return false;
2583 }
2584 res.setBoolean(result);
2585 return true;
2586}
2587
2588bool FallbackICCodeCompiler::emit_OptimizeGetIterator() {
2589 EmitRestoreTailCallReg(masm);
2590
2591 masm.pushValue(R0);
2592 masm.push(ICStubReg);
2593 pushStubPayload(masm, R0.scratchReg());
2594
2595 using Fn = bool (*)(JSContext*, BaselineFrame*, ICFallbackStub*, HandleValue,
2596 MutableHandleValue);
2597 return tailCallVM<Fn, DoOptimizeGetIteratorFallback>(masm);
2598}
2599
2600bool JitRuntime::generateBaselineICFallbackCode(JSContext* cx) {
2601 TempAllocator temp(&cx->tempLifoAlloc());
2602 StackMacroAssembler masm(cx, temp);
2603 PerfSpewerRangeRecorder rangeRecorder(masm);
2604 AutoCreatedBy acb(masm, "JitRuntime::generateBaselineICFallbackCode");
2605
2606 BaselineICFallbackCode& fallbackCode = baselineICFallbackCode_.ref();
2607 FallbackICCodeCompiler compiler(cx, fallbackCode, masm);
2608
2609 JitSpew(JitSpew_Codegen, "# Emitting Baseline IC fallback code");
2610
2611#define EMIT_CODE(kind) \
2612 { \
2613 AutoCreatedBy acb(masm, "kind=" #kind); \
2614 uint32_t offset = startTrampolineCode(masm); \
2615 InitMacroAssemblerForICStub(masm); \
2616 if (!compiler.emit_##kind()) { \
2617 return false; \
2618 } \
2619 fallbackCode.initOffset(BaselineICFallbackKind::kind, offset); \
2620 rangeRecorder.recordOffset("BaselineICFallback: " #kind); \
2621 }
2622 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)
2623#undef EMIT_CODE
2624
2625 Linker linker(masm);
2626 JitCode* code = linker.newCode(cx, CodeKind::Other);
2627 if (!code) {
2628 return false;
2629 }
2630
2631 rangeRecorder.collectRangesForJitCode(code);
2632
2633#ifdef MOZ_VTUNE1
2634 vtune::MarkStub(code, "BaselineICFallback");
2635#endif
2636
2637 fallbackCode.initCode(code);
2638 return true;
2639}
2640
2641} // namespace jit
2642} // namespace js