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