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