Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 : #ifndef jit_SharedIC_h
8 : #define jit_SharedIC_h
9 :
10 : #include "jscntxt.h"
11 : #include "jscompartment.h"
12 : #include "jsgc.h"
13 :
14 : #include "jit/BaselineICList.h"
15 : #include "jit/BaselineJIT.h"
16 : #include "jit/ICState.h"
17 : #include "jit/MacroAssembler.h"
18 : #include "jit/SharedICList.h"
19 : #include "jit/SharedICRegisters.h"
20 : #include "vm/ReceiverGuard.h"
21 : #include "vm/TypedArrayObject.h"
22 :
23 : namespace js {
24 : namespace jit {
25 :
26 : //
27 : // Baseline Inline Caches are polymorphic caches that aggressively
28 : // share their stub code.
29 : //
30 : // Every polymorphic site contains a linked list of stubs which are
31 : // specific to that site. These stubs are composed of a |StubData|
32 : // structure that stores parametrization information (e.g.
33 : // the shape pointer for a shape-check-and-property-get stub), any
34 : // dynamic information (e.g. warm-up counters), a pointer to the stub code,
35 : // and a pointer to the next stub state in the linked list.
36 : //
37 : // Every BaselineScript keeps an table of |CacheDescriptor| data
38 : // structures, which store the following:
39 : // A pointer to the first StubData in the cache.
40 : // The bytecode PC of the relevant IC.
41 : // The machine-code PC where the call to the stubcode returns.
42 : //
43 : // A diagram:
44 : //
45 : // Control flow Pointers
46 : // =======# ----. .---->
47 : // # | |
48 : // #======> \-----/
49 : //
50 : //
51 : // .---------------------------------------.
52 : // | .-------------------------. |
53 : // | | .----. | |
54 : // Baseline | | | | | |
55 : // JIT Code 0 ^ 1 ^ 2 ^ | | |
56 : // +--------------+ .-->+-----+ +-----+ +-----+ | | |
57 : // | | #=|==>| |==>| |==>| FB | | | |
58 : // | | # | +-----+ +-----+ +-----+ | | |
59 : // | | # | # # # | | |
60 : // |==============|==# | # # # | | |
61 : // |=== IC =======| | # # # | | |
62 : // .->|==============|<===|======#=========#=========# | | |
63 : // | | | | | | |
64 : // | | | | | | |
65 : // | | | | | | |
66 : // | | | | v | |
67 : // | | | | +---------+ | |
68 : // | | | | | Fallback| | |
69 : // | | | | | Stub | | |
70 : // | | | | | Code | | |
71 : // | | | | +---------+ | |
72 : // | +--------------+ | | |
73 : // | |_______ | +---------+ | |
74 : // | | | | Stub |<---/ |
75 : // | IC | \--. | Code | |
76 : // | Descriptor | | +---------+ |
77 : // | Table v | |
78 : // | +-----------------+ | +---------+ |
79 : // \--| Ins | PC | Stub |----/ | Stub |<-------/
80 : // +-----------------+ | Code |
81 : // | ... | +---------+
82 : // +-----------------+
83 : // Shared
84 : // Stub Code
85 : //
86 : //
87 : // Type ICs
88 : // ========
89 : //
90 : // Type ICs are otherwise regular ICs that are actually nested within
91 : // other IC chains. They serve to optimize locations in the code where the
92 : // baseline compiler would have otherwise had to perform a type Monitor operation
93 : // (e.g. the result of GetProp, GetElem, etc.), or locations where the baseline
94 : // compiler would have had to modify a heap typeset using the type of an input
95 : // value (e.g. SetProp, SetElem, etc.)
96 : //
97 : // There are two kinds of Type ICs: Monitor and Update.
98 : //
99 : // Note that type stub bodies are no-ops. The stubs only exist for their
100 : // guards, and their existence simply signifies that the typeset (implicit)
101 : // that is being checked already contains that type.
102 : //
103 : // TypeMonitor ICs
104 : // ---------------
105 : // Monitor ICs are shared between stubs in the general IC, and monitor the resulting
106 : // types of getter operations (call returns, getprop outputs, etc.)
107 : //
108 : // +-----------+ +-----------+ +-----------+ +-----------+
109 : // ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub |
110 : // +-----------+ +-----------+ +-----------+ +-----------+
111 : // | | | |
112 : // |------------------/-----------------/ |
113 : // v |
114 : // +-----------+ +-----------+ +-----------+ |
115 : // | Type 1 |---->| Type 2 |---->| Type FB | |
116 : // +-----------+ +-----------+ +-----------+ |
117 : // | | | |
118 : // <----------/-----------------/------------------/------------------/
119 : // r e t u r n p a t h
120 : //
121 : // After an optimized IC stub successfully executes, it passes control to the type stub
122 : // chain to check the resulting type. If no type stub succeeds, and the monitor fallback
123 : // stub is reached, the monitor fallback stub performs a manual monitor, and also adds the
124 : // appropriate type stub to the chain.
125 : //
126 : // The IC's main fallback, in addition to generating new mainline stubs, also generates
127 : // type stubs as reflected by its returned value.
128 : //
129 : // NOTE: The type IC chain returns directly to the mainline code, not back to the
130 : // stub it was entered from. Thus, entering a type IC is a matter of a |jump|, not
131 : // a |call|. This allows us to safely call a VM Monitor function from within the monitor IC's
132 : // fallback chain, since the return address (needed for stack inspection) is preserved.
133 : //
134 : //
135 : // TypeUpdate ICs
136 : // --------------
137 : // Update ICs update heap typesets and monitor the input types of setter operations
138 : // (setelem, setprop inputs, etc.). Unlike monitor ICs, they are not shared
139 : // between stubs on an IC, but instead are kept track of on a per-stub basis.
140 : //
141 : // This is because the main stubs for the operation will each identify a potentially
142 : // different ObjectGroup to update. New input types must be tracked on a group-to-
143 : // group basis.
144 : //
145 : // Type-update ICs cannot be called in tail position (they must return to the
146 : // the stub that called them so that the stub may continue to perform its original
147 : // purpose). This means that any VMCall to perform a manual type update from C++ must be
148 : // done from within the main IC stub. This necessitates that the stub enter a
149 : // "BaselineStub" frame before making the call.
150 : //
151 : // If the type-update IC chain could itself make the VMCall, then the BaselineStub frame
152 : // must be entered before calling the type-update chain, and exited afterward. This
153 : // is very expensive for a common case where we expect the type-update fallback to not
154 : // be called. To avoid the cost of entering and exiting a BaselineStub frame when
155 : // using the type-update IC chain, we design the chain to not perform any VM-calls
156 : // in its fallback.
157 : //
158 : // Instead, the type-update IC chain is responsible for returning 1 or 0, depending
159 : // on if a type is represented in the chain or not. The fallback stub simply returns
160 : // 0, and all other optimized stubs return 1.
161 : // If the chain returns 1, then the IC stub goes ahead and performs its operation.
162 : // If the chain returns 0, then the IC stub performs a call to the fallback function
163 : // inline (doing the requisite BaselineStub frame enter/exit).
164 : // This allows us to avoid the expensive subfram enter/exit in the common case.
165 : //
166 : // r e t u r n p a t h
167 : // <--------------.-----------------.-----------------.-----------------.
168 : // | | | |
169 : // +-----------+ +-----------+ +-----------+ +-----------+
170 : // ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub |
171 : // +-----------+ +-----------+ +-----------+ +-----------+
172 : // | ^ | ^ | ^
173 : // | | | | | |
174 : // | | | | | |----------------.
175 : // | | | | v |1 |0
176 : // | | | | +-----------+ +-----------+
177 : // | | | | | Type 3.1 |--->| FB 3 |
178 : // | | | | +-----------+ +-----------+
179 : // | | | |
180 : // | | | \-------------.-----------------.
181 : // | | | | | |
182 : // | | v |1 |1 |0
183 : // | | +-----------+ +-----------+ +-----------+
184 : // | | | Type 2.1 |---->| Type 2.2 |---->| FB 2 |
185 : // | | +-----------+ +-----------+ +-----------+
186 : // | |
187 : // | \-------------.-----------------.
188 : // | | | |
189 : // v |1 |1 |0
190 : // +-----------+ +-----------+ +-----------+
191 : // | Type 1.1 |---->| Type 1.2 |---->| FB 1 |
192 : // +-----------+ +-----------+ +-----------+
193 : //
194 :
195 : class ICStub;
196 : class ICFallbackStub;
197 :
198 : #define FORWARD_DECLARE_STUBS(kindName) class IC##kindName;
199 : IC_BASELINE_STUB_KIND_LIST(FORWARD_DECLARE_STUBS)
200 : IC_SHARED_STUB_KIND_LIST(FORWARD_DECLARE_STUBS)
201 : #undef FORWARD_DECLARE_STUBS
202 :
203 : #ifdef JS_JITSPEW
204 : void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...)
205 : MOZ_FORMAT_PRINTF(3, 4);
206 : void TypeFallbackICSpew(JSContext* cx, ICTypeMonitor_Fallback* stub, const char* fmt, ...)
207 : MOZ_FORMAT_PRINTF(3, 4);
208 : #else
209 : #define FallbackICSpew(...)
210 : #define TypeFallbackICSpew(...)
211 : #endif
212 :
213 : //
214 : // An entry in the JIT IC descriptor table.
215 : //
216 : class ICEntry
217 : {
218 : private:
219 : // A pointer to the shared IC stub for this instruction.
220 : ICStub* firstStub_;
221 :
222 : // Offset from the start of the JIT code where the IC
223 : // load and call instructions are.
224 : uint32_t returnOffset_;
225 :
226 : // The PC of this IC's bytecode op within the JSScript.
227 : uint32_t pcOffset_ : 28;
228 :
229 : public:
230 : enum Kind {
231 : // A for-op IC entry.
232 : Kind_Op = 0,
233 :
234 : // A non-op IC entry.
235 : Kind_NonOp,
236 :
237 : // A fake IC entry for returning from a callVM for an op.
238 : Kind_CallVM,
239 :
240 : // A fake IC entry for returning from a callVM not for an op (e.g., in
241 : // the prologue).
242 : Kind_NonOpCallVM,
243 :
244 : // A fake IC entry for returning from a callVM to after the
245 : // warmup counter.
246 : Kind_WarmupCounter,
247 :
248 : // A fake IC entry for returning from a callVM to the interrupt
249 : // handler via the over-recursion check on function entry.
250 : Kind_StackCheck,
251 :
252 : // As above, but for the early check. See emitStackCheck.
253 : Kind_EarlyStackCheck,
254 :
255 : // A fake IC entry for returning from DebugTrapHandler.
256 : Kind_DebugTrap,
257 :
258 : // A fake IC entry for returning from a callVM to
259 : // Debug{Prologue,Epilogue}.
260 : Kind_DebugPrologue,
261 : Kind_DebugEpilogue,
262 :
263 : Kind_Invalid
264 : };
265 :
266 : private:
267 : // What this IC is for.
268 : Kind kind_ : 4;
269 :
270 : // Set the kind and asserts that it's sane.
271 24731 : void setKind(Kind kind) {
272 24731 : MOZ_ASSERT(kind < Kind_Invalid);
273 24731 : kind_ = kind;
274 24731 : MOZ_ASSERT(this->kind() == kind);
275 24731 : }
276 :
277 : public:
278 22785 : ICEntry(uint32_t pcOffset, Kind kind)
279 22785 : : firstStub_(nullptr), returnOffset_(), pcOffset_(pcOffset)
280 : {
281 : // The offset must fit in at least 28 bits, since we shave off 4 for
282 : // the Kind enum.
283 22785 : MOZ_ASSERT(pcOffset_ == pcOffset);
284 : JS_STATIC_ASSERT(BaselineScript::MAX_JSSCRIPT_LENGTH <= (1u << 28) - 1);
285 22785 : MOZ_ASSERT(pcOffset <= BaselineScript::MAX_JSSCRIPT_LENGTH);
286 22785 : setKind(kind);
287 22785 : }
288 :
289 34700 : CodeOffset returnOffset() const {
290 34700 : return CodeOffset(returnOffset_);
291 : }
292 :
293 22785 : void setReturnOffset(CodeOffset offset) {
294 22785 : MOZ_ASSERT(offset.offset() <= (size_t) UINT32_MAX);
295 22785 : returnOffset_ = (uint32_t) offset.offset();
296 22785 : }
297 :
298 727421 : uint32_t pcOffset() const {
299 727421 : return pcOffset_;
300 : }
301 :
302 28618 : jsbytecode* pc(JSScript* script) const {
303 28618 : return script->offsetToPC(pcOffset_);
304 : }
305 :
306 152095 : Kind kind() const {
307 : // MSVC compiles enums as signed.
308 152095 : return Kind(kind_ & 0xf);
309 : }
310 127364 : bool isForOp() const {
311 127364 : return kind() == Kind_Op;
312 : }
313 :
314 1946 : void setFakeKind(Kind kind) {
315 1946 : MOZ_ASSERT(kind != Kind_Op && kind != Kind_NonOp);
316 1946 : setKind(kind);
317 1946 : }
318 :
319 240336 : bool hasStub() const {
320 240336 : return firstStub_ != nullptr;
321 : }
322 217540 : ICStub* firstStub() const {
323 217540 : MOZ_ASSERT(hasStub());
324 217540 : return firstStub_;
325 : }
326 :
327 : ICFallbackStub* fallbackStub() const;
328 :
329 20297 : void setFirstStub(ICStub* stub) {
330 20297 : firstStub_ = stub;
331 20297 : }
332 :
333 19345 : static inline size_t offsetOfFirstStub() {
334 19345 : return offsetof(ICEntry, firstStub_);
335 : }
336 :
337 19559 : inline ICStub** addressOfFirstStub() {
338 19559 : return &firstStub_;
339 : }
340 :
341 : protected:
342 : void traceEntry(JSTracer* trc);
343 : };
344 :
345 : class BaselineICEntry : public ICEntry
346 : {
347 : public:
348 22785 : BaselineICEntry(uint32_t pcOffset, Kind kind)
349 22785 : : ICEntry(pcOffset, kind)
350 22785 : { }
351 :
352 : void trace(JSTracer* trc);
353 : };
354 :
355 : class IonICEntry : public ICEntry
356 : {
357 : JSScript* script_;
358 :
359 : public:
360 0 : IonICEntry(uint32_t pcOffset, Kind kind, JSScript* script)
361 0 : : ICEntry(pcOffset, kind),
362 0 : script_(script)
363 0 : { }
364 :
365 0 : JSScript* script() {
366 0 : return script_;
367 : }
368 :
369 : void trace(JSTracer* trc);
370 : };
371 :
372 : class ICMonitoredStub;
373 : class ICMonitoredFallbackStub;
374 : class ICUpdatedStub;
375 :
376 : // Constant iterator that traverses arbitrary chains of ICStubs.
377 : // No requirements are made of the ICStub used to construct this
378 : // iterator, aside from that the stub be part of a nullptr-terminated
379 : // chain.
380 : // The iterator is considered to be at its end once it has been
381 : // incremented _past_ the last stub. Thus, if 'atEnd()' returns
382 : // true, the '*' and '->' operations are not valid.
383 : class ICStubConstIterator
384 : {
385 : friend class ICStub;
386 : friend class ICFallbackStub;
387 :
388 : private:
389 : ICStub* currentStub_;
390 :
391 : public:
392 31476 : explicit ICStubConstIterator(ICStub* currentStub) : currentStub_(currentStub) {}
393 :
394 : static ICStubConstIterator StartingAt(ICStub* stub) {
395 : return ICStubConstIterator(stub);
396 : }
397 : static ICStubConstIterator End(ICStub* stub) {
398 : return ICStubConstIterator(nullptr);
399 : }
400 :
401 : bool operator ==(const ICStubConstIterator& other) const {
402 : return currentStub_ == other.currentStub_;
403 : }
404 : bool operator !=(const ICStubConstIterator& other) const {
405 : return !(*this == other);
406 : }
407 :
408 : ICStubConstIterator& operator++();
409 :
410 36705 : ICStubConstIterator operator++(int) {
411 36705 : ICStubConstIterator oldThis(*this);
412 36705 : ++(*this);
413 36705 : return oldThis;
414 : }
415 :
416 17 : ICStub* operator*() const {
417 17 : MOZ_ASSERT(currentStub_);
418 17 : return currentStub_;
419 : }
420 :
421 68735 : ICStub* operator ->() const {
422 68735 : MOZ_ASSERT(currentStub_);
423 68735 : return currentStub_;
424 : }
425 :
426 68181 : bool atEnd() const {
427 68181 : return currentStub_ == nullptr;
428 : }
429 : };
430 :
431 : // Iterator that traverses "regular" IC chains that start at an ICEntry
432 : // and are terminated with an ICFallbackStub.
433 : //
434 : // The iterator is considered to be at its end once it is _at_ the
435 : // fallback stub. Thus, unlike the ICStubConstIterator, operators
436 : // '*' and '->' are valid even if 'atEnd()' returns true - they
437 : // will act on the fallback stub.
438 : //
439 : // This iterator also allows unlinking of stubs being traversed.
440 : // Note that 'unlink' does not implicitly advance the iterator -
441 : // it must be advanced explicitly using '++'.
442 : class ICStubIterator
443 : {
444 : friend class ICFallbackStub;
445 :
446 : private:
447 : ICEntry* icEntry_;
448 : ICFallbackStub* fallbackStub_;
449 : ICStub* previousStub_;
450 : ICStub* currentStub_;
451 : bool unlinked_;
452 :
453 : explicit ICStubIterator(ICFallbackStub* fallbackStub, bool end=false);
454 : public:
455 :
456 : bool operator ==(const ICStubIterator& other) const {
457 : // == should only ever be called on stubs from the same chain.
458 : MOZ_ASSERT(icEntry_ == other.icEntry_);
459 : MOZ_ASSERT(fallbackStub_ == other.fallbackStub_);
460 : return currentStub_ == other.currentStub_;
461 : }
462 : bool operator !=(const ICStubIterator& other) const {
463 : return !(*this == other);
464 : }
465 :
466 : ICStubIterator& operator++();
467 :
468 5756 : ICStubIterator operator++(int) {
469 5756 : ICStubIterator oldThis(*this);
470 5756 : ++(*this);
471 5756 : return oldThis;
472 : }
473 :
474 : ICStub* operator*() const {
475 : return currentStub_;
476 : }
477 :
478 16959 : ICStub* operator ->() const {
479 16959 : return currentStub_;
480 : }
481 :
482 12140 : bool atEnd() const {
483 12140 : return currentStub_ == (ICStub*) fallbackStub_;
484 : }
485 :
486 : void unlink(JSContext* cx);
487 : };
488 :
489 : //
490 : // Base class for all IC stubs.
491 : //
492 : class ICStub
493 : {
494 : friend class ICFallbackStub;
495 :
496 : public:
497 : enum Kind {
498 : INVALID = 0,
499 : #define DEF_ENUM_KIND(kindName) kindName,
500 : IC_BASELINE_STUB_KIND_LIST(DEF_ENUM_KIND)
501 : IC_SHARED_STUB_KIND_LIST(DEF_ENUM_KIND)
502 : #undef DEF_ENUM_KIND
503 : LIMIT
504 : };
505 :
506 15235 : static bool IsValidKind(Kind k) {
507 15235 : return (k > INVALID) && (k < LIMIT);
508 : }
509 15235 : static bool IsCacheIRKind(Kind k) {
510 15235 : return k == CacheIR_Regular || k == CacheIR_Monitored || k == CacheIR_Updated;
511 : }
512 :
513 618 : static const char* KindString(Kind k) {
514 618 : switch(k) {
515 : #define DEF_KIND_STR(kindName) case kindName: return #kindName;
516 0 : IC_BASELINE_STUB_KIND_LIST(DEF_KIND_STR)
517 0 : IC_SHARED_STUB_KIND_LIST(DEF_KIND_STR)
518 : #undef DEF_KIND_STR
519 : default:
520 0 : MOZ_CRASH("Invalid kind.");
521 : }
522 : }
523 :
524 : enum Trait {
525 : Regular = 0x0,
526 : Fallback = 0x1,
527 : Monitored = 0x2,
528 : MonitoredFallback = 0x3,
529 : Updated = 0x4
530 : };
531 :
532 : void traceCode(JSTracer* trc, const char* name);
533 : void updateCode(JitCode* stubCode);
534 : void trace(JSTracer* trc);
535 :
536 : template <typename T, typename... Args>
537 44504 : static T* New(JSContext* cx, ICStubSpace* space, JitCode* code, Args&&... args) {
538 44504 : if (!code)
539 0 : return nullptr;
540 44504 : T* result = space->allocate<T>(code, mozilla::Forward<Args>(args)...);
541 44504 : if (!result)
542 0 : ReportOutOfMemory(cx);
543 44504 : return result;
544 : }
545 :
546 : protected:
547 : // The raw jitcode to call for this stub.
548 : uint8_t* stubCode_;
549 :
550 : // Pointer to next IC stub. This is null for the last IC stub, which should
551 : // either be a fallback or inert IC stub.
552 : ICStub* next_;
553 :
554 : // A 16-bit field usable by subtypes of ICStub for subtype-specific small-info
555 : uint16_t extra_;
556 :
557 : // The kind of the stub.
558 : // High bit is 'isFallback' flag.
559 : // Second high bit is 'isMonitored' flag.
560 : Trait trait_ : 3;
561 : Kind kind_ : 13;
562 :
563 25890 : inline ICStub(Kind kind, JitCode* stubCode)
564 25890 : : stubCode_(stubCode->raw()),
565 : next_(nullptr),
566 : extra_(0),
567 : trait_(Regular),
568 25890 : kind_(kind)
569 : {
570 25890 : MOZ_ASSERT(stubCode != nullptr);
571 25890 : }
572 :
573 24600 : inline ICStub(Kind kind, Trait trait, JitCode* stubCode)
574 24600 : : stubCode_(stubCode->raw()),
575 : next_(nullptr),
576 : extra_(0),
577 : trait_(trait),
578 24600 : kind_(kind)
579 : {
580 24600 : MOZ_ASSERT(stubCode != nullptr);
581 24600 : }
582 :
583 512250 : inline Trait trait() const {
584 : // Workaround for MSVC reading trait_ as signed value.
585 512250 : return (Trait)(trait_ & 0x7);
586 : }
587 :
588 : public:
589 :
590 139016 : inline Kind kind() const {
591 139016 : return static_cast<Kind>(kind_);
592 : }
593 :
594 274165 : inline bool isFallback() const {
595 274165 : return trait() == Fallback || trait() == MonitoredFallback;
596 : }
597 :
598 20173 : inline bool isMonitored() const {
599 20173 : return trait() == Monitored;
600 : }
601 :
602 149 : inline bool isUpdated() const {
603 149 : return trait() == Updated;
604 : }
605 :
606 4772 : inline bool isMonitoredFallback() const {
607 4772 : return trait() == MonitoredFallback;
608 : }
609 :
610 : inline const ICFallbackStub* toFallbackStub() const {
611 : MOZ_ASSERT(isFallback());
612 : return reinterpret_cast<const ICFallbackStub*>(this);
613 : }
614 :
615 136011 : inline ICFallbackStub* toFallbackStub() {
616 136011 : MOZ_ASSERT(isFallback());
617 136011 : return reinterpret_cast<ICFallbackStub*>(this);
618 : }
619 :
620 : inline const ICMonitoredStub* toMonitoredStub() const {
621 : MOZ_ASSERT(isMonitored());
622 : return reinterpret_cast<const ICMonitoredStub*>(this);
623 : }
624 :
625 9715 : inline ICMonitoredStub* toMonitoredStub() {
626 9715 : MOZ_ASSERT(isMonitored());
627 9715 : return reinterpret_cast<ICMonitoredStub*>(this);
628 : }
629 :
630 : inline const ICMonitoredFallbackStub* toMonitoredFallbackStub() const {
631 : MOZ_ASSERT(isMonitoredFallback());
632 : return reinterpret_cast<const ICMonitoredFallbackStub*>(this);
633 : }
634 :
635 4638 : inline ICMonitoredFallbackStub* toMonitoredFallbackStub() {
636 4638 : MOZ_ASSERT(isMonitoredFallback());
637 4638 : return reinterpret_cast<ICMonitoredFallbackStub*>(this);
638 : }
639 :
640 : inline const ICUpdatedStub* toUpdatedStub() const {
641 : MOZ_ASSERT(isUpdated());
642 : return reinterpret_cast<const ICUpdatedStub*>(this);
643 : }
644 :
645 15 : inline ICUpdatedStub* toUpdatedStub() {
646 15 : MOZ_ASSERT(isUpdated());
647 15 : return reinterpret_cast<ICUpdatedStub*>(this);
648 : }
649 :
650 : #define KIND_METHODS(kindName) \
651 : inline bool is##kindName() const { return kind() == kindName; } \
652 : inline const IC##kindName* to##kindName() const { \
653 : MOZ_ASSERT(is##kindName()); \
654 : return reinterpret_cast<const IC##kindName*>(this); \
655 : } \
656 : inline IC##kindName* to##kindName() { \
657 : MOZ_ASSERT(is##kindName()); \
658 : return reinterpret_cast<IC##kindName*>(this); \
659 : }
660 106078 : IC_BASELINE_STUB_KIND_LIST(KIND_METHODS)
661 52269 : IC_SHARED_STUB_KIND_LIST(KIND_METHODS)
662 : #undef KIND_METHODS
663 :
664 67205 : inline ICStub* next() const {
665 67205 : return next_;
666 : }
667 :
668 : inline bool hasNext() const {
669 : return next_ != nullptr;
670 : }
671 :
672 18839 : inline void setNext(ICStub* stub) {
673 : // Note: next_ only needs to be changed under the compilation lock for
674 : // non-type-monitor/update ICs.
675 18839 : next_ = stub;
676 18839 : }
677 :
678 18365 : inline ICStub** addressOfNext() {
679 18365 : return &next_;
680 : }
681 :
682 334 : inline JitCode* jitCode() {
683 334 : return JitCode::FromExecutable(stubCode_);
684 : }
685 :
686 : inline uint8_t* rawStubCode() const {
687 : return stubCode_;
688 : }
689 :
690 : // This method is not valid on TypeUpdate stub chains!
691 118803 : inline ICFallbackStub* getChainFallback() {
692 118803 : ICStub* lastStub = this;
693 236079 : while (lastStub->next_)
694 58638 : lastStub = lastStub->next_;
695 118803 : MOZ_ASSERT(lastStub->isFallback());
696 118803 : return lastStub->toFallbackStub();
697 : }
698 :
699 : inline ICStubConstIterator beginHere() {
700 : return ICStubConstIterator::StartingAt(this);
701 : }
702 :
703 1900 : static inline size_t offsetOfNext() {
704 1900 : return offsetof(ICStub, next_);
705 : }
706 :
707 21710 : static inline size_t offsetOfStubCode() {
708 21710 : return offsetof(ICStub, stubCode_);
709 : }
710 :
711 : static inline size_t offsetOfExtra() {
712 : return offsetof(ICStub, extra_);
713 : }
714 :
715 : static bool NonCacheIRStubMakesGCCalls(Kind kind);
716 : bool makesGCCalls() const;
717 :
718 : // Optimized stubs get purged on GC. But some stubs can be active on the
719 : // stack during GC - specifically the ones that can make calls. To ensure
720 : // that these do not get purged, all stubs that can make calls are allocated
721 : // in the fallback stub space.
722 0 : bool allocatedInFallbackSpace() const {
723 0 : MOZ_ASSERT(next());
724 0 : return makesGCCalls();
725 : }
726 : };
727 :
728 : class ICFallbackStub : public ICStub
729 : {
730 : friend class ICStubConstIterator;
731 : protected:
732 : // Fallback stubs need these fields to easily add new stubs to
733 : // the linked list of stubs for an IC.
734 :
735 : // The IC entry for this linked list of stubs.
736 : ICEntry* icEntry_;
737 :
738 : // The number of stubs kept in the IC entry.
739 : ICState state_;
740 :
741 : // A pointer to the location stub pointer that needs to be
742 : // changed to add a new "last" stub immediately before the fallback
743 : // stub. This'll start out pointing to the icEntry's "firstStub_"
744 : // field, and as new stubs are added, it'll point to the current
745 : // last stub's "next_" field.
746 : ICStub** lastStubPtrAddr_;
747 :
748 5922 : ICFallbackStub(Kind kind, JitCode* stubCode)
749 5922 : : ICStub(kind, ICStub::Fallback, stubCode),
750 : icEntry_(nullptr),
751 : state_(),
752 5922 : lastStubPtrAddr_(nullptr) {}
753 :
754 11286 : ICFallbackStub(Kind kind, Trait trait, JitCode* stubCode)
755 11286 : : ICStub(kind, trait, stubCode),
756 : icEntry_(nullptr),
757 : state_(),
758 11286 : lastStubPtrAddr_(nullptr)
759 : {
760 11286 : MOZ_ASSERT(trait == ICStub::Fallback ||
761 : trait == ICStub::MonitoredFallback);
762 11286 : }
763 :
764 : public:
765 51101 : inline ICEntry* icEntry() const {
766 51101 : return icEntry_;
767 : }
768 :
769 17083 : inline size_t numOptimizedStubs() const {
770 17083 : return state_.numOptimizedStubs();
771 : }
772 :
773 0 : void setInvalid() {
774 0 : state_.setInvalid();
775 0 : }
776 :
777 10091 : bool invalid() const {
778 10091 : return state_.invalid();
779 : }
780 :
781 37876 : ICState& state() {
782 37876 : return state_;
783 : }
784 :
785 : // The icEntry and lastStubPtrAddr_ fields can't be initialized when the stub is
786 : // created since the stub is created at compile time, and we won't know the IC entry
787 : // address until after compile when the JitScript is created. This method
788 : // allows these fields to be fixed up at that point.
789 17208 : void fixupICEntry(ICEntry* icEntry) {
790 17208 : MOZ_ASSERT(icEntry_ == nullptr);
791 17208 : MOZ_ASSERT(lastStubPtrAddr_ == nullptr);
792 17208 : icEntry_ = icEntry;
793 17208 : lastStubPtrAddr_ = icEntry_->addressOfFirstStub();
794 17208 : }
795 :
796 : // Add a new stub to the IC chain terminated by this fallback stub.
797 10013 : void addNewStub(ICStub* stub) {
798 10013 : MOZ_ASSERT(!invalid());
799 10013 : MOZ_ASSERT(*lastStubPtrAddr_ == this);
800 10013 : MOZ_ASSERT(stub->next() == nullptr);
801 10013 : stub->setNext(this);
802 10013 : *lastStubPtrAddr_ = stub;
803 10013 : lastStubPtrAddr_ = stub->addressOfNext();
804 10013 : state_.trackAttached();
805 10013 : }
806 :
807 9068 : ICStubConstIterator beginChainConst() const {
808 9068 : return ICStubConstIterator(icEntry_->firstStub());
809 : }
810 :
811 6384 : ICStubIterator beginChain() {
812 6384 : return ICStubIterator(this);
813 : }
814 :
815 760 : bool hasStub(ICStub::Kind kind) const {
816 1807 : for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) {
817 1047 : if (iter->kind() == kind)
818 0 : return true;
819 : }
820 760 : return false;
821 : }
822 :
823 1852 : unsigned numStubsWithKind(ICStub::Kind kind) const {
824 1852 : unsigned count = 0;
825 4289 : for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) {
826 2437 : if (iter->kind() == kind)
827 585 : count++;
828 : }
829 1852 : return count;
830 : }
831 :
832 : void discardStubs(JSContext* cx);
833 :
834 : void unlinkStub(Zone* zone, ICStub* prev, ICStub* stub);
835 : void unlinkStubsWithKind(JSContext* cx, ICStub::Kind kind);
836 : };
837 :
838 : // Base class for Trait::Regular CacheIR stubs
839 : class ICCacheIR_Regular : public ICStub
840 : {
841 : const CacheIRStubInfo* stubInfo_;
842 :
843 : public:
844 394 : ICCacheIR_Regular(JitCode* stubCode, const CacheIRStubInfo* stubInfo)
845 394 : : ICStub(ICStub::CacheIR_Regular, stubCode),
846 394 : stubInfo_(stubInfo)
847 394 : {}
848 :
849 : void notePreliminaryObject() {
850 : extra_ = 1;
851 : }
852 0 : bool hasPreliminaryObject() const {
853 0 : return extra_;
854 : }
855 :
856 739 : const CacheIRStubInfo* stubInfo() const {
857 739 : return stubInfo_;
858 : }
859 :
860 : uint8_t* stubDataStart();
861 : };
862 :
863 : // Monitored stubs are IC stubs that feed a single resulting value out to a
864 : // type monitor operation.
865 : class ICMonitoredStub : public ICStub
866 : {
867 : protected:
868 : // Pointer to the start of the type monitoring stub chain.
869 : ICStub* firstMonitorStub_;
870 :
871 : ICMonitoredStub(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub);
872 :
873 : public:
874 4756 : inline void updateFirstMonitorStub(ICStub* monitorStub) {
875 : // This should only be called once: when the first optimized monitor stub
876 : // is added to the type monitor IC chain.
877 4756 : MOZ_ASSERT(firstMonitorStub_ && firstMonitorStub_->isTypeMonitor_Fallback());
878 4756 : firstMonitorStub_ = monitorStub;
879 4756 : }
880 203 : inline void resetFirstMonitorStub(ICStub* monitorFallback) {
881 203 : MOZ_ASSERT(monitorFallback->isTypeMonitor_Fallback());
882 203 : firstMonitorStub_ = monitorFallback;
883 203 : }
884 4756 : inline ICStub* firstMonitorStub() const {
885 4756 : return firstMonitorStub_;
886 : }
887 :
888 239 : static inline size_t offsetOfFirstMonitorStub() {
889 239 : return offsetof(ICMonitoredStub, firstMonitorStub_);
890 : }
891 : };
892 :
893 : class ICCacheIR_Monitored : public ICMonitoredStub
894 : {
895 : const CacheIRStubInfo* stubInfo_;
896 :
897 : public:
898 4523 : ICCacheIR_Monitored(JitCode* stubCode, ICStub* firstMonitorStub,
899 : const CacheIRStubInfo* stubInfo)
900 4523 : : ICMonitoredStub(ICStub::CacheIR_Monitored, stubCode, firstMonitorStub),
901 4523 : stubInfo_(stubInfo)
902 4523 : {}
903 :
904 : static ICCacheIR_Monitored* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
905 : ICCacheIR_Monitored& other);
906 :
907 427 : void notePreliminaryObject() {
908 427 : extra_ = 1;
909 427 : }
910 3018 : bool hasPreliminaryObject() const {
911 3018 : return extra_;
912 : }
913 :
914 4150 : const CacheIRStubInfo* stubInfo() const {
915 4150 : return stubInfo_;
916 : }
917 :
918 : uint8_t* stubDataStart();
919 : };
920 :
921 : // Updated stubs are IC stubs that use a TypeUpdate IC to track
922 : // the status of heap typesets that need to be updated.
923 : class ICUpdatedStub : public ICStub
924 : {
925 : protected:
926 : // Pointer to the start of the type updating stub chain.
927 : ICStub* firstUpdateStub_;
928 :
929 : static const uint32_t MAX_OPTIMIZED_STUBS = 8;
930 : uint32_t numOptimizedStubs_;
931 :
932 1069 : ICUpdatedStub(Kind kind, JitCode* stubCode)
933 1069 : : ICStub(kind, ICStub::Updated, stubCode),
934 : firstUpdateStub_(nullptr),
935 1069 : numOptimizedStubs_(0)
936 1069 : {}
937 :
938 : public:
939 : MOZ_MUST_USE bool initUpdatingChain(JSContext* cx, ICStubSpace* space);
940 :
941 : MOZ_MUST_USE bool addUpdateStubForValue(JSContext* cx, HandleScript script, HandleObject obj,
942 : HandleObjectGroup group, HandleId id, HandleValue val);
943 :
944 596 : void addOptimizedUpdateStub(ICStub* stub) {
945 596 : if (firstUpdateStub_->isTypeUpdate_Fallback()) {
946 562 : stub->setNext(firstUpdateStub_);
947 562 : firstUpdateStub_ = stub;
948 : } else {
949 34 : ICStub* iter = firstUpdateStub_;
950 34 : MOZ_ASSERT(iter->next() != nullptr);
951 23 : while (!iter->next()->isTypeUpdate_Fallback())
952 23 : iter = iter->next();
953 34 : MOZ_ASSERT(iter->next()->next() == nullptr);
954 34 : stub->setNext(iter->next());
955 34 : iter->setNext(stub);
956 : }
957 :
958 596 : numOptimizedStubs_++;
959 596 : }
960 :
961 15 : inline ICStub* firstUpdateStub() const {
962 15 : return firstUpdateStub_;
963 : }
964 :
965 : void resetUpdateStubChain(Zone* zone);
966 :
967 445 : bool hasTypeUpdateStub(ICStub::Kind kind) {
968 445 : ICStub* stub = firstUpdateStub_;
969 4 : do {
970 449 : if (stub->kind() == kind)
971 0 : return true;
972 :
973 449 : stub = stub->next();
974 449 : } while (stub);
975 :
976 445 : return false;
977 : }
978 :
979 : inline uint32_t numOptimizedStubs() const {
980 : return numOptimizedStubs_;
981 : }
982 :
983 52 : static inline size_t offsetOfFirstUpdateStub() {
984 52 : return offsetof(ICUpdatedStub, firstUpdateStub_);
985 : }
986 : };
987 :
988 : class ICCacheIR_Updated : public ICUpdatedStub
989 : {
990 : const CacheIRStubInfo* stubInfo_;
991 : GCPtrObjectGroup updateStubGroup_;
992 : GCPtrId updateStubId_;
993 :
994 : public:
995 1069 : ICCacheIR_Updated(JitCode* stubCode, const CacheIRStubInfo* stubInfo)
996 1069 : : ICUpdatedStub(ICStub::CacheIR_Updated, stubCode),
997 : stubInfo_(stubInfo),
998 : updateStubGroup_(nullptr),
999 1069 : updateStubId_(JSID_EMPTY)
1000 1069 : {}
1001 :
1002 : static ICCacheIR_Updated* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
1003 : ICCacheIR_Updated& other);
1004 :
1005 1667 : GCPtrObjectGroup& updateStubGroup() {
1006 1667 : return updateStubGroup_;
1007 : }
1008 1667 : GCPtrId& updateStubId() {
1009 1667 : return updateStubId_;
1010 : }
1011 :
1012 464 : void notePreliminaryObject() {
1013 464 : extra_ = 1;
1014 464 : }
1015 1031 : bool hasPreliminaryObject() const {
1016 1031 : return extra_;
1017 : }
1018 :
1019 1394 : const CacheIRStubInfo* stubInfo() const {
1020 1394 : return stubInfo_;
1021 : }
1022 :
1023 : uint8_t* stubDataStart();
1024 : };
1025 :
1026 : // Base class for stubcode compilers.
1027 44626 : class ICStubCompiler
1028 : {
1029 : // Prevent GC in the middle of stub compilation.
1030 : js::gc::AutoSuppressGC suppressGC;
1031 :
1032 : public:
1033 : using Engine = ICStubEngine;
1034 :
1035 : protected:
1036 : JSContext* cx;
1037 : ICStub::Kind kind;
1038 : Engine engine_;
1039 : bool inStubFrame_;
1040 :
1041 : #ifdef DEBUG
1042 : bool entersStubFrame_;
1043 : uint32_t framePushedAtEnterStubFrame_;
1044 : #endif
1045 :
1046 : // By default the stubcode key is just the kind.
1047 29619 : virtual int32_t getKey() const {
1048 29619 : return static_cast<int32_t>(engine_) |
1049 29619 : (static_cast<int32_t>(kind) << 1);
1050 : }
1051 :
1052 : virtual MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) = 0;
1053 2149 : virtual void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> genCode) {}
1054 :
1055 : JitCode* getStubCode();
1056 :
1057 44626 : ICStubCompiler(JSContext* cx, ICStub::Kind kind, Engine engine)
1058 44626 : : suppressGC(cx), cx(cx), kind(kind), engine_(engine), inStubFrame_(false)
1059 : #ifdef DEBUG
1060 44626 : , entersStubFrame_(false), framePushedAtEnterStubFrame_(0)
1061 : #endif
1062 44626 : {}
1063 :
1064 : // Push a payload specialized per compiler needed to execute stubs.
1065 : void PushStubPayload(MacroAssembler& masm, Register scratch);
1066 : void pushStubPayload(MacroAssembler& masm, Register scratch);
1067 :
1068 : // Emits a tail call to a VMFunction wrapper.
1069 : MOZ_MUST_USE bool tailCallVM(const VMFunction& fun, MacroAssembler& masm);
1070 :
1071 : // Emits a normal (non-tail) call to a VMFunction wrapper.
1072 : MOZ_MUST_USE bool callVM(const VMFunction& fun, MacroAssembler& masm);
1073 :
1074 : // A stub frame is used when a stub wants to call into the VM without
1075 : // performing a tail call. This is required for the return address
1076 : // to pc mapping to work.
1077 : void enterStubFrame(MacroAssembler& masm, Register scratch);
1078 : void assumeStubFrame(MacroAssembler& masm);
1079 : void leaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false);
1080 :
1081 : // Some stubs need to emit Gecko Profiler updates. This emits the guarding
1082 : // jitcode for those stubs. If profiling is not enabled, jumps to the
1083 : // given label.
1084 : void guardProfilingEnabled(MacroAssembler& masm, Register scratch, Label* skip);
1085 :
1086 : public:
1087 556 : static inline AllocatableGeneralRegisterSet availableGeneralRegs(size_t numInputs) {
1088 556 : AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
1089 : #if defined(JS_CODEGEN_ARM)
1090 : MOZ_ASSERT(!regs.has(BaselineStackReg));
1091 : MOZ_ASSERT(!regs.has(ICTailCallReg));
1092 : regs.take(BaselineSecondScratchReg);
1093 : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
1094 : MOZ_ASSERT(!regs.has(BaselineStackReg));
1095 : MOZ_ASSERT(!regs.has(ICTailCallReg));
1096 : MOZ_ASSERT(!regs.has(BaselineSecondScratchReg));
1097 : #elif defined(JS_CODEGEN_ARM64)
1098 : MOZ_ASSERT(!regs.has(PseudoStackPointer));
1099 : MOZ_ASSERT(!regs.has(RealStackPointer));
1100 : MOZ_ASSERT(!regs.has(ICTailCallReg));
1101 : #else
1102 556 : MOZ_ASSERT(!regs.has(BaselineStackReg));
1103 : #endif
1104 556 : regs.take(BaselineFrameReg);
1105 556 : regs.take(ICStubReg);
1106 : #ifdef JS_CODEGEN_X64
1107 556 : regs.take(ExtractTemp0);
1108 556 : regs.take(ExtractTemp1);
1109 : #endif
1110 :
1111 556 : switch (numInputs) {
1112 : case 0:
1113 297 : break;
1114 : case 1:
1115 120 : regs.take(R0);
1116 120 : break;
1117 : case 2:
1118 139 : regs.take(R0);
1119 139 : regs.take(R1);
1120 139 : break;
1121 : default:
1122 0 : MOZ_CRASH("Invalid numInputs");
1123 : }
1124 :
1125 556 : return regs;
1126 : }
1127 :
1128 : protected:
1129 : template <typename T, typename... Args>
1130 44426 : T* newStub(Args&&... args) {
1131 44426 : return ICStub::New<T>(cx, mozilla::Forward<Args>(args)...);
1132 : }
1133 :
1134 : public:
1135 : virtual ICStub* getStub(ICStubSpace* space) = 0;
1136 :
1137 18790 : static ICStubSpace* StubSpaceForStub(bool makesGCCalls, JSScript* outerScript, Engine engine) {
1138 18790 : if (makesGCCalls) {
1139 2138 : if (engine == ICStubCompiler::Engine::Baseline)
1140 2138 : return outerScript->baselineScript()->fallbackStubSpace();
1141 0 : return outerScript->ionScript()->fallbackStubSpace();
1142 : }
1143 16652 : return outerScript->zone()->jitZone()->optimizedStubSpace();
1144 : }
1145 12726 : ICStubSpace* getStubSpace(JSScript* outerScript) {
1146 12726 : return StubSpaceForStub(ICStub::NonCacheIRStubMakesGCCalls(kind), outerScript, engine_);
1147 : }
1148 : };
1149 :
1150 3385 : class SharedStubInfo
1151 : {
1152 : BaselineFrame* maybeFrame_;
1153 : RootedScript outerScript_;
1154 : RootedScript innerScript_;
1155 : ICEntry* icEntry_;
1156 :
1157 : public:
1158 : SharedStubInfo(JSContext* cx, void* payload, ICEntry* entry);
1159 :
1160 1273 : ICStubCompiler::Engine engine() const {
1161 1273 : return maybeFrame_
1162 1273 : ? ICStubCompiler::Engine::Baseline
1163 1273 : : ICStubCompiler::Engine::IonSharedIC;
1164 : }
1165 :
1166 934 : HandleScript script() const {
1167 934 : MOZ_ASSERT(innerScript_);
1168 934 : return innerScript_;
1169 : }
1170 :
1171 2209 : HandleScript innerScript() const {
1172 2209 : MOZ_ASSERT(innerScript_);
1173 2209 : return innerScript_;
1174 : }
1175 :
1176 : HandleScript outerScript(JSContext* cx);
1177 :
1178 2207 : jsbytecode* pc() const {
1179 2207 : return icEntry()->pc(innerScript());
1180 : }
1181 :
1182 : uint32_t pcOffset() const {
1183 : return script()->pcToOffset(pc());
1184 : }
1185 :
1186 : BaselineFrame* frame() const {
1187 : MOZ_ASSERT(maybeFrame_);
1188 : return maybeFrame_;
1189 : }
1190 :
1191 1273 : BaselineFrame* maybeFrame() const {
1192 1273 : return maybeFrame_;
1193 : }
1194 :
1195 2207 : ICEntry* icEntry() const {
1196 2207 : return icEntry_;
1197 : }
1198 : };
1199 :
1200 : // Monitored fallback stubs - as the name implies.
1201 : class ICMonitoredFallbackStub : public ICFallbackStub
1202 : {
1203 : protected:
1204 : // Pointer to the fallback monitor stub.
1205 : ICTypeMonitor_Fallback* fallbackMonitorStub_;
1206 :
1207 11286 : ICMonitoredFallbackStub(Kind kind, JitCode* stubCode)
1208 11286 : : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode),
1209 11286 : fallbackMonitorStub_(nullptr) {}
1210 :
1211 : public:
1212 : MOZ_MUST_USE bool initMonitoringChain(JSContext* cx, ICStubSpace* space);
1213 : MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
1214 : StackTypeSet* types, HandleValue val);
1215 :
1216 6438 : inline ICTypeMonitor_Fallback* fallbackMonitorStub() const {
1217 6438 : return fallbackMonitorStub_;
1218 : }
1219 :
1220 170 : static inline size_t offsetOfFallbackMonitorStub() {
1221 170 : return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_);
1222 : }
1223 : };
1224 :
1225 :
1226 : // Base class for stub compilers that can generate multiple stubcodes.
1227 : // These compilers need access to the JSOp they are compiling for.
1228 525 : class ICMultiStubCompiler : public ICStubCompiler
1229 : {
1230 : protected:
1231 : JSOp op;
1232 :
1233 : // Stub keys for multi-stub kinds are composed of both the kind
1234 : // and the op they are compiled for.
1235 345 : virtual int32_t getKey() const {
1236 690 : return static_cast<int32_t>(engine_) |
1237 345 : (static_cast<int32_t>(kind) << 1) |
1238 345 : (static_cast<int32_t>(op) << 17);
1239 : }
1240 :
1241 525 : ICMultiStubCompiler(JSContext* cx, ICStub::Kind kind, JSOp op, Engine engine)
1242 525 : : ICStubCompiler(cx, kind, engine), op(op) {}
1243 : };
1244 :
1245 : // TypeCheckPrimitiveSetStub
1246 : // Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given
1247 : // value's type falls within a set of primitive types.
1248 :
1249 : class TypeCheckPrimitiveSetStub : public ICStub
1250 : {
1251 : friend class ICStubSpace;
1252 : protected:
1253 21777 : inline static uint16_t TypeToFlag(JSValueType type) {
1254 21777 : return 1u << static_cast<unsigned>(type);
1255 : }
1256 :
1257 4638 : inline static uint16_t ValidFlags() {
1258 4638 : return ((TypeToFlag(JSVAL_TYPE_OBJECT) << 1) - 1) & ~TypeToFlag(JSVAL_TYPE_MAGIC);
1259 : }
1260 :
1261 4438 : TypeCheckPrimitiveSetStub(Kind kind, JitCode* stubCode, uint16_t flags)
1262 4438 : : ICStub(kind, stubCode)
1263 : {
1264 4438 : MOZ_ASSERT(kind == TypeMonitor_PrimitiveSet || kind == TypeUpdate_PrimitiveSet);
1265 4438 : MOZ_ASSERT(flags && !(flags & ~ValidFlags()));
1266 4438 : extra_ = flags;
1267 4438 : }
1268 :
1269 200 : TypeCheckPrimitiveSetStub* updateTypesAndCode(uint16_t flags, JitCode* code) {
1270 200 : MOZ_ASSERT(flags && !(flags & ~ValidFlags()));
1271 200 : if (!code)
1272 0 : return nullptr;
1273 200 : extra_ = flags;
1274 200 : updateCode(code);
1275 200 : return this;
1276 : }
1277 :
1278 : public:
1279 400 : uint16_t typeFlags() const {
1280 400 : return extra_;
1281 : }
1282 :
1283 3265 : bool containsType(JSValueType type) const {
1284 3265 : MOZ_ASSERT(type <= JSVAL_TYPE_OBJECT);
1285 3265 : MOZ_ASSERT(type != JSVAL_TYPE_MAGIC);
1286 3265 : return extra_ & TypeToFlag(type);
1287 : }
1288 :
1289 170 : ICTypeMonitor_PrimitiveSet* toMonitorStub() {
1290 170 : return toTypeMonitor_PrimitiveSet();
1291 : }
1292 :
1293 30 : ICTypeUpdate_PrimitiveSet* toUpdateStub() {
1294 30 : return toTypeUpdate_PrimitiveSet();
1295 : }
1296 :
1297 4638 : class Compiler : public ICStubCompiler {
1298 : protected:
1299 : TypeCheckPrimitiveSetStub* existingStub_;
1300 : uint16_t flags_;
1301 :
1302 4638 : virtual int32_t getKey() const {
1303 9276 : return static_cast<int32_t>(engine_) |
1304 4638 : (static_cast<int32_t>(kind) << 1) |
1305 4638 : (static_cast<int32_t>(flags_) << 17);
1306 : }
1307 :
1308 : public:
1309 4638 : Compiler(JSContext* cx, Kind kind, TypeCheckPrimitiveSetStub* existingStub,
1310 : JSValueType type)
1311 4638 : : ICStubCompiler(cx, kind, Engine::Baseline),
1312 : existingStub_(existingStub),
1313 4638 : flags_((existingStub ? existingStub->typeFlags() : 0) | TypeToFlag(type))
1314 : {
1315 4638 : MOZ_ASSERT_IF(existingStub_, flags_ != existingStub_->typeFlags());
1316 4638 : }
1317 :
1318 200 : TypeCheckPrimitiveSetStub* updateStub() {
1319 200 : MOZ_ASSERT(existingStub_);
1320 200 : return existingStub_->updateTypesAndCode(flags_, getStubCode());
1321 : }
1322 : };
1323 : };
1324 :
1325 : // TypeMonitor
1326 :
1327 : // The TypeMonitor fallback stub is not always a regular fallback stub. When
1328 : // used for monitoring the values pushed by a bytecode it doesn't hold a
1329 : // pointer to the IC entry, but rather back to the main fallback stub for the
1330 : // IC (from which a pointer to the IC entry can be retrieved). When monitoring
1331 : // the types of 'this', arguments or other values with no associated IC, there
1332 : // is no main fallback stub, and the IC entry is referenced directly.
1333 : class ICTypeMonitor_Fallback : public ICStub
1334 : {
1335 : friend class ICStubSpace;
1336 :
1337 : static const uint32_t MAX_OPTIMIZED_STUBS = 8;
1338 :
1339 : // Pointer to the main fallback stub for the IC or to the main IC entry,
1340 : // depending on hasFallbackStub.
1341 : union {
1342 : ICMonitoredFallbackStub* mainFallbackStub_;
1343 : ICEntry* icEntry_;
1344 : };
1345 :
1346 : // Pointer to the first monitor stub.
1347 : ICStub* firstMonitorStub_;
1348 :
1349 : // Address of the last monitor stub's field pointing to this
1350 : // fallback monitor stub. This will get updated when new
1351 : // monitor stubs are created and added.
1352 : ICStub** lastMonitorStubPtrAddr_;
1353 :
1354 : // Count of optimized type monitor stubs in this chain.
1355 : uint32_t numOptimizedMonitorStubs_ : 7;
1356 :
1357 : uint32_t invalid_ : 1;
1358 :
1359 : // Whether this has a fallback stub referring to the IC entry.
1360 : bool hasFallbackStub_ : 1;
1361 :
1362 : // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX
1363 : // if this is monitoring the types of values pushed at some bytecode.
1364 : uint32_t argumentIndex_ : 23;
1365 :
1366 : static const uint32_t BYTECODE_INDEX = (1 << 23) - 1;
1367 :
1368 13412 : ICTypeMonitor_Fallback(JitCode* stubCode, ICMonitoredFallbackStub* mainFallbackStub,
1369 : uint32_t argumentIndex)
1370 13412 : : ICStub(ICStub::TypeMonitor_Fallback, stubCode),
1371 : mainFallbackStub_(mainFallbackStub),
1372 13412 : firstMonitorStub_(thisFromCtor()),
1373 : lastMonitorStubPtrAddr_(nullptr),
1374 : numOptimizedMonitorStubs_(0),
1375 : invalid_(false),
1376 13412 : hasFallbackStub_(mainFallbackStub != nullptr),
1377 40236 : argumentIndex_(argumentIndex)
1378 13412 : { }
1379 :
1380 13412 : ICTypeMonitor_Fallback* thisFromCtor() {
1381 13412 : return this;
1382 : }
1383 :
1384 8189 : void addOptimizedMonitorStub(ICStub* stub) {
1385 8189 : MOZ_ASSERT(!invalid());
1386 8189 : stub->setNext(this);
1387 :
1388 8189 : MOZ_ASSERT((lastMonitorStubPtrAddr_ != nullptr) ==
1389 : (numOptimizedMonitorStubs_ || !hasFallbackStub_));
1390 :
1391 8189 : if (lastMonitorStubPtrAddr_)
1392 2795 : *lastMonitorStubPtrAddr_ = stub;
1393 :
1394 8189 : if (numOptimizedMonitorStubs_ == 0) {
1395 7237 : MOZ_ASSERT(firstMonitorStub_ == this);
1396 7237 : firstMonitorStub_ = stub;
1397 : } else {
1398 952 : MOZ_ASSERT(firstMonitorStub_ != nullptr);
1399 : }
1400 :
1401 8189 : lastMonitorStubPtrAddr_ = stub->addressOfNext();
1402 8189 : numOptimizedMonitorStubs_++;
1403 8189 : }
1404 :
1405 : public:
1406 4020 : bool hasStub(ICStub::Kind kind) {
1407 4020 : ICStub* stub = firstMonitorStub_;
1408 25 : do {
1409 4045 : if (stub->kind() == kind)
1410 0 : return true;
1411 :
1412 4045 : stub = stub->next();
1413 4045 : } while (stub);
1414 :
1415 4020 : return false;
1416 : }
1417 :
1418 545 : inline ICFallbackStub* mainFallbackStub() const {
1419 545 : MOZ_ASSERT(hasFallbackStub_);
1420 545 : return mainFallbackStub_;
1421 : }
1422 :
1423 2849 : inline ICEntry* icEntry() const {
1424 2849 : return hasFallbackStub_ ? mainFallbackStub()->icEntry() : icEntry_;
1425 : }
1426 :
1427 27385 : inline ICStub* firstMonitorStub() const {
1428 27385 : return firstMonitorStub_;
1429 : }
1430 :
1431 170 : static inline size_t offsetOfFirstMonitorStub() {
1432 170 : return offsetof(ICTypeMonitor_Fallback, firstMonitorStub_);
1433 : }
1434 :
1435 0 : inline uint32_t numOptimizedMonitorStubs() const {
1436 0 : return numOptimizedMonitorStubs_;
1437 : }
1438 :
1439 0 : void setInvalid() {
1440 0 : invalid_ = 1;
1441 0 : }
1442 :
1443 11037 : bool invalid() const {
1444 11037 : return invalid_;
1445 : }
1446 :
1447 3438 : inline bool monitorsThis() const {
1448 3438 : return argumentIndex_ == 0;
1449 : }
1450 :
1451 5696 : inline bool monitorsArgument(uint32_t* pargument) const {
1452 5696 : if (argumentIndex_ > 0 && argumentIndex_ < BYTECODE_INDEX) {
1453 2260 : *pargument = argumentIndex_ - 1;
1454 2260 : return true;
1455 : }
1456 3436 : return false;
1457 : }
1458 :
1459 : inline bool monitorsBytecode() const {
1460 : return argumentIndex_ == BYTECODE_INDEX;
1461 : }
1462 :
1463 : // Fixup the IC entry as for a normal fallback stub, for this/arguments.
1464 2122 : void fixupICEntry(ICEntry* icEntry) {
1465 2122 : MOZ_ASSERT(!hasFallbackStub_);
1466 2122 : MOZ_ASSERT(icEntry_ == nullptr);
1467 2122 : MOZ_ASSERT(lastMonitorStubPtrAddr_ == nullptr);
1468 2122 : icEntry_ = icEntry;
1469 2122 : lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
1470 2122 : }
1471 :
1472 : // Create a new monitor stub for the type of the given value, and
1473 : // add it to this chain.
1474 : MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame,
1475 : StackTypeSet* types, HandleValue val);
1476 :
1477 : void resetMonitorStubChain(Zone* zone);
1478 :
1479 : // Compiler for this stub kind.
1480 13412 : class Compiler : public ICStubCompiler {
1481 : ICMonitoredFallbackStub* mainFallbackStub_;
1482 : uint32_t argumentIndex_;
1483 :
1484 : protected:
1485 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1486 :
1487 : public:
1488 11923 : Compiler(JSContext* cx, ICMonitoredFallbackStub* mainFallbackStub)
1489 11923 : : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback, Engine::Baseline),
1490 : mainFallbackStub_(mainFallbackStub),
1491 11923 : argumentIndex_(BYTECODE_INDEX)
1492 11923 : { }
1493 :
1494 1489 : Compiler(JSContext* cx, uint32_t argumentIndex)
1495 1489 : : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback, Engine::Baseline),
1496 : mainFallbackStub_(nullptr),
1497 1489 : argumentIndex_(argumentIndex)
1498 1489 : { }
1499 :
1500 13412 : ICTypeMonitor_Fallback* getStub(ICStubSpace* space) {
1501 26824 : return newStub<ICTypeMonitor_Fallback>(space, getStubCode(), mainFallbackStub_,
1502 26824 : argumentIndex_);
1503 : }
1504 : };
1505 : };
1506 :
1507 : class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub
1508 : {
1509 : friend class ICStubSpace;
1510 :
1511 4020 : ICTypeMonitor_PrimitiveSet(JitCode* stubCode, uint16_t flags)
1512 4020 : : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags)
1513 4020 : {}
1514 :
1515 : public:
1516 4190 : class Compiler : public TypeCheckPrimitiveSetStub::Compiler {
1517 : protected:
1518 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1519 :
1520 : public:
1521 4190 : Compiler(JSContext* cx, ICTypeMonitor_PrimitiveSet* existingStub,
1522 : JSValueType type)
1523 4190 : : TypeCheckPrimitiveSetStub::Compiler(cx, TypeMonitor_PrimitiveSet, existingStub,
1524 4190 : type)
1525 4190 : {}
1526 :
1527 170 : ICTypeMonitor_PrimitiveSet* updateStub() {
1528 : TypeCheckPrimitiveSetStub* stub =
1529 170 : this->TypeCheckPrimitiveSetStub::Compiler::updateStub();
1530 170 : if (!stub)
1531 0 : return nullptr;
1532 170 : return stub->toMonitorStub();
1533 : }
1534 :
1535 4020 : ICTypeMonitor_PrimitiveSet* getStub(ICStubSpace* space) {
1536 4020 : MOZ_ASSERT(!existingStub_);
1537 4020 : return newStub<ICTypeMonitor_PrimitiveSet>(space, getStubCode(), flags_);
1538 : }
1539 : };
1540 : };
1541 :
1542 : class ICTypeMonitor_SingleObject : public ICStub
1543 : {
1544 : friend class ICStubSpace;
1545 :
1546 : GCPtrObject obj_;
1547 :
1548 : ICTypeMonitor_SingleObject(JitCode* stubCode, JSObject* obj);
1549 :
1550 : public:
1551 2668 : GCPtrObject& object() {
1552 2668 : return obj_;
1553 : }
1554 :
1555 59 : static size_t offsetOfObject() {
1556 59 : return offsetof(ICTypeMonitor_SingleObject, obj_);
1557 : }
1558 :
1559 1377 : class Compiler : public ICStubCompiler {
1560 : protected:
1561 : HandleObject obj_;
1562 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1563 :
1564 : public:
1565 1377 : Compiler(JSContext* cx, HandleObject obj)
1566 1377 : : ICStubCompiler(cx, TypeMonitor_SingleObject, Engine::Baseline),
1567 1377 : obj_(obj)
1568 1377 : { }
1569 :
1570 1377 : ICTypeMonitor_SingleObject* getStub(ICStubSpace* space) {
1571 1377 : return newStub<ICTypeMonitor_SingleObject>(space, getStubCode(), obj_);
1572 : }
1573 : };
1574 : };
1575 :
1576 : class ICTypeMonitor_ObjectGroup : public ICStub
1577 : {
1578 : friend class ICStubSpace;
1579 :
1580 : GCPtrObjectGroup group_;
1581 :
1582 : ICTypeMonitor_ObjectGroup(JitCode* stubCode, ObjectGroup* group);
1583 :
1584 : public:
1585 3801 : GCPtrObjectGroup& group() {
1586 3801 : return group_;
1587 : }
1588 :
1589 66 : static size_t offsetOfGroup() {
1590 66 : return offsetof(ICTypeMonitor_ObjectGroup, group_);
1591 : }
1592 :
1593 2792 : class Compiler : public ICStubCompiler {
1594 : protected:
1595 : HandleObjectGroup group_;
1596 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1597 :
1598 : public:
1599 2792 : Compiler(JSContext* cx, HandleObjectGroup group)
1600 2792 : : ICStubCompiler(cx, TypeMonitor_ObjectGroup, Engine::Baseline),
1601 2792 : group_(group)
1602 2792 : { }
1603 :
1604 2792 : ICTypeMonitor_ObjectGroup* getStub(ICStubSpace* space) {
1605 2792 : return newStub<ICTypeMonitor_ObjectGroup>(space, getStubCode(), group_);
1606 : }
1607 : };
1608 : };
1609 :
1610 : class ICTypeMonitor_AnyValue : public ICStub
1611 : {
1612 : friend class ICStubSpace;
1613 :
1614 0 : explicit ICTypeMonitor_AnyValue(JitCode* stubCode)
1615 0 : : ICStub(TypeMonitor_AnyValue, stubCode)
1616 0 : {}
1617 :
1618 : public:
1619 0 : class Compiler : public ICStubCompiler {
1620 : protected:
1621 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1622 :
1623 : public:
1624 0 : explicit Compiler(JSContext* cx)
1625 0 : : ICStubCompiler(cx, TypeMonitor_AnyValue, Engine::Baseline)
1626 0 : { }
1627 :
1628 0 : ICTypeMonitor_AnyValue* getStub(ICStubSpace* space) {
1629 0 : return newStub<ICTypeMonitor_AnyValue>(space, getStubCode());
1630 : }
1631 : };
1632 : };
1633 :
1634 : // BinaryArith
1635 : // JSOP_ADD, JSOP_SUB, JSOP_MUL, JOP_DIV, JSOP_MOD
1636 : // JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR
1637 : // JSOP_LSH, JSOP_RSH, JSOP_URSH
1638 :
1639 : class ICBinaryArith_Fallback : public ICFallbackStub
1640 : {
1641 : friend class ICStubSpace;
1642 :
1643 645 : explicit ICBinaryArith_Fallback(JitCode* stubCode)
1644 645 : : ICFallbackStub(BinaryArith_Fallback, stubCode)
1645 : {
1646 645 : extra_ = 0;
1647 645 : }
1648 :
1649 : static const uint16_t SAW_DOUBLE_RESULT_BIT = 0x1;
1650 : static const uint16_t UNOPTIMIZABLE_OPERANDS_BIT = 0x2;
1651 :
1652 : public:
1653 : static const uint32_t MAX_OPTIMIZED_STUBS = 8;
1654 :
1655 13 : bool sawDoubleResult() const {
1656 13 : return extra_ & SAW_DOUBLE_RESULT_BIT;
1657 : }
1658 1 : void setSawDoubleResult() {
1659 1 : extra_ |= SAW_DOUBLE_RESULT_BIT;
1660 1 : }
1661 0 : bool hadUnoptimizableOperands() const {
1662 0 : return extra_ & UNOPTIMIZABLE_OPERANDS_BIT;
1663 : }
1664 11 : void noteUnoptimizableOperands() {
1665 11 : extra_ |= UNOPTIMIZABLE_OPERANDS_BIT;
1666 11 : }
1667 :
1668 : // Compiler for this stub kind.
1669 645 : class Compiler : public ICStubCompiler {
1670 : protected:
1671 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1672 :
1673 : public:
1674 645 : explicit Compiler(JSContext* cx, Engine engine)
1675 645 : : ICStubCompiler(cx, ICStub::BinaryArith_Fallback, engine) {}
1676 :
1677 645 : ICStub* getStub(ICStubSpace* space) {
1678 645 : return newStub<ICBinaryArith_Fallback>(space, getStubCode());
1679 : }
1680 : };
1681 : };
1682 :
1683 : class ICBinaryArith_Int32 : public ICStub
1684 : {
1685 : friend class ICStubSpace;
1686 :
1687 191 : ICBinaryArith_Int32(JitCode* stubCode, bool allowDouble)
1688 191 : : ICStub(BinaryArith_Int32, stubCode)
1689 : {
1690 191 : extra_ = allowDouble;
1691 191 : }
1692 :
1693 : public:
1694 6 : bool allowDouble() const {
1695 6 : return extra_;
1696 : }
1697 :
1698 : // Compiler for this stub kind.
1699 191 : class Compiler : public ICStubCompiler {
1700 : protected:
1701 : JSOp op_;
1702 : bool allowDouble_;
1703 :
1704 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1705 :
1706 : // Stub keys shift-stubs need to encode the kind, the JSOp and if we allow doubles.
1707 191 : virtual int32_t getKey() const {
1708 382 : return static_cast<int32_t>(engine_) |
1709 382 : (static_cast<int32_t>(kind) << 1) |
1710 191 : (static_cast<int32_t>(op_) << 17) |
1711 191 : (static_cast<int32_t>(allowDouble_) << 25);
1712 : }
1713 :
1714 : public:
1715 191 : Compiler(JSContext* cx, JSOp op, Engine engine, bool allowDouble)
1716 191 : : ICStubCompiler(cx, ICStub::BinaryArith_Int32, engine),
1717 191 : op_(op), allowDouble_(allowDouble) {}
1718 :
1719 191 : ICStub* getStub(ICStubSpace* space) {
1720 191 : return newStub<ICBinaryArith_Int32>(space, getStubCode(), allowDouble_);
1721 : }
1722 : };
1723 : };
1724 :
1725 : class ICBinaryArith_StringConcat : public ICStub
1726 : {
1727 : friend class ICStubSpace;
1728 :
1729 62 : explicit ICBinaryArith_StringConcat(JitCode* stubCode)
1730 62 : : ICStub(BinaryArith_StringConcat, stubCode)
1731 62 : {}
1732 :
1733 : public:
1734 62 : class Compiler : public ICStubCompiler {
1735 : protected:
1736 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1737 :
1738 : public:
1739 62 : explicit Compiler(JSContext* cx, Engine engine)
1740 62 : : ICStubCompiler(cx, ICStub::BinaryArith_StringConcat, engine)
1741 62 : {}
1742 :
1743 62 : ICStub* getStub(ICStubSpace* space) {
1744 62 : return newStub<ICBinaryArith_StringConcat>(space, getStubCode());
1745 : }
1746 : };
1747 : };
1748 :
1749 : class ICBinaryArith_StringObjectConcat : public ICStub
1750 : {
1751 : friend class ICStubSpace;
1752 :
1753 0 : ICBinaryArith_StringObjectConcat(JitCode* stubCode, bool lhsIsString)
1754 0 : : ICStub(BinaryArith_StringObjectConcat, stubCode)
1755 : {
1756 0 : extra_ = lhsIsString;
1757 0 : }
1758 :
1759 : public:
1760 : bool lhsIsString() const {
1761 : return extra_;
1762 : }
1763 :
1764 0 : class Compiler : public ICStubCompiler {
1765 : protected:
1766 : bool lhsIsString_;
1767 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1768 :
1769 0 : virtual int32_t getKey() const {
1770 0 : return static_cast<int32_t>(engine_) |
1771 0 : (static_cast<int32_t>(kind) << 1) |
1772 0 : (static_cast<int32_t>(lhsIsString_) << 17);
1773 : }
1774 :
1775 : public:
1776 0 : Compiler(JSContext* cx, Engine engine, bool lhsIsString)
1777 0 : : ICStubCompiler(cx, ICStub::BinaryArith_StringObjectConcat, engine),
1778 0 : lhsIsString_(lhsIsString)
1779 0 : {}
1780 :
1781 0 : ICStub* getStub(ICStubSpace* space) {
1782 0 : return newStub<ICBinaryArith_StringObjectConcat>(space, getStubCode(),
1783 0 : lhsIsString_);
1784 : }
1785 : };
1786 : };
1787 :
1788 : class ICBinaryArith_Double : public ICStub
1789 : {
1790 : friend class ICStubSpace;
1791 :
1792 1 : explicit ICBinaryArith_Double(JitCode* stubCode)
1793 1 : : ICStub(BinaryArith_Double, stubCode)
1794 1 : {}
1795 :
1796 : public:
1797 1 : class Compiler : public ICMultiStubCompiler {
1798 : protected:
1799 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1800 :
1801 : public:
1802 1 : Compiler(JSContext* cx, JSOp op, Engine engine)
1803 1 : : ICMultiStubCompiler(cx, ICStub::BinaryArith_Double, op, engine)
1804 1 : {}
1805 :
1806 1 : ICStub* getStub(ICStubSpace* space) {
1807 1 : return newStub<ICBinaryArith_Double>(space, getStubCode());
1808 : }
1809 : };
1810 : };
1811 :
1812 : class ICBinaryArith_BooleanWithInt32 : public ICStub
1813 : {
1814 : friend class ICStubSpace;
1815 :
1816 4 : ICBinaryArith_BooleanWithInt32(JitCode* stubCode, bool lhsIsBool, bool rhsIsBool)
1817 4 : : ICStub(BinaryArith_BooleanWithInt32, stubCode)
1818 : {
1819 4 : MOZ_ASSERT(lhsIsBool || rhsIsBool);
1820 4 : extra_ = 0;
1821 4 : if (lhsIsBool)
1822 0 : extra_ |= 1;
1823 4 : if (rhsIsBool)
1824 4 : extra_ |= 2;
1825 4 : }
1826 :
1827 : public:
1828 : bool lhsIsBoolean() const {
1829 : return extra_ & 1;
1830 : }
1831 :
1832 : bool rhsIsBoolean() const {
1833 : return extra_ & 2;
1834 : }
1835 :
1836 4 : class Compiler : public ICStubCompiler {
1837 : protected:
1838 : JSOp op_;
1839 : bool lhsIsBool_;
1840 : bool rhsIsBool_;
1841 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1842 :
1843 4 : virtual int32_t getKey() const {
1844 8 : return static_cast<int32_t>(engine_) |
1845 8 : (static_cast<int32_t>(kind) << 1) |
1846 8 : (static_cast<int32_t>(op_) << 17) |
1847 4 : (static_cast<int32_t>(lhsIsBool_) << 25) |
1848 4 : (static_cast<int32_t>(rhsIsBool_) << 26);
1849 : }
1850 :
1851 : public:
1852 4 : Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsBool, bool rhsIsBool)
1853 4 : : ICStubCompiler(cx, ICStub::BinaryArith_BooleanWithInt32, engine),
1854 4 : op_(op), lhsIsBool_(lhsIsBool), rhsIsBool_(rhsIsBool)
1855 : {
1856 4 : MOZ_ASSERT(op_ == JSOP_ADD || op_ == JSOP_SUB || op_ == JSOP_BITOR ||
1857 : op_ == JSOP_BITAND || op_ == JSOP_BITXOR);
1858 4 : MOZ_ASSERT(lhsIsBool_ || rhsIsBool_);
1859 4 : }
1860 :
1861 4 : ICStub* getStub(ICStubSpace* space) {
1862 8 : return newStub<ICBinaryArith_BooleanWithInt32>(space, getStubCode(),
1863 8 : lhsIsBool_, rhsIsBool_);
1864 : }
1865 : };
1866 : };
1867 :
1868 : class ICBinaryArith_DoubleWithInt32 : public ICStub
1869 : {
1870 : friend class ICStubSpace;
1871 :
1872 0 : ICBinaryArith_DoubleWithInt32(JitCode* stubCode, bool lhsIsDouble)
1873 0 : : ICStub(BinaryArith_DoubleWithInt32, stubCode)
1874 : {
1875 0 : extra_ = lhsIsDouble;
1876 0 : }
1877 :
1878 : public:
1879 : bool lhsIsDouble() const {
1880 : return extra_;
1881 : }
1882 :
1883 0 : class Compiler : public ICMultiStubCompiler {
1884 : protected:
1885 : bool lhsIsDouble_;
1886 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1887 :
1888 0 : virtual int32_t getKey() const {
1889 0 : return static_cast<int32_t>(engine_) |
1890 0 : (static_cast<int32_t>(kind) << 1) |
1891 0 : (static_cast<int32_t>(op) << 17) |
1892 0 : (static_cast<int32_t>(lhsIsDouble_) << 25);
1893 : }
1894 :
1895 : public:
1896 0 : Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsDouble)
1897 0 : : ICMultiStubCompiler(cx, ICStub::BinaryArith_DoubleWithInt32, op, engine),
1898 0 : lhsIsDouble_(lhsIsDouble)
1899 0 : {}
1900 :
1901 0 : ICStub* getStub(ICStubSpace* space) {
1902 0 : return newStub<ICBinaryArith_DoubleWithInt32>(space, getStubCode(),
1903 0 : lhsIsDouble_);
1904 : }
1905 : };
1906 : };
1907 :
1908 : // UnaryArith
1909 : // JSOP_BITNOT
1910 : // JSOP_NEG
1911 :
1912 : class ICUnaryArith_Fallback : public ICFallbackStub
1913 : {
1914 : friend class ICStubSpace;
1915 :
1916 2 : explicit ICUnaryArith_Fallback(JitCode* stubCode)
1917 2 : : ICFallbackStub(UnaryArith_Fallback, stubCode)
1918 : {
1919 2 : extra_ = 0;
1920 2 : }
1921 :
1922 : public:
1923 : static const uint32_t MAX_OPTIMIZED_STUBS = 8;
1924 :
1925 0 : bool sawDoubleResult() {
1926 0 : return extra_;
1927 : }
1928 0 : void setSawDoubleResult() {
1929 0 : extra_ = 1;
1930 0 : }
1931 :
1932 : // Compiler for this stub kind.
1933 2 : class Compiler : public ICStubCompiler {
1934 : protected:
1935 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1936 :
1937 : public:
1938 2 : explicit Compiler(JSContext* cx, Engine engine)
1939 2 : : ICStubCompiler(cx, ICStub::UnaryArith_Fallback, engine)
1940 2 : {}
1941 :
1942 2 : ICStub* getStub(ICStubSpace* space) {
1943 2 : return newStub<ICUnaryArith_Fallback>(space, getStubCode());
1944 : }
1945 : };
1946 : };
1947 :
1948 : class ICUnaryArith_Int32 : public ICStub
1949 : {
1950 : friend class ICStubSpace;
1951 :
1952 1 : explicit ICUnaryArith_Int32(JitCode* stubCode)
1953 1 : : ICStub(UnaryArith_Int32, stubCode)
1954 1 : {}
1955 :
1956 : public:
1957 1 : class Compiler : public ICMultiStubCompiler {
1958 : protected:
1959 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1960 :
1961 : public:
1962 1 : Compiler(JSContext* cx, JSOp op, Engine engine)
1963 1 : : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op, engine)
1964 1 : {}
1965 :
1966 1 : ICStub* getStub(ICStubSpace* space) {
1967 1 : return newStub<ICUnaryArith_Int32>(space, getStubCode());
1968 : }
1969 : };
1970 : };
1971 :
1972 : class ICUnaryArith_Double : public ICStub
1973 : {
1974 : friend class ICStubSpace;
1975 :
1976 0 : explicit ICUnaryArith_Double(JitCode* stubCode)
1977 0 : : ICStub(UnaryArith_Double, stubCode)
1978 0 : {}
1979 :
1980 : public:
1981 0 : class Compiler : public ICMultiStubCompiler {
1982 : protected:
1983 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
1984 :
1985 : public:
1986 0 : Compiler(JSContext* cx, JSOp op, Engine engine)
1987 0 : : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op, engine)
1988 0 : {}
1989 :
1990 0 : ICStub* getStub(ICStubSpace* space) {
1991 0 : return newStub<ICUnaryArith_Double>(space, getStubCode());
1992 : }
1993 : };
1994 : };
1995 :
1996 : // Compare
1997 : // JSOP_LT
1998 : // JSOP_LE
1999 : // JSOP_GT
2000 : // JSOP_GE
2001 : // JSOP_EQ
2002 : // JSOP_NE
2003 : // JSOP_STRICTEQ
2004 : // JSOP_STRICTNE
2005 :
2006 : class ICCompare_Fallback : public ICFallbackStub
2007 : {
2008 : friend class ICStubSpace;
2009 :
2010 1202 : explicit ICCompare_Fallback(JitCode* stubCode)
2011 1202 : : ICFallbackStub(ICStub::Compare_Fallback, stubCode) {}
2012 :
2013 : public:
2014 : static const uint32_t MAX_OPTIMIZED_STUBS = 8;
2015 :
2016 : static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
2017 90 : void noteUnoptimizableAccess() {
2018 90 : extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
2019 90 : }
2020 2 : bool hadUnoptimizableAccess() const {
2021 2 : return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
2022 : }
2023 :
2024 : // Compiler for this stub kind.
2025 1202 : class Compiler : public ICStubCompiler {
2026 : protected:
2027 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2028 :
2029 : public:
2030 1202 : explicit Compiler(JSContext* cx, Engine engine)
2031 1202 : : ICStubCompiler(cx, ICStub::Compare_Fallback, engine) {}
2032 :
2033 1202 : ICStub* getStub(ICStubSpace* space) {
2034 1202 : return newStub<ICCompare_Fallback>(space, getStubCode());
2035 : }
2036 : };
2037 : };
2038 :
2039 : class ICCompare_Int32 : public ICStub
2040 : {
2041 : friend class ICStubSpace;
2042 :
2043 330 : explicit ICCompare_Int32(JitCode* stubCode)
2044 330 : : ICStub(ICStub::Compare_Int32, stubCode) {}
2045 :
2046 : public:
2047 : // Compiler for this stub kind.
2048 330 : class Compiler : public ICMultiStubCompiler {
2049 : protected:
2050 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2051 :
2052 : public:
2053 330 : Compiler(JSContext* cx, JSOp op, Engine engine)
2054 330 : : ICMultiStubCompiler(cx, ICStub::Compare_Int32, op, engine) {}
2055 :
2056 330 : ICStub* getStub(ICStubSpace* space) {
2057 330 : return newStub<ICCompare_Int32>(space, getStubCode());
2058 : }
2059 : };
2060 : };
2061 :
2062 : class ICCompare_Double : public ICStub
2063 : {
2064 : friend class ICStubSpace;
2065 :
2066 11 : explicit ICCompare_Double(JitCode* stubCode)
2067 11 : : ICStub(ICStub::Compare_Double, stubCode)
2068 11 : {}
2069 :
2070 : public:
2071 11 : class Compiler : public ICMultiStubCompiler {
2072 : protected:
2073 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2074 :
2075 : public:
2076 11 : Compiler(JSContext* cx, JSOp op, Engine engine)
2077 11 : : ICMultiStubCompiler(cx, ICStub::Compare_Double, op, engine)
2078 11 : {}
2079 :
2080 11 : ICStub* getStub(ICStubSpace* space) {
2081 11 : return newStub<ICCompare_Double>(space, getStubCode());
2082 : }
2083 : };
2084 : };
2085 :
2086 : class ICCompare_NumberWithUndefined : public ICStub
2087 : {
2088 : friend class ICStubSpace;
2089 :
2090 2 : ICCompare_NumberWithUndefined(JitCode* stubCode, bool lhsIsUndefined)
2091 2 : : ICStub(ICStub::Compare_NumberWithUndefined, stubCode)
2092 : {
2093 2 : extra_ = lhsIsUndefined;
2094 2 : }
2095 :
2096 : public:
2097 0 : bool lhsIsUndefined() {
2098 0 : return extra_;
2099 : }
2100 :
2101 2 : class Compiler : public ICMultiStubCompiler {
2102 : protected:
2103 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2104 :
2105 : bool lhsIsUndefined;
2106 :
2107 : public:
2108 2 : Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsUndefined)
2109 2 : : ICMultiStubCompiler(cx, ICStub::Compare_NumberWithUndefined, op, engine),
2110 2 : lhsIsUndefined(lhsIsUndefined)
2111 2 : {}
2112 :
2113 2 : virtual int32_t getKey() const {
2114 4 : return static_cast<int32_t>(engine_) |
2115 4 : (static_cast<int32_t>(kind) << 1) |
2116 2 : (static_cast<int32_t>(op) << 17) |
2117 2 : (static_cast<int32_t>(lhsIsUndefined) << 25);
2118 : }
2119 :
2120 2 : ICStub* getStub(ICStubSpace* space) {
2121 4 : return newStub<ICCompare_NumberWithUndefined>(space, getStubCode(),
2122 4 : lhsIsUndefined);
2123 : }
2124 : };
2125 : };
2126 :
2127 : class ICCompare_String : public ICStub
2128 : {
2129 : friend class ICStubSpace;
2130 :
2131 0 : explicit ICCompare_String(JitCode* stubCode)
2132 0 : : ICStub(ICStub::Compare_String, stubCode)
2133 0 : {}
2134 :
2135 : public:
2136 0 : class Compiler : public ICMultiStubCompiler {
2137 : protected:
2138 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2139 :
2140 : public:
2141 0 : Compiler(JSContext* cx, JSOp op, Engine engine)
2142 0 : : ICMultiStubCompiler(cx, ICStub::Compare_String, op, engine)
2143 0 : {}
2144 :
2145 0 : ICStub* getStub(ICStubSpace* space) {
2146 0 : return newStub<ICCompare_String>(space, getStubCode());
2147 : }
2148 : };
2149 : };
2150 :
2151 : class ICCompare_Symbol : public ICStub
2152 : {
2153 : friend class ICStubSpace;
2154 :
2155 0 : explicit ICCompare_Symbol(JitCode* stubCode)
2156 0 : : ICStub(ICStub::Compare_Symbol, stubCode)
2157 0 : {}
2158 :
2159 : public:
2160 0 : class Compiler : public ICMultiStubCompiler {
2161 : protected:
2162 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2163 :
2164 : public:
2165 0 : Compiler(JSContext* cx, JSOp op, Engine engine)
2166 0 : : ICMultiStubCompiler(cx, ICStub::Compare_Symbol, op, engine)
2167 0 : {}
2168 :
2169 0 : ICStub* getStub(ICStubSpace* space) {
2170 0 : return newStub<ICCompare_Symbol>(space, getStubCode());
2171 : }
2172 : };
2173 : };
2174 :
2175 : class ICCompare_Boolean : public ICStub
2176 : {
2177 : friend class ICStubSpace;
2178 :
2179 2 : explicit ICCompare_Boolean(JitCode* stubCode)
2180 2 : : ICStub(ICStub::Compare_Boolean, stubCode)
2181 2 : {}
2182 :
2183 : public:
2184 2 : class Compiler : public ICMultiStubCompiler {
2185 : protected:
2186 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2187 :
2188 : public:
2189 2 : Compiler(JSContext* cx, JSOp op, Engine engine)
2190 2 : : ICMultiStubCompiler(cx, ICStub::Compare_Boolean, op, engine)
2191 2 : {}
2192 :
2193 2 : ICStub* getStub(ICStubSpace* space) {
2194 2 : return newStub<ICCompare_Boolean>(space, getStubCode());
2195 : }
2196 : };
2197 : };
2198 :
2199 : class ICCompare_Object : public ICStub
2200 : {
2201 : friend class ICStubSpace;
2202 :
2203 0 : explicit ICCompare_Object(JitCode* stubCode)
2204 0 : : ICStub(ICStub::Compare_Object, stubCode)
2205 0 : {}
2206 :
2207 : public:
2208 0 : class Compiler : public ICMultiStubCompiler {
2209 : protected:
2210 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2211 :
2212 : public:
2213 0 : Compiler(JSContext* cx, JSOp op, Engine engine)
2214 0 : : ICMultiStubCompiler(cx, ICStub::Compare_Object, op, engine)
2215 0 : {}
2216 :
2217 0 : ICStub* getStub(ICStubSpace* space) {
2218 0 : return newStub<ICCompare_Object>(space, getStubCode());
2219 : }
2220 : };
2221 : };
2222 :
2223 : class ICCompare_ObjectWithUndefined : public ICStub
2224 : {
2225 : friend class ICStubSpace;
2226 :
2227 178 : explicit ICCompare_ObjectWithUndefined(JitCode* stubCode)
2228 178 : : ICStub(ICStub::Compare_ObjectWithUndefined, stubCode)
2229 178 : {}
2230 :
2231 : public:
2232 178 : class Compiler : public ICMultiStubCompiler {
2233 : protected:
2234 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2235 :
2236 : bool lhsIsUndefined;
2237 : bool compareWithNull;
2238 :
2239 : public:
2240 178 : Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsUndefined, bool compareWithNull)
2241 178 : : ICMultiStubCompiler(cx, ICStub::Compare_ObjectWithUndefined, op, engine),
2242 : lhsIsUndefined(lhsIsUndefined),
2243 178 : compareWithNull(compareWithNull)
2244 178 : {}
2245 :
2246 178 : virtual int32_t getKey() const {
2247 356 : return static_cast<int32_t>(engine_) |
2248 356 : (static_cast<int32_t>(kind) << 1) |
2249 356 : (static_cast<int32_t>(op) << 17) |
2250 178 : (static_cast<int32_t>(lhsIsUndefined) << 25) |
2251 178 : (static_cast<int32_t>(compareWithNull) << 26);
2252 : }
2253 :
2254 178 : ICStub* getStub(ICStubSpace* space) {
2255 178 : return newStub<ICCompare_ObjectWithUndefined>(space, getStubCode());
2256 : }
2257 : };
2258 : };
2259 :
2260 : class ICCompare_Int32WithBoolean : public ICStub
2261 : {
2262 : friend class ICStubSpace;
2263 :
2264 0 : ICCompare_Int32WithBoolean(JitCode* stubCode, bool lhsIsInt32)
2265 0 : : ICStub(ICStub::Compare_Int32WithBoolean, stubCode)
2266 : {
2267 0 : extra_ = lhsIsInt32;
2268 0 : }
2269 :
2270 : public:
2271 0 : bool lhsIsInt32() const {
2272 0 : return extra_;
2273 : }
2274 :
2275 : // Compiler for this stub kind.
2276 0 : class Compiler : public ICStubCompiler {
2277 : protected:
2278 : JSOp op_;
2279 : bool lhsIsInt32_;
2280 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2281 :
2282 0 : virtual int32_t getKey() const {
2283 0 : return static_cast<int32_t>(engine_) |
2284 0 : (static_cast<int32_t>(kind) << 1) |
2285 0 : (static_cast<int32_t>(op_) << 17) |
2286 0 : (static_cast<int32_t>(lhsIsInt32_) << 25);
2287 : }
2288 :
2289 : public:
2290 0 : Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsInt32)
2291 0 : : ICStubCompiler(cx, ICStub::Compare_Int32WithBoolean, engine),
2292 : op_(op),
2293 0 : lhsIsInt32_(lhsIsInt32)
2294 0 : {}
2295 :
2296 0 : ICStub* getStub(ICStubSpace* space) {
2297 0 : return newStub<ICCompare_Int32WithBoolean>(space, getStubCode(), lhsIsInt32_);
2298 : }
2299 : };
2300 : };
2301 :
2302 : // Enum for stubs handling a combination of typed arrays and typed objects.
2303 : enum TypedThingLayout {
2304 : Layout_TypedArray,
2305 : Layout_OutlineTypedObject,
2306 : Layout_InlineTypedObject
2307 : };
2308 :
2309 : static inline TypedThingLayout
2310 0 : GetTypedThingLayout(const Class* clasp)
2311 : {
2312 0 : if (IsTypedArrayClass(clasp))
2313 0 : return Layout_TypedArray;
2314 0 : if (IsOutlineTypedObjectClass(clasp))
2315 0 : return Layout_OutlineTypedObject;
2316 0 : if (IsInlineTypedObjectClass(clasp))
2317 0 : return Layout_InlineTypedObject;
2318 0 : MOZ_CRASH("Bad object class");
2319 : }
2320 :
2321 : bool
2322 : IsPreliminaryObject(JSObject* obj);
2323 :
2324 : void
2325 : StripPreliminaryObjectStubs(JSContext* cx, ICFallbackStub* stub);
2326 :
2327 : MOZ_MUST_USE bool
2328 : CheckHasNoSuchOwnProperty(JSContext* cx, JSObject* obj, jsid id);
2329 :
2330 : MOZ_MUST_USE bool
2331 : CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, jsid id,
2332 : JSObject** lastProto = nullptr, size_t* protoChainDepthOut = nullptr);
2333 :
2334 : void
2335 : CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure);
2336 :
2337 : void
2338 : LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result);
2339 :
2340 : bool
2341 : IsPrimitiveArrayTypedObject(JSObject* obj);
2342 :
2343 : Scalar::Type
2344 : TypedThingElementType(JSObject* obj);
2345 :
2346 : bool
2347 : TypedThingRequiresFloatingPoint(JSObject* obj);
2348 :
2349 : void
2350 : LoadTypedThingLength(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result);
2351 :
2352 : class ICGetProp_Fallback : public ICMonitoredFallbackStub
2353 : {
2354 : friend class ICStubSpace;
2355 :
2356 3722 : explicit ICGetProp_Fallback(JitCode* stubCode)
2357 3722 : : ICMonitoredFallbackStub(ICStub::GetProp_Fallback, stubCode)
2358 3722 : { }
2359 :
2360 : public:
2361 : static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
2362 : static const size_t ACCESSED_GETTER_BIT = 1;
2363 :
2364 2328 : void noteUnoptimizableAccess() {
2365 2328 : extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
2366 2328 : }
2367 22 : bool hadUnoptimizableAccess() const {
2368 22 : return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
2369 : }
2370 :
2371 715 : void noteAccessedGetter() {
2372 715 : extra_ |= (1u << ACCESSED_GETTER_BIT);
2373 715 : }
2374 14 : bool hasAccessedGetter() const {
2375 14 : return extra_ & (1u << ACCESSED_GETTER_BIT);
2376 : }
2377 :
2378 3722 : class Compiler : public ICStubCompiler {
2379 : protected:
2380 : CodeOffset bailoutReturnOffset_;
2381 : bool hasReceiver_;
2382 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2383 : void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> code);
2384 :
2385 3792 : virtual int32_t getKey() const {
2386 7584 : return static_cast<int32_t>(engine_) |
2387 3792 : (static_cast<int32_t>(kind) << 1) |
2388 3792 : (static_cast<int32_t>(hasReceiver_) << 17);
2389 : }
2390 :
2391 : public:
2392 3722 : explicit Compiler(JSContext* cx, Engine engine, bool hasReceiver = false)
2393 3722 : : ICStubCompiler(cx, ICStub::GetProp_Fallback, engine),
2394 3722 : hasReceiver_(hasReceiver)
2395 3722 : { }
2396 :
2397 3722 : ICStub* getStub(ICStubSpace* space) {
2398 3722 : ICGetProp_Fallback* stub = newStub<ICGetProp_Fallback>(space, getStubCode());
2399 3722 : if (!stub || !stub->initMonitoringChain(cx, space))
2400 0 : return nullptr;
2401 3722 : return stub;
2402 : }
2403 : };
2404 : };
2405 :
2406 : static inline uint32_t
2407 0 : SimpleTypeDescrKey(SimpleTypeDescr* descr)
2408 : {
2409 0 : if (descr->is<ScalarTypeDescr>())
2410 0 : return uint32_t(descr->as<ScalarTypeDescr>().type()) << 1;
2411 0 : return (uint32_t(descr->as<ReferenceTypeDescr>().type()) << 1) | 1;
2412 : }
2413 :
2414 : inline bool
2415 0 : SimpleTypeDescrKeyIsScalar(uint32_t key)
2416 : {
2417 0 : return !(key & 1);
2418 : }
2419 :
2420 : inline ScalarTypeDescr::Type
2421 0 : ScalarTypeFromSimpleTypeDescrKey(uint32_t key)
2422 : {
2423 0 : MOZ_ASSERT(SimpleTypeDescrKeyIsScalar(key));
2424 0 : return ScalarTypeDescr::Type(key >> 1);
2425 : }
2426 :
2427 : inline ReferenceTypeDescr::Type
2428 0 : ReferenceTypeFromSimpleTypeDescrKey(uint32_t key)
2429 : {
2430 0 : MOZ_ASSERT(!SimpleTypeDescrKeyIsScalar(key));
2431 0 : return ReferenceTypeDescr::Type(key >> 1);
2432 : }
2433 :
2434 : // JSOP_NEWARRAY
2435 : // JSOP_NEWINIT
2436 :
2437 : class ICNewArray_Fallback : public ICFallbackStub
2438 : {
2439 : friend class ICStubSpace;
2440 :
2441 : GCPtrObject templateObject_;
2442 :
2443 : // The group used for objects created here is always available, even if the
2444 : // template object itself is not.
2445 : GCPtrObjectGroup templateGroup_;
2446 :
2447 138 : ICNewArray_Fallback(JitCode* stubCode, ObjectGroup* templateGroup)
2448 138 : : ICFallbackStub(ICStub::NewArray_Fallback, stubCode),
2449 138 : templateObject_(nullptr), templateGroup_(templateGroup)
2450 138 : {}
2451 :
2452 : public:
2453 138 : class Compiler : public ICStubCompiler {
2454 : RootedObjectGroup templateGroup;
2455 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2456 :
2457 : public:
2458 138 : Compiler(JSContext* cx, ObjectGroup* templateGroup, Engine engine)
2459 138 : : ICStubCompiler(cx, ICStub::NewArray_Fallback, engine),
2460 138 : templateGroup(cx, templateGroup)
2461 138 : {}
2462 :
2463 138 : ICStub* getStub(ICStubSpace* space) {
2464 138 : return newStub<ICNewArray_Fallback>(space, getStubCode(), templateGroup);
2465 : }
2466 : };
2467 :
2468 2347 : GCPtrObject& templateObject() {
2469 2347 : return templateObject_;
2470 : }
2471 :
2472 46 : void setTemplateObject(JSObject* obj) {
2473 46 : MOZ_ASSERT(obj->group() == templateGroup());
2474 46 : templateObject_ = obj;
2475 46 : }
2476 :
2477 55 : GCPtrObjectGroup& templateGroup() {
2478 55 : return templateGroup_;
2479 : }
2480 :
2481 0 : void setTemplateGroup(ObjectGroup* group) {
2482 0 : templateObject_ = nullptr;
2483 0 : templateGroup_ = group;
2484 0 : }
2485 : };
2486 :
2487 : // JSOP_NEWOBJECT
2488 :
2489 : class ICNewObject_Fallback : public ICFallbackStub
2490 : {
2491 : friend class ICStubSpace;
2492 :
2493 : GCPtrObject templateObject_;
2494 :
2495 214 : explicit ICNewObject_Fallback(JitCode* stubCode)
2496 214 : : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(nullptr)
2497 214 : {}
2498 :
2499 : public:
2500 214 : class Compiler : public ICStubCompiler {
2501 : MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
2502 :
2503 : public:
2504 214 : explicit Compiler(JSContext* cx, Engine engine)
2505 214 : : ICStubCompiler(cx, ICStub::NewObject_Fallback, engine)
2506 214 : {}
2507 :
2508 214 : ICStub* getStub(ICStubSpace* space) {
2509 214 : return newStub<ICNewObject_Fallback>(space, getStubCode());
2510 : }
2511 : };
2512 :
2513 928 : GCPtrObject& templateObject() {
2514 928 : return templateObject_;
2515 : }
2516 :
2517 82 : void setTemplateObject(JSObject* obj) {
2518 82 : templateObject_ = obj;
2519 82 : }
2520 : };
2521 :
2522 : class ICNewObject_WithTemplate : public ICStub
2523 : {
2524 : friend class ICStubSpace;
2525 :
2526 78 : explicit ICNewObject_WithTemplate(JitCode* stubCode)
2527 78 : : ICStub(ICStub::NewObject_WithTemplate, stubCode)
2528 78 : {}
2529 : };
2530 :
2531 : } // namespace jit
2532 : } // namespace js
2533 :
2534 : #endif /* jit_SharedIC_h */
|