Bug Summary

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