Bug Summary

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