js/src/jit/BaselineIC.h

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:ff5bfcea9a18
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_BaselineIC_h
8 #define jit_BaselineIC_h
9
10 #ifdef JS_ION
11
12 #include "mozilla/Assertions.h"
13
14 #include "jscntxt.h"
15 #include "jscompartment.h"
16 #include "jsgc.h"
17 #include "jsopcode.h"
18
19 #include "jit/BaselineJIT.h"
20 #include "jit/BaselineRegisters.h"
21
22 namespace js {
23 namespace jit {
24
25 //
26 // Baseline Inline Caches are polymorphic caches that aggressively
27 // share their stub code.
28 //
29 // Every polymorphic site contains a linked list of stubs which are
30 // specific to that site. These stubs are composed of a |StubData|
31 // structure that stores parametrization information (e.g.
32 // the shape pointer for a shape-check-and-property-get stub), any
33 // dynamic information (e.g. use counts), a pointer to the stub code,
34 // and a pointer to the next stub state in the linked list.
35 //
36 // Every BaselineScript keeps an table of |CacheDescriptor| data
37 // structures, which store the following:
38 // A pointer to the first StubData in the cache.
39 // The bytecode PC of the relevant IC.
40 // The machine-code PC where the call to the stubcode returns.
41 //
42 // A diagram:
43 //
44 // Control flow Pointers
45 // =======# ----. .---->
46 // # | |
47 // #======> \-----/
48 //
49 //
50 // .---------------------------------------.
51 // | .-------------------------. |
52 // | | .----. | |
53 // Baseline | | | | | |
54 // JIT Code 0 ^ 1 ^ 2 ^ | | |
55 // +--------------+ .-->+-----+ +-----+ +-----+ | | |
56 // | | #=|==>| |==>| |==>| FB | | | |
57 // | | # | +-----+ +-----+ +-----+ | | |
58 // | | # | # # # | | |
59 // |==============|==# | # # # | | |
60 // |=== IC =======| | # # # | | |
61 // .->|==============|<===|======#=========#=========# | | |
62 // | | | | | | |
63 // | | | | | | |
64 // | | | | | | |
65 // | | | | v | |
66 // | | | | +---------+ | |
67 // | | | | | Fallback| | |
68 // | | | | | Stub | | |
69 // | | | | | Code | | |
70 // | | | | +---------+ | |
71 // | +--------------+ | | |
72 // | |_______ | +---------+ | |
73 // | | | | Stub |<---/ |
74 // | IC | \--. | Code | |
75 // | Descriptor | | +---------+ |
76 // | Table v | |
77 // | +-----------------+ | +---------+ |
78 // \--| Ins | PC | Stub |----/ | Stub |<-------/
79 // +-----------------+ | Code |
80 // | ... | +---------+
81 // +-----------------+
82 // Shared
83 // Stub Code
84 //
85 //
86 // Type ICs
87 // ========
88 //
89 // Type ICs are otherwise regular ICs that are actually nested within
90 // other IC chains. They serve to optimize locations in the code where the
91 // baseline compiler would have otherwise had to perform a type Monitor operation
92 // (e.g. the result of GetProp, GetElem, etc.), or locations where the baseline
93 // compiler would have had to modify a heap typeset using the type of an input
94 // value (e.g. SetProp, SetElem, etc.)
95 //
96 // There are two kinds of Type ICs: Monitor and Update.
97 //
98 // Note that type stub bodies are no-ops. The stubs only exist for their
99 // guards, and their existence simply signifies that the typeset (implicit)
100 // that is being checked already contains that type.
101 //
102 // TypeMonitor ICs
103 // ---------------
104 // Monitor ICs are shared between stubs in the general IC, and monitor the resulting
105 // types of getter operations (call returns, getprop outputs, etc.)
106 //
107 // +-----------+ +-----------+ +-----------+ +-----------+
108 // ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub |
109 // +-----------+ +-----------+ +-----------+ +-----------+
110 // | | | |
111 // |------------------/-----------------/ |
112 // v |
113 // +-----------+ +-----------+ +-----------+ |
114 // | Type 1 |---->| Type 2 |---->| Type FB | |
115 // +-----------+ +-----------+ +-----------+ |
116 // | | | |
117 // <----------/-----------------/------------------/------------------/
118 // r e t u r n p a t h
119 //
120 // After an optimized IC stub successfully executes, it passes control to the type stub
121 // chain to check the resulting type. If no type stub succeeds, and the monitor fallback
122 // stub is reached, the monitor fallback stub performs a manual monitor, and also adds the
123 // appropriate type stub to the chain.
124 //
125 // The IC's main fallback, in addition to generating new mainline stubs, also generates
126 // type stubs as reflected by its returned value.
127 //
128 // NOTE: The type IC chain returns directly to the mainline code, not back to the
129 // stub it was entered from. Thus, entering a type IC is a matter of a |jump|, not
130 // a |call|. This allows us to safely call a VM Monitor function from within the monitor IC's
131 // fallback chain, since the return address (needed for stack inspection) is preserved.
132 //
133 //
134 // TypeUpdate ICs
135 // --------------
136 // Update ICs update heap typesets and monitor the input types of setter operations
137 // (setelem, setprop inputs, etc.). Unlike monitor ICs, they are not shared
138 // between stubs on an IC, but instead are kept track of on a per-stub basis.
139 //
140 // This is because the main stubs for the operation will each identify a potentially
141 // different TypeObject to update. New input types must be tracked on a typeobject-to-
142 // typeobject basis.
143 //
144 // Type-update ICs cannot be called in tail position (they must return to the
145 // the stub that called them so that the stub may continue to perform its original
146 // purpose). This means that any VMCall to perform a manual type update from C++ must be
147 // done from within the main IC stub. This necessitates that the stub enter a
148 // "BaselineStub" frame before making the call.
149 //
150 // If the type-update IC chain could itself make the VMCall, then the BaselineStub frame
151 // must be entered before calling the type-update chain, and exited afterward. This
152 // is very expensive for a common case where we expect the type-update fallback to not
153 // be called. To avoid the cost of entering and exiting a BaselineStub frame when
154 // using the type-update IC chain, we design the chain to not perform any VM-calls
155 // in its fallback.
156 //
157 // Instead, the type-update IC chain is responsible for returning 1 or 0, depending
158 // on if a type is represented in the chain or not. The fallback stub simply returns
159 // 0, and all other optimized stubs return 1.
160 // If the chain returns 1, then the IC stub goes ahead and performs its operation.
161 // If the chain returns 0, then the IC stub performs a call to the fallback function
162 // inline (doing the requisite BaselineStub frame enter/exit).
163 // This allows us to avoid the expensive subfram enter/exit in the common case.
164 //
165 // r e t u r n p a t h
166 // <--------------.-----------------.-----------------.-----------------.
167 // | | | |
168 // +-----------+ +-----------+ +-----------+ +-----------+
169 // ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub |
170 // +-----------+ +-----------+ +-----------+ +-----------+
171 // | ^ | ^ | ^
172 // | | | | | |
173 // | | | | | |----------------.
174 // | | | | v |1 |0
175 // | | | | +-----------+ +-----------+
176 // | | | | | Type 3.1 |--->| FB 3 |
177 // | | | | +-----------+ +-----------+
178 // | | | |
179 // | | | \-------------.-----------------.
180 // | | | | | |
181 // | | v |1 |1 |0
182 // | | +-----------+ +-----------+ +-----------+
183 // | | | Type 2.1 |---->| Type 2.2 |---->| FB 2 |
184 // | | +-----------+ +-----------+ +-----------+
185 // | |
186 // | \-------------.-----------------.
187 // | | | |
188 // v |1 |1 |0
189 // +-----------+ +-----------+ +-----------+
190 // | Type 1.1 |---->| Type 1.2 |---->| FB 1 |
191 // +-----------+ +-----------+ +-----------+
192 //
193
194 class ICStub;
195 class ICFallbackStub;
196
197 //
198 // An entry in the Baseline IC descriptor table.
199 //
200 class ICEntry
201 {
202 private:
203 // A pointer to the baseline IC stub for this instruction.
204 ICStub *firstStub_;
205
206 // Offset from the start of the JIT code where the IC
207 // load and call instructions are.
208 uint32_t returnOffset_;
209
210 // The PC of this IC's bytecode op within the JSScript.
211 uint32_t pcOffset_ : 29;
212
213 public:
214 enum Kind {
215 // A for-op IC entry.
216 Kind_Op = 0,
217
218 // A non-op IC entry.
219 Kind_NonOp,
220
221 // A fake IC entry for returning from a callVM.
222 Kind_CallVM,
223
224 // A fake IC entry for returning from DebugTrapHandler.
225 Kind_DebugTrap,
226
227 // A fake IC entry for returning from a callVM to
228 // Debug{Prologue,Epilogue}.
229 Kind_DebugPrologue,
230 Kind_DebugEpilogue
231 };
232
233 private:
234 // What this IC is for.
235 Kind kind_ : 3;
236
237 // Set the kind and asserts that it's sane.
238 void setKind(Kind kind) {
239 kind_ = kind;
240 MOZ_ASSERT(this->kind() == kind);
241 }
242
243 public:
244 ICEntry(uint32_t pcOffset, Kind kind)
245 : firstStub_(nullptr), returnOffset_(), pcOffset_(pcOffset)
246 {
247 // The offset must fit in at least 29 bits, since we shave off 3 for
248 // the Kind enum.
249 MOZ_ASSERT(pcOffset_ == pcOffset);
250 JS_STATIC_ASSERT(BaselineScript::MAX_JSSCRIPT_LENGTH < 0x1fffffffu);
251 MOZ_ASSERT(pcOffset <= BaselineScript::MAX_JSSCRIPT_LENGTH);
252 setKind(kind);
253 }
254
255 CodeOffsetLabel returnOffset() const {
256 return CodeOffsetLabel(returnOffset_);
257 }
258
259 void setReturnOffset(CodeOffsetLabel offset) {
260 JS_ASSERT(offset.offset() <= (size_t) UINT32_MAX);
261 returnOffset_ = (uint32_t) offset.offset();
262 }
263
264 void fixupReturnOffset(MacroAssembler &masm) {
265 CodeOffsetLabel offset = returnOffset();
266 offset.fixup(&masm);
267 JS_ASSERT(offset.offset() <= UINT32_MAX);
268 returnOffset_ = (uint32_t) offset.offset();
269 }
270
271 uint32_t pcOffset() const {
272 return pcOffset_;
273 }
274
275 jsbytecode *pc(JSScript *script) const {
276 return script->offsetToPC(pcOffset_);
277 }
278
279 Kind kind() const {
280 // MSVC compiles enums as signed.
281 return (Kind)(kind_ & 0x7);
282 }
283 bool isForOp() const {
284 return kind() == Kind_Op;
285 }
286
287 void setForDebugPrologue() {
288 MOZ_ASSERT(kind() == Kind_CallVM);
289 setKind(Kind_DebugPrologue);
290 }
291 void setForDebugEpilogue() {
292 MOZ_ASSERT(kind() == Kind_CallVM);
293 setKind(Kind_DebugEpilogue);
294 }
295
296 bool hasStub() const {
297 return firstStub_ != nullptr;
298 }
299 ICStub *firstStub() const {
300 JS_ASSERT(hasStub());
301 return firstStub_;
302 }
303
304 ICFallbackStub *fallbackStub() const;
305
306 void setFirstStub(ICStub *stub) {
307 firstStub_ = stub;
308 }
309
310 static inline size_t offsetOfFirstStub() {
311 return offsetof(ICEntry, firstStub_);
312 }
313
314 inline ICStub **addressOfFirstStub() {
315 return &firstStub_;
316 }
317 };
318
319 // List of baseline IC stub kinds.
320 #define IC_STUB_KIND_LIST(_) \
321 _(UseCount_Fallback) \
322 \
323 _(Profiler_Fallback) \
324 _(Profiler_PushFunction) \
325 \
326 _(TypeMonitor_Fallback) \
327 _(TypeMonitor_SingleObject) \
328 _(TypeMonitor_TypeObject) \
329 _(TypeMonitor_PrimitiveSet) \
330 \
331 _(TypeUpdate_Fallback) \
332 _(TypeUpdate_SingleObject) \
333 _(TypeUpdate_TypeObject) \
334 _(TypeUpdate_PrimitiveSet) \
335 \
336 _(This_Fallback) \
337 \
338 _(NewArray_Fallback) \
339 _(NewObject_Fallback) \
340 \
341 _(Compare_Fallback) \
342 _(Compare_Int32) \
343 _(Compare_Double) \
344 _(Compare_NumberWithUndefined) \
345 _(Compare_String) \
346 _(Compare_Boolean) \
347 _(Compare_Object) \
348 _(Compare_ObjectWithUndefined) \
349 _(Compare_Int32WithBoolean) \
350 \
351 _(ToBool_Fallback) \
352 _(ToBool_Int32) \
353 _(ToBool_String) \
354 _(ToBool_NullUndefined) \
355 _(ToBool_Double) \
356 _(ToBool_Object) \
357 \
358 _(ToNumber_Fallback) \
359 \
360 _(BinaryArith_Fallback) \
361 _(BinaryArith_Int32) \
362 _(BinaryArith_Double) \
363 _(BinaryArith_StringConcat) \
364 _(BinaryArith_StringObjectConcat) \
365 _(BinaryArith_BooleanWithInt32) \
366 _(BinaryArith_DoubleWithInt32) \
367 \
368 _(UnaryArith_Fallback) \
369 _(UnaryArith_Int32) \
370 _(UnaryArith_Double) \
371 \
372 _(Call_Fallback) \
373 _(Call_Scripted) \
374 _(Call_AnyScripted) \
375 _(Call_Native) \
376 _(Call_ScriptedApplyArray) \
377 _(Call_ScriptedApplyArguments) \
378 _(Call_ScriptedFunCall) \
379 \
380 _(GetElem_Fallback) \
381 _(GetElem_NativeSlot) \
382 _(GetElem_NativePrototypeSlot) \
383 _(GetElem_NativePrototypeCallNative) \
384 _(GetElem_NativePrototypeCallScripted) \
385 _(GetElem_String) \
386 _(GetElem_Dense) \
387 _(GetElem_TypedArray) \
388 _(GetElem_Arguments) \
389 \
390 _(SetElem_Fallback) \
391 _(SetElem_Dense) \
392 _(SetElem_DenseAdd) \
393 _(SetElem_TypedArray) \
394 \
395 _(In_Fallback) \
396 \
397 _(GetName_Fallback) \
398 _(GetName_Global) \
399 _(GetName_Scope0) \
400 _(GetName_Scope1) \
401 _(GetName_Scope2) \
402 _(GetName_Scope3) \
403 _(GetName_Scope4) \
404 _(GetName_Scope5) \
405 _(GetName_Scope6) \
406 \
407 _(BindName_Fallback) \
408 \
409 _(GetIntrinsic_Fallback) \
410 _(GetIntrinsic_Constant) \
411 \
412 _(GetProp_Fallback) \
413 _(GetProp_ArrayLength) \
414 _(GetProp_TypedArrayLength) \
415 _(GetProp_Primitive) \
416 _(GetProp_StringLength) \
417 _(GetProp_Native) \
418 _(GetProp_NativePrototype) \
419 _(GetProp_CallScripted) \
420 _(GetProp_CallNative) \
421 _(GetProp_CallNativePrototype)\
422 _(GetProp_CallDOMProxyNative)\
423 _(GetProp_CallDOMProxyWithGenerationNative)\
424 _(GetProp_DOMProxyShadowed) \
425 _(GetProp_ArgumentsLength) \
426 \
427 _(SetProp_Fallback) \
428 _(SetProp_Native) \
429 _(SetProp_NativeAdd) \
430 _(SetProp_CallScripted) \
431 _(SetProp_CallNative) \
432 \
433 _(TableSwitch) \
434 \
435 _(IteratorNew_Fallback) \
436 _(IteratorMore_Fallback) \
437 _(IteratorMore_Native) \
438 _(IteratorNext_Fallback) \
439 _(IteratorNext_Native) \
440 _(IteratorClose_Fallback) \
441 \
442 _(InstanceOf_Fallback) \
443 \
444 _(TypeOf_Fallback) \
445 _(TypeOf_Typed) \
446 \
447 _(Rest_Fallback) \
448 \
449 _(RetSub_Fallback) \
450 _(RetSub_Resume)
451
452 #define FORWARD_DECLARE_STUBS(kindName) class IC##kindName;
453 IC_STUB_KIND_LIST(FORWARD_DECLARE_STUBS)
454 #undef FORWARD_DECLARE_STUBS
455
456 class ICMonitoredStub;
457 class ICMonitoredFallbackStub;
458 class ICUpdatedStub;
459
460 // Constant iterator that traverses arbitrary chains of ICStubs.
461 // No requirements are made of the ICStub used to construct this
462 // iterator, aside from that the stub be part of a nullptr-terminated
463 // chain.
464 // The iterator is considered to be at its end once it has been
465 // incremented _past_ the last stub. Thus, if 'atEnd()' returns
466 // true, the '*' and '->' operations are not valid.
467 class ICStubConstIterator
468 {
469 friend class ICStub;
470 friend class ICFallbackStub;
471
472 private:
473 ICStub *currentStub_;
474
475 public:
476 ICStubConstIterator(ICStub *currentStub) : currentStub_(currentStub) {}
477
478 static ICStubConstIterator StartingAt(ICStub *stub) {
479 return ICStubConstIterator(stub);
480 }
481 static ICStubConstIterator End(ICStub *stub) {
482 return ICStubConstIterator(nullptr);
483 }
484
485 bool operator ==(const ICStubConstIterator &other) const {
486 return currentStub_ == other.currentStub_;
487 }
488 bool operator !=(const ICStubConstIterator &other) const {
489 return !(*this == other);
490 }
491
492 ICStubConstIterator &operator++();
493
494 ICStubConstIterator operator++(int) {
495 ICStubConstIterator oldThis(*this);
496 ++(*this);
497 return oldThis;
498 }
499
500 ICStub *operator *() const {
501 JS_ASSERT(currentStub_);
502 return currentStub_;
503 }
504
505 ICStub *operator ->() const {
506 JS_ASSERT(currentStub_);
507 return currentStub_;
508 }
509
510 bool atEnd() const {
511 return currentStub_ == nullptr;
512 }
513 };
514
515 // Iterator that traverses "regular" IC chains that start at an ICEntry
516 // and are terminated with an ICFallbackStub.
517 //
518 // The iterator is considered to be at its end once it is _at_ the
519 // fallback stub. Thus, unlike the ICStubConstIterator, operators
520 // '*' and '->' are valid even if 'atEnd()' returns true - they
521 // will act on the fallback stub.
522 //
523 // This iterator also allows unlinking of stubs being traversed.
524 // Note that 'unlink' does not implicitly advance the iterator -
525 // it must be advanced explicitly using '++'.
526 class ICStubIterator
527 {
528 friend class ICFallbackStub;
529
530 private:
531 ICEntry *icEntry_;
532 ICFallbackStub *fallbackStub_;
533 ICStub *previousStub_;
534 ICStub *currentStub_;
535 bool unlinked_;
536
537 ICStubIterator(ICFallbackStub *fallbackStub, bool end=false);
538 public:
539
540 bool operator ==(const ICStubIterator &other) const {
541 // == should only ever be called on stubs from the same chain.
542 JS_ASSERT(icEntry_ == other.icEntry_);
543 JS_ASSERT(fallbackStub_ == other.fallbackStub_);
544 return currentStub_ == other.currentStub_;
545 }
546 bool operator !=(const ICStubIterator &other) const {
547 return !(*this == other);
548 }
549
550 ICStubIterator &operator++();
551
552 ICStubIterator operator++(int) {
553 ICStubIterator oldThis(*this);
554 ++(*this);
555 return oldThis;
556 }
557
558 ICStub *operator *() const {
559 return currentStub_;
560 }
561
562 ICStub *operator ->() const {
563 return currentStub_;
564 }
565
566 bool atEnd() const {
567 return currentStub_ == (ICStub *) fallbackStub_;
568 }
569
570 void unlink(JSContext *cx);
571 };
572
573 //
574 // Base class for all IC stubs.
575 //
576 class ICStub
577 {
578 friend class ICFallbackStub;
579
580 public:
581 enum Kind {
582 INVALID = 0,
583 #define DEF_ENUM_KIND(kindName) kindName,
584 IC_STUB_KIND_LIST(DEF_ENUM_KIND)
585 #undef DEF_ENUM_KIND
586 LIMIT
587 };
588
589 static inline bool IsValidKind(Kind k) {
590 return (k > INVALID) && (k < LIMIT);
591 }
592
593 static const char *KindString(Kind k) {
594 switch(k) {
595 #define DEF_KIND_STR(kindName) case kindName: return #kindName;
596 IC_STUB_KIND_LIST(DEF_KIND_STR)
597 #undef DEF_KIND_STR
598 default:
599 MOZ_ASSUME_UNREACHABLE("Invalid kind.");
600 }
601 }
602
603 enum Trait {
604 Regular = 0x0,
605 Fallback = 0x1,
606 Monitored = 0x2,
607 MonitoredFallback = 0x3,
608 Updated = 0x4
609 };
610
611 void markCode(JSTracer *trc, const char *name);
612 void updateCode(JitCode *stubCode);
613 void trace(JSTracer *trc);
614
615 protected:
616 // The raw jitcode to call for this stub.
617 uint8_t *stubCode_;
618
619 // Pointer to next IC stub. This is null for the last IC stub, which should
620 // either be a fallback or inert IC stub.
621 ICStub *next_;
622
623 // A 16-bit field usable by subtypes of ICStub for subtype-specific small-info
624 uint16_t extra_;
625
626 // The kind of the stub.
627 // High bit is 'isFallback' flag.
628 // Second high bit is 'isMonitored' flag.
629 Trait trait_ : 3;
630 Kind kind_ : 13;
631
632 inline ICStub(Kind kind, JitCode *stubCode)
633 : stubCode_(stubCode->raw()),
634 next_(nullptr),
635 extra_(0),
636 trait_(Regular),
637 kind_(kind)
638 {
639 JS_ASSERT(stubCode != nullptr);
640 }
641
642 inline ICStub(Kind kind, Trait trait, JitCode *stubCode)
643 : stubCode_(stubCode->raw()),
644 next_(nullptr),
645 extra_(0),
646 trait_(trait),
647 kind_(kind)
648 {
649 JS_ASSERT(stubCode != nullptr);
650 }
651
652 inline Trait trait() const {
653 // Workaround for MSVC reading trait_ as signed value.
654 return (Trait)(trait_ & 0x7);
655 }
656
657 public:
658
659 inline Kind kind() const {
660 return static_cast<Kind>(kind_);
661 }
662
663 inline bool isFallback() const {
664 return trait() == Fallback || trait() == MonitoredFallback;
665 }
666
667 inline bool isMonitored() const {
668 return trait() == Monitored;
669 }
670
671 inline bool isUpdated() const {
672 return trait() == Updated;
673 }
674
675 inline bool isMonitoredFallback() const {
676 return trait() == MonitoredFallback;
677 }
678
679 inline const ICFallbackStub *toFallbackStub() const {
680 JS_ASSERT(isFallback());
681 return reinterpret_cast<const ICFallbackStub *>(this);
682 }
683
684 inline ICFallbackStub *toFallbackStub() {
685 JS_ASSERT(isFallback());
686 return reinterpret_cast<ICFallbackStub *>(this);
687 }
688
689 inline const ICMonitoredStub *toMonitoredStub() const {
690 JS_ASSERT(isMonitored());
691 return reinterpret_cast<const ICMonitoredStub *>(this);
692 }
693
694 inline ICMonitoredStub *toMonitoredStub() {
695 JS_ASSERT(isMonitored());
696 return reinterpret_cast<ICMonitoredStub *>(this);
697 }
698
699 inline const ICMonitoredFallbackStub *toMonitoredFallbackStub() const {
700 JS_ASSERT(isMonitoredFallback());
701 return reinterpret_cast<const ICMonitoredFallbackStub *>(this);
702 }
703
704 inline ICMonitoredFallbackStub *toMonitoredFallbackStub() {
705 JS_ASSERT(isMonitoredFallback());
706 return reinterpret_cast<ICMonitoredFallbackStub *>(this);
707 }
708
709 inline const ICUpdatedStub *toUpdatedStub() const {
710 JS_ASSERT(isUpdated());
711 return reinterpret_cast<const ICUpdatedStub *>(this);
712 }
713
714 inline ICUpdatedStub *toUpdatedStub() {
715 JS_ASSERT(isUpdated());
716 return reinterpret_cast<ICUpdatedStub *>(this);
717 }
718
719 #define KIND_METHODS(kindName) \
720 inline bool is##kindName() const { return kind() == kindName; } \
721 inline const IC##kindName *to##kindName() const { \
722 JS_ASSERT(is##kindName()); \
723 return reinterpret_cast<const IC##kindName *>(this); \
724 } \
725 inline IC##kindName *to##kindName() { \
726 JS_ASSERT(is##kindName()); \
727 return reinterpret_cast<IC##kindName *>(this); \
728 }
729 IC_STUB_KIND_LIST(KIND_METHODS)
730 #undef KIND_METHODS
731
732 inline ICStub *next() const {
733 return next_;
734 }
735
736 inline bool hasNext() const {
737 return next_ != nullptr;
738 }
739
740 inline void setNext(ICStub *stub) {
741 // Note: next_ only needs to be changed under the compilation lock for
742 // non-type-monitor/update ICs.
743 next_ = stub;
744 }
745
746 inline ICStub **addressOfNext() {
747 return &next_;
748 }
749
750 inline JitCode *jitCode() {
751 return JitCode::FromExecutable(stubCode_);
752 }
753
754 inline uint8_t *rawStubCode() const {
755 return stubCode_;
756 }
757
758 // This method is not valid on TypeUpdate stub chains!
759 inline ICFallbackStub *getChainFallback() {
760 ICStub *lastStub = this;
761 while (lastStub->next_)
762 lastStub = lastStub->next_;
763 JS_ASSERT(lastStub->isFallback());
764 return lastStub->toFallbackStub();
765 }
766
767 inline ICStubConstIterator beginHere() {
768 return ICStubConstIterator::StartingAt(this);
769 }
770
771 static inline size_t offsetOfNext() {
772 return offsetof(ICStub, next_);
773 }
774
775 static inline size_t offsetOfStubCode() {
776 return offsetof(ICStub, stubCode_);
777 }
778
779 static inline size_t offsetOfExtra() {
780 return offsetof(ICStub, extra_);
781 }
782
783 static bool CanMakeCalls(ICStub::Kind kind) {
784 JS_ASSERT(IsValidKind(kind));
785 switch (kind) {
786 case Call_Fallback:
787 case Call_Scripted:
788 case Call_AnyScripted:
789 case Call_Native:
790 case Call_ScriptedApplyArray:
791 case Call_ScriptedApplyArguments:
792 case Call_ScriptedFunCall:
793 case UseCount_Fallback:
794 case GetElem_NativeSlot:
795 case GetElem_NativePrototypeSlot:
796 case GetElem_NativePrototypeCallNative:
797 case GetElem_NativePrototypeCallScripted:
798 case GetProp_CallScripted:
799 case GetProp_CallNative:
800 case GetProp_CallNativePrototype:
801 case GetProp_CallDOMProxyNative:
802 case GetProp_CallDOMProxyWithGenerationNative:
803 case GetProp_DOMProxyShadowed:
804 case SetProp_CallScripted:
805 case SetProp_CallNative:
806 case RetSub_Fallback:
807 // These two fallback stubs don't actually make non-tail calls,
808 // but the fallback code for the bailout path needs to pop the stub frame
809 // pushed during the bailout.
810 case GetProp_Fallback:
811 case SetProp_Fallback:
812 #if JS_HAS_NO_SUCH_METHOD
813 case GetElem_Dense:
814 case GetElem_Arguments:
815 case GetProp_NativePrototype:
816 case GetProp_Native:
817 #endif
818 return true;
819 default:
820 return false;
821 }
822 }
823
824 // Optimized stubs get purged on GC. But some stubs can be active on the
825 // stack during GC - specifically the ones that can make calls. To ensure
826 // that these do not get purged, all stubs that can make calls are allocated
827 // in the fallback stub space.
828 bool allocatedInFallbackSpace() const {
829 JS_ASSERT(next());
830 return CanMakeCalls(kind());
831 }
832 };
833
834 class ICFallbackStub : public ICStub
835 {
836 friend class ICStubConstIterator;
837 protected:
838 // Fallback stubs need these fields to easily add new stubs to
839 // the linked list of stubs for an IC.
840
841 // The IC entry for this linked list of stubs.
842 ICEntry *icEntry_;
843
844 // The number of stubs kept in the IC entry.
845 uint32_t numOptimizedStubs_;
846
847 // A pointer to the location stub pointer that needs to be
848 // changed to add a new "last" stub immediately before the fallback
849 // stub. This'll start out pointing to the icEntry's "firstStub_"
850 // field, and as new stubs are addd, it'll point to the current
851 // last stub's "next_" field.
852 ICStub **lastStubPtrAddr_;
853
854 ICFallbackStub(Kind kind, JitCode *stubCode)
855 : ICStub(kind, ICStub::Fallback, stubCode),
856 icEntry_(nullptr),
857 numOptimizedStubs_(0),
858 lastStubPtrAddr_(nullptr) {}
859
860 ICFallbackStub(Kind kind, Trait trait, JitCode *stubCode)
861 : ICStub(kind, trait, stubCode),
862 icEntry_(nullptr),
863 numOptimizedStubs_(0),
864 lastStubPtrAddr_(nullptr)
865 {
866 JS_ASSERT(trait == ICStub::Fallback ||
867 trait == ICStub::MonitoredFallback);
868 }
869
870 public:
871 inline ICEntry *icEntry() const {
872 return icEntry_;
873 }
874
875 inline size_t numOptimizedStubs() const {
876 return (size_t) numOptimizedStubs_;
877 }
878
879 // The icEntry and lastStubPtrAddr_ fields can't be initialized when the stub is
880 // created since the stub is created at compile time, and we won't know the IC entry
881 // address until after compile when the BaselineScript is created. This method
882 // allows these fields to be fixed up at that point.
883 void fixupICEntry(ICEntry *icEntry) {
884 JS_ASSERT(icEntry_ == nullptr);
885 JS_ASSERT(lastStubPtrAddr_ == nullptr);
886 icEntry_ = icEntry;
887 lastStubPtrAddr_ = icEntry_->addressOfFirstStub();
888 }
889
890 // Add a new stub to the IC chain terminated by this fallback stub.
891 void addNewStub(ICStub *stub) {
892 JS_ASSERT(*lastStubPtrAddr_ == this);
893 JS_ASSERT(stub->next() == nullptr);
894 stub->setNext(this);
895 *lastStubPtrAddr_ = stub;
896 lastStubPtrAddr_ = stub->addressOfNext();
897 numOptimizedStubs_++;
898 }
899
900 ICStubConstIterator beginChainConst() const {
901 return ICStubConstIterator(icEntry_->firstStub());
902 }
903
904 ICStubIterator beginChain() {
905 return ICStubIterator(this);
906 }
907
908 bool hasStub(ICStub::Kind kind) const {
909 for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) {
910 if (iter->kind() == kind)
911 return true;
912 }
913 return false;
914 }
915
916 unsigned numStubsWithKind(ICStub::Kind kind) const {
917 unsigned count = 0;
918 for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) {
919 if (iter->kind() == kind)
920 count++;
921 }
922 return count;
923 }
924
925 void unlinkStub(Zone *zone, ICStub *prev, ICStub *stub);
926 void unlinkStubsWithKind(JSContext *cx, ICStub::Kind kind);
927 };
928
929 // Monitored stubs are IC stubs that feed a single resulting value out to a
930 // type monitor operation.
931 class ICMonitoredStub : public ICStub
932 {
933 protected:
934 // Pointer to the start of the type monitoring stub chain.
935 ICStub *firstMonitorStub_;
936
937 ICMonitoredStub(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub);
938
939 public:
940 inline void updateFirstMonitorStub(ICStub *monitorStub) {
941 // This should only be called once: when the first optimized monitor stub
942 // is added to the type monitor IC chain.
943 JS_ASSERT(firstMonitorStub_ && firstMonitorStub_->isTypeMonitor_Fallback());
944 firstMonitorStub_ = monitorStub;
945 }
946 inline void resetFirstMonitorStub(ICStub *monitorFallback) {
947 JS_ASSERT(monitorFallback->isTypeMonitor_Fallback());
948 firstMonitorStub_ = monitorFallback;
949 }
950 inline ICStub *firstMonitorStub() const {
951 return firstMonitorStub_;
952 }
953
954 static inline size_t offsetOfFirstMonitorStub() {
955 return offsetof(ICMonitoredStub, firstMonitorStub_);
956 }
957 };
958
959 // Monitored fallback stubs - as the name implies.
960 class ICMonitoredFallbackStub : public ICFallbackStub
961 {
962 protected:
963 // Pointer to the fallback monitor stub.
964 ICTypeMonitor_Fallback *fallbackMonitorStub_;
965
966 ICMonitoredFallbackStub(Kind kind, JitCode *stubCode)
967 : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode),
968 fallbackMonitorStub_(nullptr) {}
969
970 public:
971 bool initMonitoringChain(JSContext *cx, ICStubSpace *space);
972 bool addMonitorStubForValue(JSContext *cx, JSScript *script, HandleValue val);
973
974 inline ICTypeMonitor_Fallback *fallbackMonitorStub() const {
975 return fallbackMonitorStub_;
976 }
977
978 static inline size_t offsetOfFallbackMonitorStub() {
979 return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_);
980 }
981 };
982
983 // Updated stubs are IC stubs that use a TypeUpdate IC to track
984 // the status of heap typesets that need to be updated.
985 class ICUpdatedStub : public ICStub
986 {
987 protected:
988 // Pointer to the start of the type updating stub chain.
989 ICStub *firstUpdateStub_;
990
991 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
992 uint32_t numOptimizedStubs_;
993
994 ICUpdatedStub(Kind kind, JitCode *stubCode)
995 : ICStub(kind, ICStub::Updated, stubCode),
996 firstUpdateStub_(nullptr),
997 numOptimizedStubs_(0)
998 {}
999
1000 public:
1001 bool initUpdatingChain(JSContext *cx, ICStubSpace *space);
1002
1003 bool addUpdateStubForValue(JSContext *cx, HandleScript script, HandleObject obj, HandleId id,
1004 HandleValue val);
1005
1006 void addOptimizedUpdateStub(ICStub *stub) {
1007 if (firstUpdateStub_->isTypeUpdate_Fallback()) {
1008 stub->setNext(firstUpdateStub_);
1009 firstUpdateStub_ = stub;
1010 } else {
1011 ICStub *iter = firstUpdateStub_;
1012 JS_ASSERT(iter->next() != nullptr);
1013 while (!iter->next()->isTypeUpdate_Fallback())
1014 iter = iter->next();
1015 JS_ASSERT(iter->next()->next() == nullptr);
1016 stub->setNext(iter->next());
1017 iter->setNext(stub);
1018 }
1019
1020 numOptimizedStubs_++;
1021 }
1022
1023 inline ICStub *firstUpdateStub() const {
1024 return firstUpdateStub_;
1025 }
1026
1027 bool hasTypeUpdateStub(ICStub::Kind kind) {
1028 ICStub *stub = firstUpdateStub_;
1029 do {
1030 if (stub->kind() == kind)
1031 return true;
1032
1033 stub = stub->next();
1034 } while (stub);
1035
1036 return false;
1037 }
1038
1039 inline uint32_t numOptimizedStubs() const {
1040 return numOptimizedStubs_;
1041 }
1042
1043 static inline size_t offsetOfFirstUpdateStub() {
1044 return offsetof(ICUpdatedStub, firstUpdateStub_);
1045 }
1046 };
1047
1048 // Base class for stubcode compilers.
1049 class ICStubCompiler
1050 {
1051 // Prevent GC in the middle of stub compilation.
1052 js::gc::AutoSuppressGC suppressGC;
1053
1054
1055 protected:
1056 JSContext *cx;
1057 ICStub::Kind kind;
1058 #ifdef DEBUG
1059 bool entersStubFrame_;
1060 #endif
1061
1062 // By default the stubcode key is just the kind.
1063 virtual int32_t getKey() const {
1064 return static_cast<int32_t>(kind);
1065 }
1066
1067 virtual bool generateStubCode(MacroAssembler &masm) = 0;
1068 virtual bool postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> genCode) {
1069 return true;
1070 }
1071 JitCode *getStubCode();
1072
1073 ICStubCompiler(JSContext *cx, ICStub::Kind kind)
1074 : suppressGC(cx), cx(cx), kind(kind)
1075 #ifdef DEBUG
1076 , entersStubFrame_(false)
1077 #endif
1078 {}
1079
1080 // Emits a tail call to a VMFunction wrapper.
1081 bool tailCallVM(const VMFunction &fun, MacroAssembler &masm);
1082
1083 // Emits a normal (non-tail) call to a VMFunction wrapper.
1084 bool callVM(const VMFunction &fun, MacroAssembler &masm);
1085
1086 // Emits a call to a type-update IC, assuming that the value to be
1087 // checked is already in R0.
1088 bool callTypeUpdateIC(MacroAssembler &masm, uint32_t objectOffset);
1089
1090 // A stub frame is used when a stub wants to call into the VM without
1091 // performing a tail call. This is required for the return address
1092 // to pc mapping to work.
1093 void enterStubFrame(MacroAssembler &masm, Register scratch);
1094 void leaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false);
1095 void leaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false);
1096 void leaveStubFrameCommonTail(MacroAssembler &masm);
1097
1098 // Some stubs need to emit SPS profiler updates. This emits the guarding
1099 // jitcode for those stubs. If profiling is not enabled, jumps to the
1100 // given label.
1101 void guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip);
1102
1103 // Higher-level helper to emit an update to the profiler pseudo-stack.
1104 void emitProfilingUpdate(MacroAssembler &masm, Register pcIdx, Register scratch,
1105 uint32_t stubPcOffset);
1106 void emitProfilingUpdate(MacroAssembler &masm, GeneralRegisterSet regs, uint32_t stubPcOffset);
1107
1108 inline GeneralRegisterSet availableGeneralRegs(size_t numInputs) const {
1109 GeneralRegisterSet regs(GeneralRegisterSet::All());
1110 JS_ASSERT(!regs.has(BaselineStackReg));
1111 #if defined(JS_CODEGEN_ARM)
1112 JS_ASSERT(!regs.has(BaselineTailCallReg));
1113 regs.take(BaselineSecondScratchReg);
1114 #elif defined(JS_CODEGEN_MIPS)
1115 JS_ASSERT(!regs.has(BaselineTailCallReg));
1116 JS_ASSERT(!regs.has(BaselineSecondScratchReg));
1117 #endif
1118 regs.take(BaselineFrameReg);
1119 regs.take(BaselineStubReg);
1120 #ifdef JS_CODEGEN_X64
1121 regs.take(ExtractTemp0);
1122 regs.take(ExtractTemp1);
1123 #endif
1124
1125 switch (numInputs) {
1126 case 0:
1127 break;
1128 case 1:
1129 regs.take(R0);
1130 break;
1131 case 2:
1132 regs.take(R0);
1133 regs.take(R1);
1134 break;
1135 default:
1136 MOZ_ASSUME_UNREACHABLE("Invalid numInputs");
1137 }
1138
1139 return regs;
1140 }
1141
1142 #ifdef JSGC_GENERATIONAL
1143 inline bool emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
1144 Register scratch, GeneralRegisterSet saveRegs);
1145 #endif
1146
1147 public:
1148 virtual ICStub *getStub(ICStubSpace *space) = 0;
1149
1150 ICStubSpace *getStubSpace(JSScript *script) {
1151 if (ICStub::CanMakeCalls(kind))
1152 return script->baselineScript()->fallbackStubSpace();
1153 return script->zone()->jitZone()->optimizedStubSpace();
1154 }
1155 };
1156
1157 // Base class for stub compilers that can generate multiple stubcodes.
1158 // These compilers need access to the JSOp they are compiling for.
1159 class ICMultiStubCompiler : public ICStubCompiler
1160 {
1161 protected:
1162 JSOp op;
1163
1164 // Stub keys for multi-stub kinds are composed of both the kind
1165 // and the op they are compiled for.
1166 virtual int32_t getKey() const {
1167 return static_cast<int32_t>(kind) | (static_cast<int32_t>(op) << 16);
1168 }
1169
1170 ICMultiStubCompiler(JSContext *cx, ICStub::Kind kind, JSOp op)
1171 : ICStubCompiler(cx, kind), op(op) {}
1172 };
1173
1174 // UseCount_Fallback
1175
1176 // A UseCount IC chain has only the fallback stub.
1177 class ICUseCount_Fallback : public ICFallbackStub
1178 {
1179 friend class ICStubSpace;
1180
1181 ICUseCount_Fallback(JitCode *stubCode)
1182 : ICFallbackStub(ICStub::UseCount_Fallback, stubCode)
1183 { }
1184
1185 public:
1186 static inline ICUseCount_Fallback *New(ICStubSpace *space, JitCode *code) {
1187 if (!code)
1188 return nullptr;
1189 return space->allocate<ICUseCount_Fallback>(code);
1190 }
1191
1192 // Compiler for this stub kind.
1193 class Compiler : public ICStubCompiler {
1194 protected:
1195 bool generateStubCode(MacroAssembler &masm);
1196
1197 public:
1198 Compiler(JSContext *cx)
1199 : ICStubCompiler(cx, ICStub::UseCount_Fallback)
1200 { }
1201
1202 ICUseCount_Fallback *getStub(ICStubSpace *space) {
1203 return ICUseCount_Fallback::New(space, getStubCode());
1204 }
1205 };
1206 };
1207
1208 // Profiler_Fallback
1209
1210 class ICProfiler_Fallback : public ICFallbackStub
1211 {
1212 friend class ICStubSpace;
1213
1214 ICProfiler_Fallback(JitCode *stubCode)
1215 : ICFallbackStub(ICStub::Profiler_Fallback, stubCode)
1216 { }
1217
1218 public:
1219 static inline ICProfiler_Fallback *New(ICStubSpace *space, JitCode *code) {
1220 if (!code)
1221 return nullptr;
1222 return space->allocate<ICProfiler_Fallback>(code);
1223 }
1224
1225 // Compiler for this stub kind.
1226 class Compiler : public ICStubCompiler {
1227 protected:
1228 bool generateStubCode(MacroAssembler &masm);
1229
1230 public:
1231 Compiler(JSContext *cx)
1232 : ICStubCompiler(cx, ICStub::Profiler_Fallback)
1233 { }
1234
1235 ICProfiler_Fallback *getStub(ICStubSpace *space) {
1236 return ICProfiler_Fallback::New(space, getStubCode());
1237 }
1238 };
1239 };
1240
1241 // Profiler_PushFunction
1242
1243 class ICProfiler_PushFunction : public ICStub
1244 {
1245 friend class ICStubSpace;
1246
1247 protected:
1248 const char *str_;
1249 HeapPtrScript script_;
1250
1251 ICProfiler_PushFunction(JitCode *stubCode, const char *str, HandleScript script);
1252
1253 public:
1254 static inline ICProfiler_PushFunction *New(ICStubSpace *space, JitCode *code,
1255 const char *str, HandleScript script)
1256 {
1257 if (!code)
1258 return nullptr;
1259 return space->allocate<ICProfiler_PushFunction>(code, str, script);
1260 }
1261
1262 HeapPtrScript &script() {
1263 return script_;
1264 }
1265
1266 static size_t offsetOfStr() {
1267 return offsetof(ICProfiler_PushFunction, str_);
1268 }
1269 static size_t offsetOfScript() {
1270 return offsetof(ICProfiler_PushFunction, script_);
1271 }
1272
1273 // Compiler for this stub kind.
1274 class Compiler : public ICStubCompiler {
1275 protected:
1276 const char *str_;
1277 RootedScript script_;
1278 bool generateStubCode(MacroAssembler &masm);
1279
1280 public:
1281 Compiler(JSContext *cx, const char *str, HandleScript script)
1282 : ICStubCompiler(cx, ICStub::Profiler_PushFunction),
1283 str_(str),
1284 script_(cx, script)
1285 { }
1286
1287 ICProfiler_PushFunction *getStub(ICStubSpace *space) {
1288 return ICProfiler_PushFunction::New(space, getStubCode(), str_, script_);
1289 }
1290 };
1291 };
1292
1293
1294 // TypeCheckPrimitiveSetStub
1295 // Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given
1296 // value's type falls within a set of primitive types.
1297
1298 class TypeCheckPrimitiveSetStub : public ICStub
1299 {
1300 friend class ICStubSpace;
1301 protected:
1302 inline static uint16_t TypeToFlag(JSValueType type) {
1303 return 1u << static_cast<unsigned>(type);
1304 }
1305
1306 inline static uint16_t ValidFlags() {
1307 return ((TypeToFlag(JSVAL_TYPE_OBJECT) << 1) - 1) & ~TypeToFlag(JSVAL_TYPE_MAGIC);
1308 }
1309
1310 TypeCheckPrimitiveSetStub(Kind kind, JitCode *stubCode, uint16_t flags)
1311 : ICStub(kind, stubCode)
1312 {
1313 JS_ASSERT(kind == TypeMonitor_PrimitiveSet || kind == TypeUpdate_PrimitiveSet);
1314 JS_ASSERT(flags && !(flags & ~ValidFlags()));
1315 extra_ = flags;
1316 }
1317
1318 TypeCheckPrimitiveSetStub *updateTypesAndCode(uint16_t flags, JitCode *code) {
1319 JS_ASSERT(flags && !(flags & ~ValidFlags()));
1320 if (!code)
1321 return nullptr;
1322 extra_ = flags;
1323 updateCode(code);
1324 return this;
1325 }
1326
1327 public:
1328 uint16_t typeFlags() const {
1329 return extra_;
1330 }
1331
1332 bool containsType(JSValueType type) const {
1333 JS_ASSERT(type <= JSVAL_TYPE_OBJECT);
1334 JS_ASSERT(type != JSVAL_TYPE_MAGIC);
1335 return extra_ & TypeToFlag(type);
1336 }
1337
1338 ICTypeMonitor_PrimitiveSet *toMonitorStub() {
1339 return toTypeMonitor_PrimitiveSet();
1340 }
1341
1342 ICTypeUpdate_PrimitiveSet *toUpdateStub() {
1343 return toTypeUpdate_PrimitiveSet();
1344 }
1345
1346 class Compiler : public ICStubCompiler {
1347 protected:
1348 TypeCheckPrimitiveSetStub *existingStub_;
1349 uint16_t flags_;
1350
1351 virtual int32_t getKey() const {
1352 return static_cast<int32_t>(kind) | (static_cast<int32_t>(flags_) << 16);
1353 }
1354
1355 public:
1356 Compiler(JSContext *cx, Kind kind, TypeCheckPrimitiveSetStub *existingStub,
1357 JSValueType type)
1358 : ICStubCompiler(cx, kind),
1359 existingStub_(existingStub),
1360 flags_((existingStub ? existingStub->typeFlags() : 0) | TypeToFlag(type))
1361 {
1362 JS_ASSERT_IF(existingStub_, flags_ != existingStub_->typeFlags());
1363 }
1364
1365 TypeCheckPrimitiveSetStub *updateStub() {
1366 JS_ASSERT(existingStub_);
1367 return existingStub_->updateTypesAndCode(flags_, getStubCode());
1368 }
1369 };
1370 };
1371
1372 // TypeMonitor
1373
1374 // The TypeMonitor fallback stub is not always a regular fallback stub. When
1375 // used for monitoring the values pushed by a bytecode it doesn't hold a
1376 // pointer to the IC entry, but rather back to the main fallback stub for the
1377 // IC (from which a pointer to the IC entry can be retrieved). When monitoring
1378 // the types of 'this', arguments or other values with no associated IC, there
1379 // is no main fallback stub, and the IC entry is referenced directly.
1380 class ICTypeMonitor_Fallback : public ICStub
1381 {
1382 friend class ICStubSpace;
1383
1384 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
1385
1386 // Pointer to the main fallback stub for the IC or to the main IC entry,
1387 // depending on hasFallbackStub.
1388 union {
1389 ICMonitoredFallbackStub *mainFallbackStub_;
1390 ICEntry *icEntry_;
1391 };
1392
1393 // Pointer to the first monitor stub.
1394 ICStub *firstMonitorStub_;
1395
1396 // Address of the last monitor stub's field pointing to this
1397 // fallback monitor stub. This will get updated when new
1398 // monitor stubs are created and added.
1399 ICStub **lastMonitorStubPtrAddr_;
1400
1401 // Count of optimized type monitor stubs in this chain.
1402 uint32_t numOptimizedMonitorStubs_ : 8;
1403
1404 // Whether this has a fallback stub referring to the IC entry.
1405 bool hasFallbackStub_ : 1;
1406
1407 // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX
1408 // if this is monitoring the types of values pushed at some bytecode.
1409 uint32_t argumentIndex_ : 23;
1410
1411 static const uint32_t BYTECODE_INDEX = (1 << 23) - 1;
1412
1413 ICTypeMonitor_Fallback(JitCode *stubCode, ICMonitoredFallbackStub *mainFallbackStub,
1414 uint32_t argumentIndex)
1415 : ICStub(ICStub::TypeMonitor_Fallback, stubCode),
1416 mainFallbackStub_(mainFallbackStub),
1417 firstMonitorStub_(thisFromCtor()),
1418 lastMonitorStubPtrAddr_(nullptr),
1419 numOptimizedMonitorStubs_(0),
1420 hasFallbackStub_(mainFallbackStub != nullptr),
1421 argumentIndex_(argumentIndex)
1422 { }
1423
1424 ICTypeMonitor_Fallback *thisFromCtor() {
1425 return this;
1426 }
1427
1428 void addOptimizedMonitorStub(ICStub *stub) {
1429 stub->setNext(this);
1430
1431 JS_ASSERT((lastMonitorStubPtrAddr_ != nullptr) ==
1432 (numOptimizedMonitorStubs_ || !hasFallbackStub_));
1433
1434 if (lastMonitorStubPtrAddr_)
1435 *lastMonitorStubPtrAddr_ = stub;
1436
1437 if (numOptimizedMonitorStubs_ == 0) {
1438 JS_ASSERT(firstMonitorStub_ == this);
1439 firstMonitorStub_ = stub;
1440 } else {
1441 JS_ASSERT(firstMonitorStub_ != nullptr);
1442 }
1443
1444 lastMonitorStubPtrAddr_ = stub->addressOfNext();
1445 numOptimizedMonitorStubs_++;
1446 }
1447
1448 public:
1449 static inline ICTypeMonitor_Fallback *New(
1450 ICStubSpace *space, JitCode *code, ICMonitoredFallbackStub *mainFbStub,
1451 uint32_t argumentIndex)
1452 {
1453 if (!code)
1454 return nullptr;
1455 return space->allocate<ICTypeMonitor_Fallback>(code, mainFbStub, argumentIndex);
1456 }
1457
1458 bool hasStub(ICStub::Kind kind) {
1459 ICStub *stub = firstMonitorStub_;
1460 do {
1461 if (stub->kind() == kind)
1462 return true;
1463
1464 stub = stub->next();
1465 } while (stub);
1466
1467 return false;
1468 }
1469
1470 inline ICFallbackStub *mainFallbackStub() const {
1471 JS_ASSERT(hasFallbackStub_);
1472 return mainFallbackStub_;
1473 }
1474
1475 inline ICEntry *icEntry() const {
1476 return hasFallbackStub_ ? mainFallbackStub()->icEntry() : icEntry_;
1477 }
1478
1479 inline ICStub *firstMonitorStub() const {
1480 return firstMonitorStub_;
1481 }
1482
1483 static inline size_t offsetOfFirstMonitorStub() {
1484 return offsetof(ICTypeMonitor_Fallback, firstMonitorStub_);
1485 }
1486
1487 inline uint32_t numOptimizedMonitorStubs() const {
1488 return numOptimizedMonitorStubs_;
1489 }
1490
1491 inline bool monitorsThis() const {
1492 return argumentIndex_ == 0;
1493 }
1494
1495 inline bool monitorsArgument(uint32_t *pargument) const {
1496 if (argumentIndex_ > 0 && argumentIndex_ < BYTECODE_INDEX) {
1497 *pargument = argumentIndex_ - 1;
1498 return true;
1499 }
1500 return false;
1501 }
1502
1503 inline bool monitorsBytecode() const {
1504 return argumentIndex_ == BYTECODE_INDEX;
1505 }
1506
1507 // Fixup the IC entry as for a normal fallback stub, for this/arguments.
1508 void fixupICEntry(ICEntry *icEntry) {
1509 JS_ASSERT(!hasFallbackStub_);
1510 JS_ASSERT(icEntry_ == nullptr);
1511 JS_ASSERT(lastMonitorStubPtrAddr_ == nullptr);
1512 icEntry_ = icEntry;
1513 lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
1514 }
1515
1516 // Create a new monitor stub for the type of the given value, and
1517 // add it to this chain.
1518 bool addMonitorStubForValue(JSContext *cx, JSScript *script, HandleValue val);
1519
1520 void resetMonitorStubChain(Zone *zone);
1521
1522 // Compiler for this stub kind.
1523 class Compiler : public ICStubCompiler {
1524 ICMonitoredFallbackStub *mainFallbackStub_;
1525 uint32_t argumentIndex_;
1526
1527 protected:
1528 bool generateStubCode(MacroAssembler &masm);
1529
1530 public:
1531 Compiler(JSContext *cx, ICMonitoredFallbackStub *mainFallbackStub)
1532 : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
1533 mainFallbackStub_(mainFallbackStub),
1534 argumentIndex_(BYTECODE_INDEX)
1535 { }
1536
1537 Compiler(JSContext *cx, uint32_t argumentIndex)
1538 : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback),
1539 mainFallbackStub_(nullptr),
1540 argumentIndex_(argumentIndex)
1541 { }
1542
1543 ICTypeMonitor_Fallback *getStub(ICStubSpace *space) {
1544 return ICTypeMonitor_Fallback::New(space, getStubCode(), mainFallbackStub_,
1545 argumentIndex_);
1546 }
1547 };
1548 };
1549
1550 class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub
1551 {
1552 friend class ICStubSpace;
1553
1554 ICTypeMonitor_PrimitiveSet(JitCode *stubCode, uint16_t flags)
1555 : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags)
1556 {}
1557
1558 public:
1559 static inline ICTypeMonitor_PrimitiveSet *New(ICStubSpace *space, JitCode *code,
1560 uint16_t flags)
1561 {
1562 if (!code)
1563 return nullptr;
1564 return space->allocate<ICTypeMonitor_PrimitiveSet>(code, flags);
1565 }
1566
1567 class Compiler : public TypeCheckPrimitiveSetStub::Compiler {
1568 protected:
1569 bool generateStubCode(MacroAssembler &masm);
1570
1571 public:
1572 Compiler(JSContext *cx, ICTypeMonitor_PrimitiveSet *existingStub, JSValueType type)
1573 : TypeCheckPrimitiveSetStub::Compiler(cx, TypeMonitor_PrimitiveSet, existingStub, type)
1574 {}
1575
1576 ICTypeMonitor_PrimitiveSet *updateStub() {
1577 TypeCheckPrimitiveSetStub *stub =
1578 this->TypeCheckPrimitiveSetStub::Compiler::updateStub();
1579 if (!stub)
1580 return nullptr;
1581 return stub->toMonitorStub();
1582 }
1583
1584 ICTypeMonitor_PrimitiveSet *getStub(ICStubSpace *space) {
1585 JS_ASSERT(!existingStub_);
1586 return ICTypeMonitor_PrimitiveSet::New(space, getStubCode(), flags_);
1587 }
1588 };
1589 };
1590
1591 class ICTypeMonitor_SingleObject : public ICStub
1592 {
1593 friend class ICStubSpace;
1594
1595 HeapPtrObject obj_;
1596
1597 ICTypeMonitor_SingleObject(JitCode *stubCode, HandleObject obj);
1598
1599 public:
1600 static inline ICTypeMonitor_SingleObject *New(
1601 ICStubSpace *space, JitCode *code, HandleObject obj)
1602 {
1603 if (!code)
1604 return nullptr;
1605 return space->allocate<ICTypeMonitor_SingleObject>(code, obj);
1606 }
1607
1608 HeapPtrObject &object() {
1609 return obj_;
1610 }
1611
1612 static size_t offsetOfObject() {
1613 return offsetof(ICTypeMonitor_SingleObject, obj_);
1614 }
1615
1616 class Compiler : public ICStubCompiler {
1617 protected:
1618 HandleObject obj_;
1619 bool generateStubCode(MacroAssembler &masm);
1620
1621 public:
1622 Compiler(JSContext *cx, HandleObject obj)
1623 : ICStubCompiler(cx, TypeMonitor_SingleObject),
1624 obj_(obj)
1625 { }
1626
1627 ICTypeMonitor_SingleObject *getStub(ICStubSpace *space) {
1628 return ICTypeMonitor_SingleObject::New(space, getStubCode(), obj_);
1629 }
1630 };
1631 };
1632
1633 class ICTypeMonitor_TypeObject : public ICStub
1634 {
1635 friend class ICStubSpace;
1636
1637 HeapPtrTypeObject type_;
1638
1639 ICTypeMonitor_TypeObject(JitCode *stubCode, HandleTypeObject type);
1640
1641 public:
1642 static inline ICTypeMonitor_TypeObject *New(
1643 ICStubSpace *space, JitCode *code, HandleTypeObject type)
1644 {
1645 if (!code)
1646 return nullptr;
1647 return space->allocate<ICTypeMonitor_TypeObject>(code, type);
1648 }
1649
1650 HeapPtrTypeObject &type() {
1651 return type_;
1652 }
1653
1654 static size_t offsetOfType() {
1655 return offsetof(ICTypeMonitor_TypeObject, type_);
1656 }
1657
1658 class Compiler : public ICStubCompiler {
1659 protected:
1660 HandleTypeObject type_;
1661 bool generateStubCode(MacroAssembler &masm);
1662
1663 public:
1664 Compiler(JSContext *cx, HandleTypeObject type)
1665 : ICStubCompiler(cx, TypeMonitor_TypeObject),
1666 type_(type)
1667 { }
1668
1669 ICTypeMonitor_TypeObject *getStub(ICStubSpace *space) {
1670 return ICTypeMonitor_TypeObject::New(space, getStubCode(), type_);
1671 }
1672 };
1673 };
1674
1675 // TypeUpdate
1676
1677 extern const VMFunction DoTypeUpdateFallbackInfo;
1678
1679 // The TypeUpdate fallback is not a regular fallback, since it just
1680 // forwards to a different entry point in the main fallback stub.
1681 class ICTypeUpdate_Fallback : public ICStub
1682 {
1683 friend class ICStubSpace;
1684
1685 ICTypeUpdate_Fallback(JitCode *stubCode)
1686 : ICStub(ICStub::TypeUpdate_Fallback, stubCode)
1687 {}
1688
1689 public:
1690 static inline ICTypeUpdate_Fallback *New(ICStubSpace *space, JitCode *code) {
1691 if (!code)
1692 return nullptr;
1693 return space->allocate<ICTypeUpdate_Fallback>(code);
1694 }
1695
1696 // Compiler for this stub kind.
1697 class Compiler : public ICStubCompiler {
1698 protected:
1699 bool generateStubCode(MacroAssembler &masm);
1700
1701 public:
1702 Compiler(JSContext *cx)
1703 : ICStubCompiler(cx, ICStub::TypeUpdate_Fallback)
1704 { }
1705
1706 ICTypeUpdate_Fallback *getStub(ICStubSpace *space) {
1707 return ICTypeUpdate_Fallback::New(space, getStubCode());
1708 }
1709 };
1710 };
1711
1712 class ICTypeUpdate_PrimitiveSet : public TypeCheckPrimitiveSetStub
1713 {
1714 friend class ICStubSpace;
1715
1716 ICTypeUpdate_PrimitiveSet(JitCode *stubCode, uint16_t flags)
1717 : TypeCheckPrimitiveSetStub(TypeUpdate_PrimitiveSet, stubCode, flags)
1718 {}
1719
1720 public:
1721 static inline ICTypeUpdate_PrimitiveSet *New(ICStubSpace *space, JitCode *code,
1722 uint16_t flags)
1723 {
1724 if (!code)
1725 return nullptr;
1726 return space->allocate<ICTypeUpdate_PrimitiveSet>(code, flags);
1727 }
1728
1729 class Compiler : public TypeCheckPrimitiveSetStub::Compiler {
1730 protected:
1731 bool generateStubCode(MacroAssembler &masm);
1732
1733 public:
1734 Compiler(JSContext *cx, ICTypeUpdate_PrimitiveSet *existingStub, JSValueType type)
1735 : TypeCheckPrimitiveSetStub::Compiler(cx, TypeUpdate_PrimitiveSet, existingStub, type)
1736 {}
1737
1738 ICTypeUpdate_PrimitiveSet *updateStub() {
1739 TypeCheckPrimitiveSetStub *stub =
1740 this->TypeCheckPrimitiveSetStub::Compiler::updateStub();
1741 if (!stub)
1742 return nullptr;
1743 return stub->toUpdateStub();
1744 }
1745
1746 ICTypeUpdate_PrimitiveSet *getStub(ICStubSpace *space) {
1747 JS_ASSERT(!existingStub_);
1748 return ICTypeUpdate_PrimitiveSet::New(space, getStubCode(), flags_);
1749 }
1750 };
1751 };
1752
1753 // Type update stub to handle a singleton object.
1754 class ICTypeUpdate_SingleObject : public ICStub
1755 {
1756 friend class ICStubSpace;
1757
1758 HeapPtrObject obj_;
1759
1760 ICTypeUpdate_SingleObject(JitCode *stubCode, HandleObject obj);
1761
1762 public:
1763 static inline ICTypeUpdate_SingleObject *New(ICStubSpace *space, JitCode *code,
1764 HandleObject obj)
1765 {
1766 if (!code)
1767 return nullptr;
1768 return space->allocate<ICTypeUpdate_SingleObject>(code, obj);
1769 }
1770
1771 HeapPtrObject &object() {
1772 return obj_;
1773 }
1774
1775 static size_t offsetOfObject() {
1776 return offsetof(ICTypeUpdate_SingleObject, obj_);
1777 }
1778
1779 class Compiler : public ICStubCompiler {
1780 protected:
1781 HandleObject obj_;
1782 bool generateStubCode(MacroAssembler &masm);
1783
1784 public:
1785 Compiler(JSContext *cx, HandleObject obj)
1786 : ICStubCompiler(cx, TypeUpdate_SingleObject),
1787 obj_(obj)
1788 { }
1789
1790 ICTypeUpdate_SingleObject *getStub(ICStubSpace *space) {
1791 return ICTypeUpdate_SingleObject::New(space, getStubCode(), obj_);
1792 }
1793 };
1794 };
1795
1796 // Type update stub to handle a single TypeObject.
1797 class ICTypeUpdate_TypeObject : public ICStub
1798 {
1799 friend class ICStubSpace;
1800
1801 HeapPtrTypeObject type_;
1802
1803 ICTypeUpdate_TypeObject(JitCode *stubCode, HandleTypeObject type);
1804
1805 public:
1806 static inline ICTypeUpdate_TypeObject *New(ICStubSpace *space, JitCode *code,
1807 HandleTypeObject type)
1808 {
1809 if (!code)
1810 return nullptr;
1811 return space->allocate<ICTypeUpdate_TypeObject>(code, type);
1812 }
1813
1814 HeapPtrTypeObject &type() {
1815 return type_;
1816 }
1817
1818 static size_t offsetOfType() {
1819 return offsetof(ICTypeUpdate_TypeObject, type_);
1820 }
1821
1822 class Compiler : public ICStubCompiler {
1823 protected:
1824 HandleTypeObject type_;
1825 bool generateStubCode(MacroAssembler &masm);
1826
1827 public:
1828 Compiler(JSContext *cx, HandleTypeObject type)
1829 : ICStubCompiler(cx, TypeUpdate_TypeObject),
1830 type_(type)
1831 { }
1832
1833 ICTypeUpdate_TypeObject *getStub(ICStubSpace *space) {
1834 return ICTypeUpdate_TypeObject::New(space, getStubCode(), type_);
1835 }
1836 };
1837 };
1838
1839 // This
1840 // JSOP_THIS
1841
1842 class ICThis_Fallback : public ICFallbackStub
1843 {
1844 friend class ICStubSpace;
1845
1846 ICThis_Fallback(JitCode *stubCode)
1847 : ICFallbackStub(ICStub::This_Fallback, stubCode) {}
1848
1849 public:
1850 static inline ICThis_Fallback *New(ICStubSpace *space, JitCode *code) {
1851 if (!code)
1852 return nullptr;
1853 return space->allocate<ICThis_Fallback>(code);
1854 }
1855
1856 // Compiler for this stub kind.
1857 class Compiler : public ICStubCompiler {
1858 protected:
1859 bool generateStubCode(MacroAssembler &masm);
1860
1861 public:
1862 Compiler(JSContext *cx)
1863 : ICStubCompiler(cx, ICStub::This_Fallback) {}
1864
1865 ICStub *getStub(ICStubSpace *space) {
1866 return ICThis_Fallback::New(space, getStubCode());
1867 }
1868 };
1869 };
1870
1871 class ICNewArray_Fallback : public ICFallbackStub
1872 {
1873 friend class ICStubSpace;
1874
1875 HeapPtrObject templateObject_;
1876
1877 ICNewArray_Fallback(JitCode *stubCode, JSObject *templateObject)
1878 : ICFallbackStub(ICStub::NewArray_Fallback, stubCode), templateObject_(templateObject)
1879 {}
1880
1881 public:
1882 static inline ICNewArray_Fallback *New(ICStubSpace *space, JitCode *code,
1883 JSObject *templateObject) {
1884 if (!code)
1885 return nullptr;
1886 return space->allocate<ICNewArray_Fallback>(code, templateObject);
1887 }
1888
1889 class Compiler : public ICStubCompiler {
1890 RootedObject templateObject;
1891 bool generateStubCode(MacroAssembler &masm);
1892
1893 public:
1894 Compiler(JSContext *cx, JSObject *templateObject)
1895 : ICStubCompiler(cx, ICStub::NewArray_Fallback),
1896 templateObject(cx, templateObject)
1897 {}
1898
1899 ICStub *getStub(ICStubSpace *space) {
1900 return ICNewArray_Fallback::New(space, getStubCode(), templateObject);
1901 }
1902 };
1903
1904 HeapPtrObject &templateObject() {
1905 return templateObject_;
1906 }
1907 };
1908
1909 class ICNewObject_Fallback : public ICFallbackStub
1910 {
1911 friend class ICStubSpace;
1912
1913 HeapPtrObject templateObject_;
1914
1915 ICNewObject_Fallback(JitCode *stubCode, JSObject *templateObject)
1916 : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(templateObject)
1917 {}
1918
1919 public:
1920 static inline ICNewObject_Fallback *New(ICStubSpace *space, JitCode *code,
1921 JSObject *templateObject) {
1922 if (!code)
1923 return nullptr;
1924 return space->allocate<ICNewObject_Fallback>(code, templateObject);
1925 }
1926
1927 class Compiler : public ICStubCompiler {
1928 RootedObject templateObject;
1929 bool generateStubCode(MacroAssembler &masm);
1930
1931 public:
1932 Compiler(JSContext *cx, JSObject *templateObject)
1933 : ICStubCompiler(cx, ICStub::NewObject_Fallback),
1934 templateObject(cx, templateObject)
1935 {}
1936
1937 ICStub *getStub(ICStubSpace *space) {
1938 return ICNewObject_Fallback::New(space, getStubCode(), templateObject);
1939 }
1940 };
1941
1942 HeapPtrObject &templateObject() {
1943 return templateObject_;
1944 }
1945 };
1946
1947 // Compare
1948 // JSOP_LT
1949 // JSOP_GT
1950
1951 class ICCompare_Fallback : public ICFallbackStub
1952 {
1953 friend class ICStubSpace;
1954
1955 ICCompare_Fallback(JitCode *stubCode)
1956 : ICFallbackStub(ICStub::Compare_Fallback, stubCode) {}
1957
1958 public:
1959 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
1960
1961 static inline ICCompare_Fallback *New(ICStubSpace *space, JitCode *code) {
1962 if (!code)
1963 return nullptr;
1964 return space->allocate<ICCompare_Fallback>(code);
1965 }
1966
1967 // Compiler for this stub kind.
1968 class Compiler : public ICStubCompiler {
1969 protected:
1970 bool generateStubCode(MacroAssembler &masm);
1971
1972 public:
1973 Compiler(JSContext *cx)
1974 : ICStubCompiler(cx, ICStub::Compare_Fallback) {}
1975
1976 ICStub *getStub(ICStubSpace *space) {
1977 return ICCompare_Fallback::New(space, getStubCode());
1978 }
1979 };
1980 };
1981
1982 class ICCompare_Int32 : public ICStub
1983 {
1984 friend class ICStubSpace;
1985
1986 ICCompare_Int32(JitCode *stubCode)
1987 : ICStub(ICStub::Compare_Int32, stubCode) {}
1988
1989 public:
1990 static inline ICCompare_Int32 *New(ICStubSpace *space, JitCode *code) {
1991 if (!code)
1992 return nullptr;
1993 return space->allocate<ICCompare_Int32>(code);
1994 }
1995
1996 // Compiler for this stub kind.
1997 class Compiler : public ICMultiStubCompiler {
1998 protected:
1999 bool generateStubCode(MacroAssembler &masm);
2000
2001 public:
2002 Compiler(JSContext *cx, JSOp op)
2003 : ICMultiStubCompiler(cx, ICStub::Compare_Int32, op) {}
2004
2005 ICStub *getStub(ICStubSpace *space) {
2006 return ICCompare_Int32::New(space, getStubCode());
2007 }
2008 };
2009 };
2010
2011 class ICCompare_Double : public ICStub
2012 {
2013 friend class ICStubSpace;
2014
2015 ICCompare_Double(JitCode *stubCode)
2016 : ICStub(ICStub::Compare_Double, stubCode)
2017 {}
2018
2019 public:
2020 static inline ICCompare_Double *New(ICStubSpace *space, JitCode *code) {
2021 if (!code)
2022 return nullptr;
2023 return space->allocate<ICCompare_Double>(code);
2024 }
2025
2026 class Compiler : public ICMultiStubCompiler {
2027 protected:
2028 bool generateStubCode(MacroAssembler &masm);
2029
2030 public:
2031 Compiler(JSContext *cx, JSOp op)
2032 : ICMultiStubCompiler(cx, ICStub::Compare_Double, op)
2033 {}
2034
2035 ICStub *getStub(ICStubSpace *space) {
2036 return ICCompare_Double::New(space, getStubCode());
2037 }
2038 };
2039 };
2040
2041 class ICCompare_NumberWithUndefined : public ICStub
2042 {
2043 friend class ICStubSpace;
2044
2045 ICCompare_NumberWithUndefined(JitCode *stubCode, bool lhsIsUndefined)
2046 : ICStub(ICStub::Compare_NumberWithUndefined, stubCode)
2047 {
2048 extra_ = lhsIsUndefined;
2049 }
2050
2051 public:
2052 static inline ICCompare_NumberWithUndefined *New(ICStubSpace *space, JitCode *code, bool lhsIsUndefined) {
2053 if (!code)
2054 return nullptr;
2055 return space->allocate<ICCompare_NumberWithUndefined>(code, lhsIsUndefined);
2056 }
2057
2058 bool lhsIsUndefined() {
2059 return extra_;
2060 }
2061
2062 class Compiler : public ICMultiStubCompiler {
2063 protected:
2064 bool generateStubCode(MacroAssembler &masm);
2065
2066 bool lhsIsUndefined;
2067
2068 public:
2069 Compiler(JSContext *cx, JSOp op, bool lhsIsUndefined)
2070 : ICMultiStubCompiler(cx, ICStub::Compare_NumberWithUndefined, op),
2071 lhsIsUndefined(lhsIsUndefined)
2072 {}
2073
2074 virtual int32_t getKey() const {
2075 return static_cast<int32_t>(kind)
2076 | (static_cast<int32_t>(op) << 16)
2077 | (static_cast<int32_t>(lhsIsUndefined) << 24);
2078 }
2079
2080 ICStub *getStub(ICStubSpace *space) {
2081 return ICCompare_NumberWithUndefined::New(space, getStubCode(), lhsIsUndefined);
2082 }
2083 };
2084 };
2085
2086 class ICCompare_String : public ICStub
2087 {
2088 friend class ICStubSpace;
2089
2090 ICCompare_String(JitCode *stubCode)
2091 : ICStub(ICStub::Compare_String, stubCode)
2092 {}
2093
2094 public:
2095 static inline ICCompare_String *New(ICStubSpace *space, JitCode *code) {
2096 if (!code)
2097 return nullptr;
2098 return space->allocate<ICCompare_String>(code);
2099 }
2100
2101 class Compiler : public ICMultiStubCompiler {
2102 protected:
2103 bool generateStubCode(MacroAssembler &masm);
2104
2105 public:
2106 Compiler(JSContext *cx, JSOp op)
2107 : ICMultiStubCompiler(cx, ICStub::Compare_String, op)
2108 {}
2109
2110 ICStub *getStub(ICStubSpace *space) {
2111 return ICCompare_String::New(space, getStubCode());
2112 }
2113 };
2114 };
2115
2116 class ICCompare_Boolean : public ICStub
2117 {
2118 friend class ICStubSpace;
2119
2120 ICCompare_Boolean(JitCode *stubCode)
2121 : ICStub(ICStub::Compare_Boolean, stubCode)
2122 {}
2123
2124 public:
2125 static inline ICCompare_Boolean *New(ICStubSpace *space, JitCode *code) {
2126 if (!code)
2127 return nullptr;
2128 return space->allocate<ICCompare_Boolean>(code);
2129 }
2130
2131 class Compiler : public ICMultiStubCompiler {
2132 protected:
2133 bool generateStubCode(MacroAssembler &masm);
2134
2135 public:
2136 Compiler(JSContext *cx, JSOp op)
2137 : ICMultiStubCompiler(cx, ICStub::Compare_Boolean, op)
2138 {}
2139
2140 ICStub *getStub(ICStubSpace *space) {
2141 return ICCompare_Boolean::New(space, getStubCode());
2142 }
2143 };
2144 };
2145
2146 class ICCompare_Object : public ICStub
2147 {
2148 friend class ICStubSpace;
2149
2150 ICCompare_Object(JitCode *stubCode)
2151 : ICStub(ICStub::Compare_Object, stubCode)
2152 {}
2153
2154 public:
2155 static inline ICCompare_Object *New(ICStubSpace *space, JitCode *code) {
2156 if (!code)
2157 return nullptr;
2158 return space->allocate<ICCompare_Object>(code);
2159 }
2160
2161 class Compiler : public ICMultiStubCompiler {
2162 protected:
2163 bool generateStubCode(MacroAssembler &masm);
2164
2165 public:
2166 Compiler(JSContext *cx, JSOp op)
2167 : ICMultiStubCompiler(cx, ICStub::Compare_Object, op)
2168 {}
2169
2170 ICStub *getStub(ICStubSpace *space) {
2171 return ICCompare_Object::New(space, getStubCode());
2172 }
2173 };
2174 };
2175
2176 class ICCompare_ObjectWithUndefined : public ICStub
2177 {
2178 friend class ICStubSpace;
2179
2180 ICCompare_ObjectWithUndefined(JitCode *stubCode)
2181 : ICStub(ICStub::Compare_ObjectWithUndefined, stubCode)
2182 {}
2183
2184 public:
2185 static inline ICCompare_ObjectWithUndefined *New(ICStubSpace *space, JitCode *code) {
2186 if (!code)
2187 return nullptr;
2188 return space->allocate<ICCompare_ObjectWithUndefined>(code);
2189 }
2190
2191 class Compiler : public ICMultiStubCompiler {
2192 protected:
2193 bool generateStubCode(MacroAssembler &masm);
2194
2195 bool lhsIsUndefined;
2196 bool compareWithNull;
2197
2198 public:
2199 Compiler(JSContext *cx, JSOp op, bool lhsIsUndefined, bool compareWithNull)
2200 : ICMultiStubCompiler(cx, ICStub::Compare_ObjectWithUndefined, op),
2201 lhsIsUndefined(lhsIsUndefined),
2202 compareWithNull(compareWithNull)
2203 {}
2204
2205 virtual int32_t getKey() const {
2206 return static_cast<int32_t>(kind)
2207 | (static_cast<int32_t>(op) << 16)
2208 | (static_cast<int32_t>(lhsIsUndefined) << 24)
2209 | (static_cast<int32_t>(compareWithNull) << 25);
2210 }
2211
2212 ICStub *getStub(ICStubSpace *space) {
2213 return ICCompare_ObjectWithUndefined::New(space, getStubCode());
2214 }
2215 };
2216 };
2217
2218 class ICCompare_Int32WithBoolean : public ICStub
2219 {
2220 friend class ICStubSpace;
2221
2222 ICCompare_Int32WithBoolean(JitCode *stubCode, bool lhsIsInt32)
2223 : ICStub(ICStub::Compare_Int32WithBoolean, stubCode)
2224 {
2225 extra_ = lhsIsInt32;
2226 }
2227
2228 public:
2229 static inline ICCompare_Int32WithBoolean *New(ICStubSpace *space, JitCode *code,
2230 bool lhsIsInt32)
2231 {
2232 if (!code)
2233 return nullptr;
2234 return space->allocate<ICCompare_Int32WithBoolean>(code, lhsIsInt32);
2235 }
2236
2237 bool lhsIsInt32() const {
2238 return extra_;
2239 }
2240
2241 // Compiler for this stub kind.
2242 class Compiler : public ICStubCompiler {
2243 protected:
2244 JSOp op_;
2245 bool lhsIsInt32_;
2246 bool generateStubCode(MacroAssembler &masm);
2247
2248 virtual int32_t getKey() const {
2249 return (static_cast<int32_t>(kind) | (static_cast<int32_t>(op_) << 16) |
2250 (static_cast<int32_t>(lhsIsInt32_) << 24));
2251 }
2252
2253 public:
2254 Compiler(JSContext *cx, JSOp op, bool lhsIsInt32)
2255 : ICStubCompiler(cx, ICStub::Compare_Int32WithBoolean),
2256 op_(op),
2257 lhsIsInt32_(lhsIsInt32)
2258 {}
2259
2260 ICStub *getStub(ICStubSpace *space) {
2261 return ICCompare_Int32WithBoolean::New(space, getStubCode(), lhsIsInt32_);
2262 }
2263 };
2264 };
2265
2266 // ToBool
2267 // JSOP_IFNE
2268
2269 class ICToBool_Fallback : public ICFallbackStub
2270 {
2271 friend class ICStubSpace;
2272
2273 ICToBool_Fallback(JitCode *stubCode)
2274 : ICFallbackStub(ICStub::ToBool_Fallback, stubCode) {}
2275
2276 public:
2277 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
2278
2279 static inline ICToBool_Fallback *New(ICStubSpace *space, JitCode *code) {
2280 if (!code)
2281 return nullptr;
2282 return space->allocate<ICToBool_Fallback>(code);
2283 }
2284
2285 // Compiler for this stub kind.
2286 class Compiler : public ICStubCompiler {
2287 protected:
2288 bool generateStubCode(MacroAssembler &masm);
2289
2290 public:
2291 Compiler(JSContext *cx)
2292 : ICStubCompiler(cx, ICStub::ToBool_Fallback) {}
2293
2294 ICStub *getStub(ICStubSpace *space) {
2295 return ICToBool_Fallback::New(space, getStubCode());
2296 }
2297 };
2298 };
2299
2300 class ICToBool_Int32 : public ICStub
2301 {
2302 friend class ICStubSpace;
2303
2304 ICToBool_Int32(JitCode *stubCode)
2305 : ICStub(ICStub::ToBool_Int32, stubCode) {}
2306
2307 public:
2308 static inline ICToBool_Int32 *New(ICStubSpace *space, JitCode *code) {
2309 if (!code)
2310 return nullptr;
2311 return space->allocate<ICToBool_Int32>(code);
2312 }
2313
2314 // Compiler for this stub kind.
2315 class Compiler : public ICStubCompiler {
2316 protected:
2317 bool generateStubCode(MacroAssembler &masm);
2318
2319 public:
2320 Compiler(JSContext *cx)
2321 : ICStubCompiler(cx, ICStub::ToBool_Int32) {}
2322
2323 ICStub *getStub(ICStubSpace *space) {
2324 return ICToBool_Int32::New(space, getStubCode());
2325 }
2326 };
2327 };
2328
2329 class ICToBool_String : public ICStub
2330 {
2331 friend class ICStubSpace;
2332
2333 ICToBool_String(JitCode *stubCode)
2334 : ICStub(ICStub::ToBool_String, stubCode) {}
2335
2336 public:
2337 static inline ICToBool_String *New(ICStubSpace *space, JitCode *code) {
2338 if (!code)
2339 return nullptr;
2340 return space->allocate<ICToBool_String>(code);
2341 }
2342
2343 // Compiler for this stub kind.
2344 class Compiler : public ICStubCompiler {
2345 protected:
2346 bool generateStubCode(MacroAssembler &masm);
2347
2348 public:
2349 Compiler(JSContext *cx)
2350 : ICStubCompiler(cx, ICStub::ToBool_String) {}
2351
2352 ICStub *getStub(ICStubSpace *space) {
2353 return ICToBool_String::New(space, getStubCode());
2354 }
2355 };
2356 };
2357
2358 class ICToBool_NullUndefined : public ICStub
2359 {
2360 friend class ICStubSpace;
2361
2362 ICToBool_NullUndefined(JitCode *stubCode)
2363 : ICStub(ICStub::ToBool_NullUndefined, stubCode) {}
2364
2365 public:
2366 static inline ICToBool_NullUndefined *New(ICStubSpace *space, JitCode *code) {
2367 if (!code)
2368 return nullptr;
2369 return space->allocate<ICToBool_NullUndefined>(code);
2370 }
2371
2372 // Compiler for this stub kind.
2373 class Compiler : public ICStubCompiler {
2374 protected:
2375 bool generateStubCode(MacroAssembler &masm);
2376
2377 public:
2378 Compiler(JSContext *cx)
2379 : ICStubCompiler(cx, ICStub::ToBool_NullUndefined) {}
2380
2381 ICStub *getStub(ICStubSpace *space) {
2382 return ICToBool_NullUndefined::New(space, getStubCode());
2383 }
2384 };
2385 };
2386
2387 class ICToBool_Double : public ICStub
2388 {
2389 friend class ICStubSpace;
2390
2391 ICToBool_Double(JitCode *stubCode)
2392 : ICStub(ICStub::ToBool_Double, stubCode) {}
2393
2394 public:
2395 static inline ICToBool_Double *New(ICStubSpace *space, JitCode *code) {
2396 if (!code)
2397 return nullptr;
2398 return space->allocate<ICToBool_Double>(code);
2399 }
2400
2401 // Compiler for this stub kind.
2402 class Compiler : public ICStubCompiler {
2403 protected:
2404 bool generateStubCode(MacroAssembler &masm);
2405
2406 public:
2407 Compiler(JSContext *cx)
2408 : ICStubCompiler(cx, ICStub::ToBool_Double) {}
2409
2410 ICStub *getStub(ICStubSpace *space) {
2411 return ICToBool_Double::New(space, getStubCode());
2412 }
2413 };
2414 };
2415
2416 class ICToBool_Object : public ICStub
2417 {
2418 friend class ICStubSpace;
2419
2420 ICToBool_Object(JitCode *stubCode)
2421 : ICStub(ICStub::ToBool_Object, stubCode) {}
2422
2423 public:
2424 static inline ICToBool_Object *New(ICStubSpace *space, JitCode *code) {
2425 if (!code)
2426 return nullptr;
2427 return space->allocate<ICToBool_Object>(code);
2428 }
2429
2430 // Compiler for this stub kind.
2431 class Compiler : public ICStubCompiler {
2432 protected:
2433 bool generateStubCode(MacroAssembler &masm);
2434
2435 public:
2436 Compiler(JSContext *cx)
2437 : ICStubCompiler(cx, ICStub::ToBool_Object) {}
2438
2439 ICStub *getStub(ICStubSpace *space) {
2440 return ICToBool_Object::New(space, getStubCode());
2441 }
2442 };
2443 };
2444
2445 // ToNumber
2446 // JSOP_POS
2447
2448 class ICToNumber_Fallback : public ICFallbackStub
2449 {
2450 friend class ICStubSpace;
2451
2452 ICToNumber_Fallback(JitCode *stubCode)
2453 : ICFallbackStub(ICStub::ToNumber_Fallback, stubCode) {}
2454
2455 public:
2456 static inline ICToNumber_Fallback *New(ICStubSpace *space, JitCode *code) {
2457 if (!code)
2458 return nullptr;
2459 return space->allocate<ICToNumber_Fallback>(code);
2460 }
2461
2462 // Compiler for this stub kind.
2463 class Compiler : public ICStubCompiler {
2464 protected:
2465 bool generateStubCode(MacroAssembler &masm);
2466
2467 public:
2468 Compiler(JSContext *cx)
2469 : ICStubCompiler(cx, ICStub::ToNumber_Fallback) {}
2470
2471 ICStub *getStub(ICStubSpace *space) {
2472 return ICToNumber_Fallback::New(space, getStubCode());
2473 }
2474 };
2475 };
2476
2477 // BinaryArith
2478 // JSOP_ADD
2479 // JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR
2480 // JSOP_LSH, JSOP_RSH, JSOP_URSH
2481
2482 class ICBinaryArith_Fallback : public ICFallbackStub
2483 {
2484 friend class ICStubSpace;
2485
2486 ICBinaryArith_Fallback(JitCode *stubCode)
2487 : ICFallbackStub(BinaryArith_Fallback, stubCode)
2488 {
2489 extra_ = 0;
2490 }
2491
2492 static const uint16_t SAW_DOUBLE_RESULT_BIT = 0x1;
2493 static const uint16_t UNOPTIMIZABLE_OPERANDS_BIT = 0x2;
2494
2495 public:
2496 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
2497
2498 static inline ICBinaryArith_Fallback *New(ICStubSpace *space, JitCode *code) {
2499 if (!code)
2500 return nullptr;
2501 return space->allocate<ICBinaryArith_Fallback>(code);
2502 }
2503
2504 bool sawDoubleResult() const {
2505 return extra_ & SAW_DOUBLE_RESULT_BIT;
2506 }
2507 void setSawDoubleResult() {
2508 extra_ |= SAW_DOUBLE_RESULT_BIT;
2509 }
2510 bool hadUnoptimizableOperands() const {
2511 return extra_ & UNOPTIMIZABLE_OPERANDS_BIT;
2512 }
2513 void noteUnoptimizableOperands() {
2514 extra_ |= UNOPTIMIZABLE_OPERANDS_BIT;
2515 }
2516
2517 // Compiler for this stub kind.
2518 class Compiler : public ICStubCompiler {
2519 protected:
2520 bool generateStubCode(MacroAssembler &masm);
2521
2522 public:
2523 Compiler(JSContext *cx)
2524 : ICStubCompiler(cx, ICStub::BinaryArith_Fallback) {}
2525
2526 ICStub *getStub(ICStubSpace *space) {
2527 return ICBinaryArith_Fallback::New(space, getStubCode());
2528 }
2529 };
2530 };
2531
2532 class ICBinaryArith_Int32 : public ICStub
2533 {
2534 friend class ICStubSpace;
2535
2536 ICBinaryArith_Int32(JitCode *stubCode, bool allowDouble)
2537 : ICStub(BinaryArith_Int32, stubCode)
2538 {
2539 extra_ = allowDouble;
2540 }
2541
2542 public:
2543 static inline ICBinaryArith_Int32 *New(ICStubSpace *space, JitCode *code, bool allowDouble) {
2544 if (!code)
2545 return nullptr;
2546 return space->allocate<ICBinaryArith_Int32>(code, allowDouble);
2547 }
2548 bool allowDouble() const {
2549 return extra_;
2550 }
2551
2552 // Compiler for this stub kind.
2553 class Compiler : public ICStubCompiler {
2554 protected:
2555 JSOp op_;
2556 bool allowDouble_;
2557
2558 bool generateStubCode(MacroAssembler &masm);
2559
2560 // Stub keys shift-stubs need to encode the kind, the JSOp and if we allow doubles.
2561 virtual int32_t getKey() const {
2562 return (static_cast<int32_t>(kind) | (static_cast<int32_t>(op_) << 16) |
2563 (static_cast<int32_t>(allowDouble_) << 24));
2564 }
2565
2566 public:
2567 Compiler(JSContext *cx, JSOp op, bool allowDouble)
2568 : ICStubCompiler(cx, ICStub::BinaryArith_Int32),
2569 op_(op), allowDouble_(allowDouble) {}
2570
2571 ICStub *getStub(ICStubSpace *space) {
2572 return ICBinaryArith_Int32::New(space, getStubCode(), allowDouble_);
2573 }
2574 };
2575 };
2576
2577 class ICBinaryArith_StringConcat : public ICStub
2578 {
2579 friend class ICStubSpace;
2580
2581 ICBinaryArith_StringConcat(JitCode *stubCode)
2582 : ICStub(BinaryArith_StringConcat, stubCode)
2583 {}
2584
2585 public:
2586 static inline ICBinaryArith_StringConcat *New(ICStubSpace *space, JitCode *code) {
2587 if (!code)
2588 return nullptr;
2589 return space->allocate<ICBinaryArith_StringConcat>(code);
2590 }
2591
2592 class Compiler : public ICStubCompiler {
2593 protected:
2594 bool generateStubCode(MacroAssembler &masm);
2595
2596 public:
2597 Compiler(JSContext *cx)
2598 : ICStubCompiler(cx, ICStub::BinaryArith_StringConcat)
2599 {}
2600
2601 ICStub *getStub(ICStubSpace *space) {
2602 return ICBinaryArith_StringConcat::New(space, getStubCode());
2603 }
2604 };
2605 };
2606
2607 class ICBinaryArith_StringObjectConcat : public ICStub
2608 {
2609 friend class ICStubSpace;
2610
2611 ICBinaryArith_StringObjectConcat(JitCode *stubCode, bool lhsIsString)
2612 : ICStub(BinaryArith_StringObjectConcat, stubCode)
2613 {
2614 extra_ = lhsIsString;
2615 }
2616
2617 public:
2618 static inline ICBinaryArith_StringObjectConcat *New(ICStubSpace *space, JitCode *code,
2619 bool lhsIsString) {
2620 if (!code)
2621 return nullptr;
2622 return space->allocate<ICBinaryArith_StringObjectConcat>(code, lhsIsString);
2623 }
2624
2625 bool lhsIsString() const {
2626 return extra_;
2627 }
2628
2629 class Compiler : public ICStubCompiler {
2630 protected:
2631 bool lhsIsString_;
2632 bool generateStubCode(MacroAssembler &masm);
2633
2634 virtual int32_t getKey() const {
2635 return static_cast<int32_t>(kind) | (static_cast<int32_t>(lhsIsString_) << 16);
2636 }
2637
2638 public:
2639 Compiler(JSContext *cx, bool lhsIsString)
2640 : ICStubCompiler(cx, ICStub::BinaryArith_StringObjectConcat),
2641 lhsIsString_(lhsIsString)
2642 {}
2643
2644 ICStub *getStub(ICStubSpace *space) {
2645 return ICBinaryArith_StringObjectConcat::New(space, getStubCode(), lhsIsString_);
2646 }
2647 };
2648 };
2649
2650 class ICBinaryArith_Double : public ICStub
2651 {
2652 friend class ICStubSpace;
2653
2654 ICBinaryArith_Double(JitCode *stubCode)
2655 : ICStub(BinaryArith_Double, stubCode)
2656 {}
2657
2658 public:
2659 static inline ICBinaryArith_Double *New(ICStubSpace *space, JitCode *code) {
2660 if (!code)
2661 return nullptr;
2662 return space->allocate<ICBinaryArith_Double>(code);
2663 }
2664
2665 class Compiler : public ICMultiStubCompiler {
2666 protected:
2667 bool generateStubCode(MacroAssembler &masm);
2668
2669 public:
2670 Compiler(JSContext *cx, JSOp op)
2671 : ICMultiStubCompiler(cx, ICStub::BinaryArith_Double, op)
2672 {}
2673
2674 ICStub *getStub(ICStubSpace *space) {
2675 return ICBinaryArith_Double::New(space, getStubCode());
2676 }
2677 };
2678 };
2679
2680 class ICBinaryArith_BooleanWithInt32 : public ICStub
2681 {
2682 friend class ICStubSpace;
2683
2684 ICBinaryArith_BooleanWithInt32(JitCode *stubCode, bool lhsIsBool, bool rhsIsBool)
2685 : ICStub(BinaryArith_BooleanWithInt32, stubCode)
2686 {
2687 JS_ASSERT(lhsIsBool || rhsIsBool);
2688 extra_ = 0;
2689 if (lhsIsBool)
2690 extra_ |= 1;
2691 if (rhsIsBool)
2692 extra_ |= 2;
2693 }
2694
2695 public:
2696 static inline ICBinaryArith_BooleanWithInt32 *New(ICStubSpace *space, JitCode *code,
2697 bool lhsIsBool, bool rhsIsBool) {
2698 if (!code)
2699 return nullptr;
2700 return space->allocate<ICBinaryArith_BooleanWithInt32>(code, lhsIsBool, rhsIsBool);
2701 }
2702
2703 bool lhsIsBoolean() const {
2704 return extra_ & 1;
2705 }
2706
2707 bool rhsIsBoolean() const {
2708 return extra_ & 2;
2709 }
2710
2711 class Compiler : public ICStubCompiler {
2712 protected:
2713 JSOp op_;
2714 bool lhsIsBool_;
2715 bool rhsIsBool_;
2716 bool generateStubCode(MacroAssembler &masm);
2717
2718 virtual int32_t getKey() const {
2719 return static_cast<int32_t>(kind) | (static_cast<int32_t>(op_) << 16) |
2720 (static_cast<int32_t>(lhsIsBool_) << 24) |
2721 (static_cast<int32_t>(rhsIsBool_) << 25);
2722 }
2723
2724 public:
2725 Compiler(JSContext *cx, JSOp op, bool lhsIsBool, bool rhsIsBool)
2726 : ICStubCompiler(cx, ICStub::BinaryArith_BooleanWithInt32),
2727 op_(op), lhsIsBool_(lhsIsBool), rhsIsBool_(rhsIsBool)
2728 {
2729 JS_ASSERT(op_ == JSOP_ADD || op_ == JSOP_SUB || op_ == JSOP_BITOR ||
2730 op_ == JSOP_BITAND || op_ == JSOP_BITXOR);
2731 JS_ASSERT(lhsIsBool_ || rhsIsBool_);
2732 }
2733
2734 ICStub *getStub(ICStubSpace *space) {
2735 return ICBinaryArith_BooleanWithInt32::New(space, getStubCode(),
2736 lhsIsBool_, rhsIsBool_);
2737 }
2738 };
2739 };
2740
2741 class ICBinaryArith_DoubleWithInt32 : public ICStub
2742 {
2743 friend class ICStubSpace;
2744
2745 ICBinaryArith_DoubleWithInt32(JitCode *stubCode, bool lhsIsDouble)
2746 : ICStub(BinaryArith_DoubleWithInt32, stubCode)
2747 {
2748 extra_ = lhsIsDouble;
2749 }
2750
2751 public:
2752 static inline ICBinaryArith_DoubleWithInt32 *New(ICStubSpace *space, JitCode *code,
2753 bool lhsIsDouble) {
2754 if (!code)
2755 return nullptr;
2756 return space->allocate<ICBinaryArith_DoubleWithInt32>(code, lhsIsDouble);
2757 }
2758
2759 bool lhsIsDouble() const {
2760 return extra_;
2761 }
2762
2763 class Compiler : public ICMultiStubCompiler {
2764 protected:
2765 bool lhsIsDouble_;
2766 bool generateStubCode(MacroAssembler &masm);
2767
2768 virtual int32_t getKey() const {
2769 return static_cast<int32_t>(kind) | (static_cast<int32_t>(op) << 16) |
2770 (static_cast<int32_t>(lhsIsDouble_) << 24);
2771 }
2772
2773 public:
2774 Compiler(JSContext *cx, JSOp op, bool lhsIsDouble)
2775 : ICMultiStubCompiler(cx, ICStub::BinaryArith_DoubleWithInt32, op),
2776 lhsIsDouble_(lhsIsDouble)
2777 {}
2778
2779 ICStub *getStub(ICStubSpace *space) {
2780 return ICBinaryArith_DoubleWithInt32::New(space, getStubCode(), lhsIsDouble_);
2781 }
2782 };
2783 };
2784
2785 // UnaryArith
2786 // JSOP_BITNOT
2787 // JSOP_NEG
2788
2789 class ICUnaryArith_Fallback : public ICFallbackStub
2790 {
2791 friend class ICStubSpace;
2792
2793 ICUnaryArith_Fallback(JitCode *stubCode)
2794 : ICFallbackStub(UnaryArith_Fallback, stubCode)
2795 {
2796 extra_ = 0;
2797 }
2798
2799 public:
2800 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
2801
2802 static inline ICUnaryArith_Fallback *New(ICStubSpace *space, JitCode *code) {
2803 if (!code)
2804 return nullptr;
2805 return space->allocate<ICUnaryArith_Fallback>(code);
2806 }
2807
2808 bool sawDoubleResult() {
2809 return extra_;
2810 }
2811 void setSawDoubleResult() {
2812 extra_ = 1;
2813 }
2814
2815 // Compiler for this stub kind.
2816 class Compiler : public ICStubCompiler {
2817 protected:
2818 bool generateStubCode(MacroAssembler &masm);
2819
2820 public:
2821 Compiler(JSContext *cx)
2822 : ICStubCompiler(cx, ICStub::UnaryArith_Fallback)
2823 {}
2824
2825 ICStub *getStub(ICStubSpace *space) {
2826 return ICUnaryArith_Fallback::New(space, getStubCode());
2827 }
2828 };
2829 };
2830
2831 class ICUnaryArith_Int32 : public ICStub
2832 {
2833 friend class ICStubSpace;
2834
2835 ICUnaryArith_Int32(JitCode *stubCode)
2836 : ICStub(UnaryArith_Int32, stubCode)
2837 {}
2838
2839 public:
2840 static inline ICUnaryArith_Int32 *New(ICStubSpace *space, JitCode *code) {
2841 if (!code)
2842 return nullptr;
2843 return space->allocate<ICUnaryArith_Int32>(code);
2844 }
2845
2846 class Compiler : public ICMultiStubCompiler {
2847 protected:
2848 bool generateStubCode(MacroAssembler &masm);
2849
2850 public:
2851 Compiler(JSContext *cx, JSOp op)
2852 : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op)
2853 {}
2854
2855 ICStub *getStub(ICStubSpace *space) {
2856 return ICUnaryArith_Int32::New(space, getStubCode());
2857 }
2858 };
2859 };
2860
2861 class ICUnaryArith_Double : public ICStub
2862 {
2863 friend class ICStubSpace;
2864
2865 ICUnaryArith_Double(JitCode *stubCode)
2866 : ICStub(UnaryArith_Double, stubCode)
2867 {}
2868
2869 public:
2870 static inline ICUnaryArith_Double *New(ICStubSpace *space, JitCode *code) {
2871 if (!code)
2872 return nullptr;
2873 return space->allocate<ICUnaryArith_Double>(code);
2874 }
2875
2876 class Compiler : public ICMultiStubCompiler {
2877 protected:
2878 bool generateStubCode(MacroAssembler &masm);
2879
2880 public:
2881 Compiler(JSContext *cx, JSOp op)
2882 : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op)
2883 {}
2884
2885 ICStub *getStub(ICStubSpace *space) {
2886 return ICUnaryArith_Double::New(space, getStubCode());
2887 }
2888 };
2889 };
2890
2891 // GetElem
2892 // JSOP_GETELEM
2893
2894 class ICGetElem_Fallback : public ICMonitoredFallbackStub
2895 {
2896 friend class ICStubSpace;
2897
2898 ICGetElem_Fallback(JitCode *stubCode)
2899 : ICMonitoredFallbackStub(ICStub::GetElem_Fallback, stubCode)
2900 { }
2901
2902 static const uint16_t EXTRA_NON_NATIVE = 0x1;
2903 static const uint16_t EXTRA_NEGATIVE_INDEX = 0x2;
2904
2905 public:
2906 static const uint32_t MAX_OPTIMIZED_STUBS = 16;
2907
2908 static inline ICGetElem_Fallback *New(ICStubSpace *space, JitCode *code) {
2909 if (!code)
2910 return nullptr;
2911 return space->allocate<ICGetElem_Fallback>(code);
2912 }
2913
2914 void noteNonNativeAccess() {
2915 extra_ |= EXTRA_NON_NATIVE;
2916 }
2917 bool hasNonNativeAccess() const {
2918 return extra_ & EXTRA_NON_NATIVE;
2919 }
2920
2921 void noteNegativeIndex() {
2922 extra_ |= EXTRA_NEGATIVE_INDEX;
2923 }
2924 bool hasNegativeIndex() const {
2925 return extra_ & EXTRA_NEGATIVE_INDEX;
2926 }
2927
2928 // Compiler for this stub kind.
2929 class Compiler : public ICStubCompiler {
2930 protected:
2931 bool generateStubCode(MacroAssembler &masm);
2932
2933 public:
2934 Compiler(JSContext *cx)
2935 : ICStubCompiler(cx, ICStub::GetElem_Fallback)
2936 { }
2937
2938 ICStub *getStub(ICStubSpace *space) {
2939 ICGetElem_Fallback *stub = ICGetElem_Fallback::New(space, getStubCode());
2940 if (!stub)
2941 return nullptr;
2942 if (!stub->initMonitoringChain(cx, space))
2943 return nullptr;
2944 return stub;
2945 }
2946 };
2947 };
2948
2949 class ICGetElemNativeStub : public ICMonitoredStub
2950 {
2951 public:
2952 enum AccessType { FixedSlot = 0, DynamicSlot, NativeGetter, ScriptedGetter };
2953
2954 protected:
2955 HeapPtrShape shape_;
2956 HeapPtrPropertyName name_;
2957
2958 static const unsigned NEEDS_ATOMIZE_SHIFT = 0;
2959 static const uint16_t NEEDS_ATOMIZE_MASK = 0x1;
2960
2961 static const unsigned ACCESSTYPE_SHIFT = 1;
2962 static const uint16_t ACCESSTYPE_MASK = 0x3;
2963
2964 ICGetElemNativeStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
2965 HandleShape shape, HandlePropertyName name, AccessType acctype,
2966 bool needsAtomize);
2967
2968 ~ICGetElemNativeStub();
2969
2970 public:
2971 HeapPtrShape &shape() {
2972 return shape_;
2973 }
2974 static size_t offsetOfShape() {
2975 return offsetof(ICGetElemNativeStub, shape_);
2976 }
2977
2978 HeapPtrPropertyName &name() {
2979 return name_;
2980 }
2981 static size_t offsetOfName() {
2982 return offsetof(ICGetElemNativeStub, name_);
2983 }
2984
2985 AccessType accessType() const {
2986 return static_cast<AccessType>((extra_ >> ACCESSTYPE_SHIFT) & ACCESSTYPE_MASK);
2987 }
2988
2989 bool needsAtomize() const {
2990 return (extra_ >> NEEDS_ATOMIZE_SHIFT) & NEEDS_ATOMIZE_MASK;
2991 }
2992 };
2993
2994 class ICGetElemNativeSlotStub : public ICGetElemNativeStub
2995 {
2996 protected:
2997 uint32_t offset_;
2998
2999 ICGetElemNativeSlotStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
3000 HandleShape shape, HandlePropertyName name,
3001 AccessType acctype, bool needsAtomize, uint32_t offset)
3002 : ICGetElemNativeStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize),
3003 offset_(offset)
3004 {
3005 JS_ASSERT(kind == GetElem_NativeSlot || kind == GetElem_NativePrototypeSlot);
3006 JS_ASSERT(acctype == FixedSlot || acctype == DynamicSlot);
3007 }
3008
3009 public:
3010 uint32_t offset() const {
3011 return offset_;
3012 }
3013
3014 static size_t offsetOfOffset() {
3015 return offsetof(ICGetElemNativeSlotStub, offset_);
3016 }
3017 };
3018
3019 class ICGetElemNativeGetterStub : public ICGetElemNativeStub
3020 {
3021 protected:
3022 HeapPtrFunction getter_;
3023 uint32_t pcOffset_;
3024
3025 ICGetElemNativeGetterStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
3026 HandleShape shape, HandlePropertyName name, AccessType acctype,
3027 bool needsAtomize, HandleFunction getter, uint32_t pcOffset);
3028
3029 public:
3030 HeapPtrFunction &getter() {
3031 return getter_;
3032 }
3033 static size_t offsetOfGetter() {
3034 return offsetof(ICGetElemNativeGetterStub, getter_);
3035 }
3036
3037 static size_t offsetOfPCOffset() {
3038 return offsetof(ICGetElemNativeGetterStub, pcOffset_);
3039 }
3040 };
3041
3042 class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub
3043 {
3044 friend class ICStubSpace;
3045 ICGetElem_NativeSlot(JitCode *stubCode, ICStub *firstMonitorStub,
3046 HandleShape shape, HandlePropertyName name,
3047 AccessType acctype, bool needsAtomize, uint32_t offset)
3048 : ICGetElemNativeSlotStub(ICStub::GetElem_NativeSlot, stubCode, firstMonitorStub, shape,
3049 name, acctype, needsAtomize, offset)
3050 {}
3051
3052 public:
3053 static inline ICGetElem_NativeSlot *New(ICStubSpace *space, JitCode *code,
3054 ICStub *firstMonitorStub,
3055 HandleShape shape, HandlePropertyName name,
3056 AccessType acctype, bool needsAtomize, uint32_t offset)
3057 {
3058 if (!code)
3059 return nullptr;
3060 return space->allocate<ICGetElem_NativeSlot>(code, firstMonitorStub, shape, name,
3061 acctype, needsAtomize, offset);
3062 }
3063 };
3064
3065 class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub
3066 {
3067 friend class ICStubSpace;
3068 HeapPtrObject holder_;
3069 HeapPtrShape holderShape_;
3070
3071 ICGetElem_NativePrototypeSlot(JitCode *stubCode, ICStub *firstMonitorStub,
3072 HandleShape shape, HandlePropertyName name,
3073 AccessType acctype, bool needsAtomize, uint32_t offset,
3074 HandleObject holder, HandleShape holderShape);
3075
3076 public:
3077 static inline ICGetElem_NativePrototypeSlot *New(ICStubSpace *space, JitCode *code,
3078 ICStub *firstMonitorStub,
3079 HandleShape shape, HandlePropertyName name,
3080 AccessType acctype, bool needsAtomize,
3081 uint32_t offset, HandleObject holder,
3082 HandleShape holderShape)
3083 {
3084 if (!code)
3085 return nullptr;
3086 return space->allocate<ICGetElem_NativePrototypeSlot>(
3087 code, firstMonitorStub, shape, name, acctype, needsAtomize, offset, holder,
3088 holderShape);
3089 }
3090
3091 HeapPtrObject &holder() {
3092 return holder_;
3093 }
3094 static size_t offsetOfHolder() {
3095 return offsetof(ICGetElem_NativePrototypeSlot, holder_);
3096 }
3097
3098 HeapPtrShape &holderShape() {
3099 return holderShape_;
3100 }
3101 static size_t offsetOfHolderShape() {
3102 return offsetof(ICGetElem_NativePrototypeSlot, holderShape_);
3103 }
3104 };
3105
3106 class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub
3107 {
3108 friend class ICStubSpace;
3109 HeapPtrObject holder_;
3110 HeapPtrShape holderShape_;
3111
3112 protected:
3113 ICGetElemNativePrototypeCallStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
3114 HandleShape shape, HandlePropertyName name,
3115 AccessType acctype, bool needsAtomize, HandleFunction getter,
3116 uint32_t pcOffset, HandleObject holder,
3117 HandleShape holderShape);
3118
3119 public:
3120 HeapPtrObject &holder() {
3121 return holder_;
3122 }
3123 static size_t offsetOfHolder() {
3124 return offsetof(ICGetElemNativePrototypeCallStub, holder_);
3125 }
3126
3127 HeapPtrShape &holderShape() {
3128 return holderShape_;
3129 }
3130 static size_t offsetOfHolderShape() {
3131 return offsetof(ICGetElemNativePrototypeCallStub, holderShape_);
3132 }
3133 };
3134
3135 class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub
3136 {
3137 friend class ICStubSpace;
3138
3139 ICGetElem_NativePrototypeCallNative(JitCode *stubCode, ICStub *firstMonitorStub,
3140 HandleShape shape, HandlePropertyName name,
3141 AccessType acctype, bool needsAtomize,
3142 HandleFunction getter, uint32_t pcOffset,
3143 HandleObject holder, HandleShape holderShape)
3144 : ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallNative,
3145 stubCode, firstMonitorStub, shape, name,
3146 acctype, needsAtomize, getter, pcOffset, holder,
3147 holderShape)
3148 {}
3149
3150 public:
3151 static inline ICGetElem_NativePrototypeCallNative *New(
3152 ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
3153 HandleShape shape, HandlePropertyName name, AccessType acctype,
3154 bool needsAtomize, HandleFunction getter, uint32_t pcOffset,
3155 HandleObject holder, HandleShape holderShape)
3156 {
3157 if (!code)
3158 return nullptr;
3159 return space->allocate<ICGetElem_NativePrototypeCallNative>(
3160 code, firstMonitorStub, shape, name, acctype, needsAtomize, getter,
3161 pcOffset, holder, holderShape);
3162 }
3163 };
3164
3165 class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub
3166 {
3167 friend class ICStubSpace;
3168
3169 ICGetElem_NativePrototypeCallScripted(JitCode *stubCode, ICStub *firstMonitorStub,
3170 HandleShape shape, HandlePropertyName name,
3171 AccessType acctype, bool needsAtomize,
3172 HandleFunction getter, uint32_t pcOffset,
3173 HandleObject holder, HandleShape holderShape)
3174 : ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallScripted,
3175 stubCode, firstMonitorStub, shape, name,
3176 acctype, needsAtomize, getter, pcOffset, holder,
3177 holderShape)
3178 {}
3179
3180 public:
3181 static inline ICGetElem_NativePrototypeCallScripted *New(
3182 ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
3183 HandleShape shape, HandlePropertyName name, AccessType acctype,
3184 bool needsAtomize, HandleFunction getter, uint32_t pcOffset,
3185 HandleObject holder, HandleShape holderShape)
3186 {
3187 if (!code)
3188 return nullptr;
3189 return space->allocate<ICGetElem_NativePrototypeCallScripted>(
3190 code, firstMonitorStub, shape, name, acctype, needsAtomize, getter,
3191 pcOffset, holder, holderShape);
3192 }
3193 };
3194
3195 // Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs.
3196 class ICGetElemNativeCompiler : public ICStubCompiler
3197 {
3198 bool isCallElem_;
3199 ICStub *firstMonitorStub_;
3200 HandleObject obj_;
3201 HandleObject holder_;
3202 HandlePropertyName name_;
3203 ICGetElemNativeStub::AccessType acctype_;
3204 bool needsAtomize_;
3205 uint32_t offset_;
3206 HandleFunction getter_;
3207 uint32_t pcOffset_;
3208
3209 bool emitCallNative(MacroAssembler &masm, Register objReg);
3210 bool emitCallScripted(MacroAssembler &masm, Register objReg);
3211 bool generateStubCode(MacroAssembler &masm);
3212
3213 protected:
3214 virtual int32_t getKey() const {
3215 #if JS_HAS_NO_SUCH_METHOD
3216 return static_cast<int32_t>(kind) |
3217 (static_cast<int32_t>(isCallElem_) << 16) |
3218 (static_cast<int32_t>(needsAtomize_) << 17) |
3219 (static_cast<int32_t>(acctype_) << 18);
3220 #else
3221 return static_cast<int32_t>(kind) | (static_cast<int32_t>(needsAtomize_) << 16) |
3222 (static_cast<int32_t>(acctype_) << 17);
3223 #endif
3224 }
3225
3226 public:
3227 ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, bool isCallElem,
3228 ICStub *firstMonitorStub, HandleObject obj, HandleObject holder,
3229 HandlePropertyName name, ICGetElemNativeStub::AccessType acctype,
3230 bool needsAtomize, uint32_t offset)
3231 : ICStubCompiler(cx, kind),
3232 isCallElem_(isCallElem),
3233 firstMonitorStub_(firstMonitorStub),
3234 obj_(obj),
3235 holder_(holder),
3236 name_(name),
3237 acctype_(acctype),
3238 needsAtomize_(needsAtomize),
3239 offset_(offset),
3240 getter_(js::NullPtr()),
3241 pcOffset_(0)
3242 {}
3243
3244 ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub,
3245 HandleObject obj, HandleObject holder, HandlePropertyName name,
3246 ICGetElemNativeStub::AccessType acctype, bool needsAtomize,
3247 HandleFunction getter, uint32_t pcOffset, bool isCallElem)
3248 : ICStubCompiler(cx, kind),
3249 isCallElem_(false),
3250 firstMonitorStub_(firstMonitorStub),
3251 obj_(obj),
3252 holder_(holder),
3253 name_(name),
3254 acctype_(acctype),
3255 needsAtomize_(needsAtomize),
3256 offset_(0),
3257 getter_(getter),
3258 pcOffset_(pcOffset)
3259 {}
3260
3261 ICStub *getStub(ICStubSpace *space) {
3262 RootedShape shape(cx, obj_->lastProperty());
3263 if (kind == ICStub::GetElem_NativeSlot) {
3264 JS_ASSERT(obj_ == holder_);
3265 return ICGetElem_NativeSlot::New(
3266 space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
3267 offset_);
3268 }
3269
3270 JS_ASSERT(obj_ != holder_);
3271 RootedShape holderShape(cx, holder_->lastProperty());
3272 if (kind == ICStub::GetElem_NativePrototypeSlot) {
3273 return ICGetElem_NativePrototypeSlot::New(
3274 space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
3275 offset_, holder_, holderShape);
3276 }
3277
3278 if (kind == ICStub::GetElem_NativePrototypeCallNative) {
3279 return ICGetElem_NativePrototypeCallNative::New(
3280 space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
3281 getter_, pcOffset_, holder_, holderShape);
3282 }
3283
3284 JS_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScripted);
3285 if (kind == ICStub::GetElem_NativePrototypeCallScripted) {
3286 return ICGetElem_NativePrototypeCallScripted::New(
3287 space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
3288 getter_, pcOffset_, holder_, holderShape);
3289 }
3290
3291 MOZ_ASSUME_UNREACHABLE("Invalid kind.");
3292 return nullptr;
3293 }
3294 };
3295
3296 class ICGetElem_String : public ICStub
3297 {
3298 friend class ICStubSpace;
3299
3300 ICGetElem_String(JitCode *stubCode)
3301 : ICStub(ICStub::GetElem_String, stubCode) {}
3302
3303 public:
3304 static inline ICGetElem_String *New(ICStubSpace *space, JitCode *code) {
3305 if (!code)
3306 return nullptr;
3307 return space->allocate<ICGetElem_String>(code);
3308 }
3309
3310 // Compiler for this stub kind.
3311 class Compiler : public ICStubCompiler {
3312 protected:
3313 bool generateStubCode(MacroAssembler &masm);
3314
3315 public:
3316 Compiler(JSContext *cx)
3317 : ICStubCompiler(cx, ICStub::GetElem_String) {}
3318
3319 ICStub *getStub(ICStubSpace *space) {
3320 return ICGetElem_String::New(space, getStubCode());
3321 }
3322 };
3323 };
3324
3325 class ICGetElem_Dense : public ICMonitoredStub
3326 {
3327 friend class ICStubSpace;
3328
3329 HeapPtrShape shape_;
3330
3331 ICGetElem_Dense(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape);
3332
3333 public:
3334 static inline ICGetElem_Dense *New(ICStubSpace *space, JitCode *code,
3335 ICStub *firstMonitorStub, HandleShape shape)
3336 {
3337 if (!code)
3338 return nullptr;
3339 return space->allocate<ICGetElem_Dense>(code, firstMonitorStub, shape);
3340 }
3341
3342 static size_t offsetOfShape() {
3343 return offsetof(ICGetElem_Dense, shape_);
3344 }
3345
3346 HeapPtrShape &shape() {
3347 return shape_;
3348 }
3349
3350 class Compiler : public ICStubCompiler {
3351 ICStub *firstMonitorStub_;
3352 RootedShape shape_;
3353 bool isCallElem_;
3354
3355 protected:
3356 bool generateStubCode(MacroAssembler &masm);
3357
3358 virtual int32_t getKey() const {
3359 #if JS_HAS_NO_SUCH_METHOD
3360 return static_cast<int32_t>(kind) | (static_cast<int32_t>(isCallElem_) << 16);
3361 #else
3362 return static_cast<int32_t>(kind);
3363 #endif
3364 }
3365
3366 public:
3367 Compiler(JSContext *cx, ICStub *firstMonitorStub, Shape *shape, bool isCallElem)
3368 : ICStubCompiler(cx, ICStub::GetElem_Dense),
3369 firstMonitorStub_(firstMonitorStub),
3370 shape_(cx, shape),
3371 isCallElem_(isCallElem)
3372 {}
3373
3374 ICStub *getStub(ICStubSpace *space) {
3375 return ICGetElem_Dense::New(space, getStubCode(), firstMonitorStub_, shape_);
3376 }
3377 };
3378 };
3379
3380 class ICGetElem_TypedArray : public ICStub
3381 {
3382 friend class ICStubSpace;
3383
3384 protected: // Protected to silence Clang warning.
3385 HeapPtrShape shape_;
3386
3387 ICGetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type);
3388
3389 public:
3390 static inline ICGetElem_TypedArray *New(ICStubSpace *space, JitCode *code,
3391 HandleShape shape, uint32_t type)
3392 {
3393 if (!code)
3394 return nullptr;
3395 return space->allocate<ICGetElem_TypedArray>(code, shape, type);
3396 }
3397
3398 static size_t offsetOfShape() {
3399 return offsetof(ICGetElem_TypedArray, shape_);
3400 }
3401
3402 HeapPtrShape &shape() {
3403 return shape_;
3404 }
3405
3406 class Compiler : public ICStubCompiler {
3407 RootedShape shape_;
3408 uint32_t type_;
3409
3410 protected:
3411 bool generateStubCode(MacroAssembler &masm);
3412
3413 virtual int32_t getKey() const {
3414 return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16);
3415 }
3416
3417 public:
3418 Compiler(JSContext *cx, Shape *shape, uint32_t type)
3419 : ICStubCompiler(cx, ICStub::GetElem_TypedArray),
3420 shape_(cx, shape),
3421 type_(type)
3422 {}
3423
3424 ICStub *getStub(ICStubSpace *space) {
3425 return ICGetElem_TypedArray::New(space, getStubCode(), shape_, type_);
3426 }
3427 };
3428 };
3429
3430 class ICGetElem_Arguments : public ICMonitoredStub
3431 {
3432 friend class ICStubSpace;
3433 public:
3434 enum Which { Normal, Strict, Magic };
3435
3436 private:
3437 ICGetElem_Arguments(JitCode *stubCode, ICStub *firstMonitorStub, Which which)
3438 : ICMonitoredStub(ICStub::GetElem_Arguments, stubCode, firstMonitorStub)
3439 {
3440 extra_ = static_cast<uint16_t>(which);
3441 }
3442
3443 public:
3444 static inline ICGetElem_Arguments *New(ICStubSpace *space, JitCode *code,
3445 ICStub *firstMonitorStub, Which which)
3446 {
3447 if (!code)
3448 return nullptr;
3449 return space->allocate<ICGetElem_Arguments>(code, firstMonitorStub, which);
3450 }
3451
3452 Which which() const {
3453 return static_cast<Which>(extra_);
3454 }
3455
3456 class Compiler : public ICStubCompiler {
3457 ICStub *firstMonitorStub_;
3458 Which which_;
3459 bool isCallElem_;
3460
3461 protected:
3462 bool generateStubCode(MacroAssembler &masm);
3463
3464 virtual int32_t getKey() const {
3465 #if JS_HAS_NO_SUCH_METHOD
3466 return static_cast<int32_t>(kind) |
3467 static_cast<int32_t>(isCallElem_ << 16) |
3468 (static_cast<int32_t>(which_) << 17);
3469 #else
3470 return static_cast<int32_t>(kind) | (static_cast<int32_t>(which_) << 16);
3471 #endif
3472 }
3473
3474 public:
3475 Compiler(JSContext *cx, ICStub *firstMonitorStub, Which which, bool isCallElem)
3476 : ICStubCompiler(cx, ICStub::GetElem_Arguments),
3477 firstMonitorStub_(firstMonitorStub),
3478 which_(which),
3479 isCallElem_(isCallElem)
3480 {}
3481
3482 ICStub *getStub(ICStubSpace *space) {
3483 return ICGetElem_Arguments::New(space, getStubCode(), firstMonitorStub_, which_);
3484 }
3485 };
3486 };
3487
3488 // SetElem
3489 // JSOP_SETELEM
3490 // JSOP_INITELEM
3491
3492 class ICSetElem_Fallback : public ICFallbackStub
3493 {
3494 friend class ICStubSpace;
3495
3496 ICSetElem_Fallback(JitCode *stubCode)
3497 : ICFallbackStub(ICStub::SetElem_Fallback, stubCode)
3498 { }
3499
3500 public:
3501 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
3502
3503 static inline ICSetElem_Fallback *New(ICStubSpace *space, JitCode *code) {
3504 if (!code)
3505 return nullptr;
3506 return space->allocate<ICSetElem_Fallback>(code);
3507 }
3508
3509 void noteArrayWriteHole() {
3510 extra_ = 1;
3511 }
3512 bool hasArrayWriteHole() const {
3513 return extra_;
3514 }
3515
3516 // Compiler for this stub kind.
3517 class Compiler : public ICStubCompiler {
3518 protected:
3519 bool generateStubCode(MacroAssembler &masm);
3520
3521 public:
3522 Compiler(JSContext *cx)
3523 : ICStubCompiler(cx, ICStub::SetElem_Fallback)
3524 { }
3525
3526 ICStub *getStub(ICStubSpace *space) {
3527 return ICSetElem_Fallback::New(space, getStubCode());
3528 }
3529 };
3530 };
3531
3532 class ICSetElem_Dense : public ICUpdatedStub
3533 {
3534 friend class ICStubSpace;
3535
3536 HeapPtrShape shape_;
3537 HeapPtrTypeObject type_;
3538
3539 ICSetElem_Dense(JitCode *stubCode, HandleShape shape, HandleTypeObject type);
3540
3541 public:
3542 static inline ICSetElem_Dense *New(ICStubSpace *space, JitCode *code, HandleShape shape,
3543 HandleTypeObject type) {
3544 if (!code)
3545 return nullptr;
3546 return space->allocate<ICSetElem_Dense>(code, shape, type);
3547 }
3548
3549 static size_t offsetOfShape() {
3550 return offsetof(ICSetElem_Dense, shape_);
3551 }
3552 static size_t offsetOfType() {
3553 return offsetof(ICSetElem_Dense, type_);
3554 }
3555
3556 HeapPtrShape &shape() {
3557 return shape_;
3558 }
3559 HeapPtrTypeObject &type() {
3560 return type_;
3561 }
3562
3563 class Compiler : public ICStubCompiler {
3564 RootedShape shape_;
3565
3566 // Compiler is only live on stack during compilation, it should
3567 // outlive any RootedTypeObject it's passed. So it can just
3568 // use the handle.
3569 HandleTypeObject type_;
3570
3571 bool generateStubCode(MacroAssembler &masm);
3572
3573 public:
3574 Compiler(JSContext *cx, Shape *shape, HandleTypeObject type)
3575 : ICStubCompiler(cx, ICStub::SetElem_Dense),
3576 shape_(cx, shape),
3577 type_(type)
3578 {}
3579
3580 ICUpdatedStub *getStub(ICStubSpace *space) {
3581 ICSetElem_Dense *stub = ICSetElem_Dense::New(space, getStubCode(), shape_, type_);
3582 if (!stub || !stub->initUpdatingChain(cx, space))
3583 return nullptr;
3584 return stub;
3585 }
3586 };
3587 };
3588
3589 template <size_t ProtoChainDepth> class ICSetElem_DenseAddImpl;
3590
3591 class ICSetElem_DenseAdd : public ICUpdatedStub
3592 {
3593 friend class ICStubSpace;
3594
3595 public:
3596 static const size_t MAX_PROTO_CHAIN_DEPTH = 4;
3597
3598 protected:
3599 HeapPtrTypeObject type_;
3600
3601 ICSetElem_DenseAdd(JitCode *stubCode, types::TypeObject *type, size_t protoChainDepth);
3602
3603 public:
3604 static size_t offsetOfType() {
3605 return offsetof(ICSetElem_DenseAdd, type_);
3606 }
3607
3608 HeapPtrTypeObject &type() {
3609 return type_;
3610 }
3611 size_t protoChainDepth() const {
3612 MOZ_ASSERT(extra_ <= MAX_PROTO_CHAIN_DEPTH);
3613 return extra_;
3614 }
3615
3616 template <size_t ProtoChainDepth>
3617 ICSetElem_DenseAddImpl<ProtoChainDepth> *toImplUnchecked() {
3618 return static_cast<ICSetElem_DenseAddImpl<ProtoChainDepth> *>(this);
3619 }
3620
3621 template <size_t ProtoChainDepth>
3622 ICSetElem_DenseAddImpl<ProtoChainDepth> *toImpl() {
3623 JS_ASSERT(ProtoChainDepth == protoChainDepth());
3624 return toImplUnchecked<ProtoChainDepth>();
3625 }
3626 };
3627
3628 template <size_t ProtoChainDepth>
3629 class ICSetElem_DenseAddImpl : public ICSetElem_DenseAdd
3630 {
3631 friend class ICStubSpace;
3632
3633 static const size_t NumShapes = ProtoChainDepth + 1;
3634 mozilla::Array<HeapPtrShape, NumShapes> shapes_;
3635
3636 ICSetElem_DenseAddImpl(JitCode *stubCode, types::TypeObject *type,
3637 const AutoShapeVector *shapes)
3638 : ICSetElem_DenseAdd(stubCode, type, ProtoChainDepth)
3639 {
3640 JS_ASSERT(shapes->length() == NumShapes);
3641 for (size_t i = 0; i < NumShapes; i++)
3642 shapes_[i].init((*shapes)[i]);
3643 }
3644
3645 public:
3646 static inline ICSetElem_DenseAddImpl *New(ICStubSpace *space, JitCode *code,
3647 types::TypeObject *type,
3648 const AutoShapeVector *shapes)
3649 {
3650 if (!code)
3651 return nullptr;
3652 return space->allocate<ICSetElem_DenseAddImpl<ProtoChainDepth> >(code, type, shapes);
3653 }
3654
3655 void traceShapes(JSTracer *trc) {
3656 for (size_t i = 0; i < NumShapes; i++)
3657 MarkShape(trc, &shapes_[i], "baseline-setelem-denseadd-stub-shape");
3658 }
3659 Shape *shape(size_t i) const {
3660 JS_ASSERT(i < NumShapes);
3661 return shapes_[i];
3662 }
3663 static size_t offsetOfShape(size_t idx) {
3664 return offsetof(ICSetElem_DenseAddImpl, shapes_) + idx * sizeof(HeapPtrShape);
3665 }
3666 };
3667
3668 class ICSetElemDenseAddCompiler : public ICStubCompiler {
3669 RootedObject obj_;
3670 size_t protoChainDepth_;
3671
3672 bool generateStubCode(MacroAssembler &masm);
3673
3674 protected:
3675 virtual int32_t getKey() const {
3676 return static_cast<int32_t>(kind) | (static_cast<int32_t>(protoChainDepth_) << 16);
3677 }
3678
3679 public:
3680 ICSetElemDenseAddCompiler(JSContext *cx, HandleObject obj, size_t protoChainDepth)
3681 : ICStubCompiler(cx, ICStub::SetElem_DenseAdd),
3682 obj_(cx, obj),
3683 protoChainDepth_(protoChainDepth)
3684 {}
3685
3686 template <size_t ProtoChainDepth>
3687 ICUpdatedStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes);
3688
3689 ICUpdatedStub *getStub(ICStubSpace *space);
3690 };
3691
3692 class ICSetElem_TypedArray : public ICStub
3693 {
3694 friend class ICStubSpace;
3695
3696 protected: // Protected to silence Clang warning.
3697 HeapPtrShape shape_;
3698
3699 ICSetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type,
3700 bool expectOutOfBounds);
3701
3702 public:
3703 static inline ICSetElem_TypedArray *New(ICStubSpace *space, JitCode *code,
3704 HandleShape shape, uint32_t type,
3705 bool expectOutOfBounds)
3706 {
3707 if (!code)
3708 return nullptr;
3709 return space->allocate<ICSetElem_TypedArray>(code, shape, type, expectOutOfBounds);
3710 }
3711
3712 uint32_t type() const {
3713 return extra_ & 0xff;
3714 }
3715
3716 bool expectOutOfBounds() const {
3717 return (extra_ >> 8) & 1;
3718 }
3719
3720 static size_t offsetOfShape() {
3721 return offsetof(ICSetElem_TypedArray, shape_);
3722 }
3723
3724 HeapPtrShape &shape() {
3725 return shape_;
3726 }
3727
3728 class Compiler : public ICStubCompiler {
3729 RootedShape shape_;
3730 uint32_t type_;
3731 bool expectOutOfBounds_;
3732
3733 protected:
3734 bool generateStubCode(MacroAssembler &masm);
3735
3736 virtual int32_t getKey() const {
3737 return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16) |
3738 (static_cast<int32_t>(expectOutOfBounds_) << 24);
3739 }
3740
3741 public:
3742 Compiler(JSContext *cx, Shape *shape, uint32_t type, bool expectOutOfBounds)
3743 : ICStubCompiler(cx, ICStub::SetElem_TypedArray),
3744 shape_(cx, shape),
3745 type_(type),
3746 expectOutOfBounds_(expectOutOfBounds)
3747 {}
3748
3749 ICStub *getStub(ICStubSpace *space) {
3750 return ICSetElem_TypedArray::New(space, getStubCode(), shape_, type_,
3751 expectOutOfBounds_);
3752 }
3753 };
3754 };
3755
3756 // In
3757 // JSOP_IN
3758 class ICIn_Fallback : public ICFallbackStub
3759 {
3760 friend class ICStubSpace;
3761
3762 ICIn_Fallback(JitCode *stubCode)
3763 : ICFallbackStub(ICStub::In_Fallback, stubCode)
3764 { }
3765
3766 public:
3767 static inline ICIn_Fallback *New(ICStubSpace *space, JitCode *code) {
3768 if (!code)
3769 return nullptr;
3770 return space->allocate<ICIn_Fallback>(code);
3771 }
3772
3773 class Compiler : public ICStubCompiler {
3774 protected:
3775 bool generateStubCode(MacroAssembler &masm);
3776
3777 public:
3778 Compiler(JSContext *cx)
3779 : ICStubCompiler(cx, ICStub::In_Fallback)
3780 { }
3781
3782 ICStub *getStub(ICStubSpace *space) {
3783 return ICIn_Fallback::New(space, getStubCode());
3784 }
3785 };
3786 };
3787
3788 // GetName
3789 // JSOP_NAME
3790 // JSOP_GETGNAME
3791 class ICGetName_Fallback : public ICMonitoredFallbackStub
3792 {
3793 friend class ICStubSpace;
3794
3795 ICGetName_Fallback(JitCode *stubCode)
3796 : ICMonitoredFallbackStub(ICStub::GetName_Fallback, stubCode)
3797 { }
3798
3799 public:
3800 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
3801
3802 static inline ICGetName_Fallback *New(ICStubSpace *space, JitCode *code) {
3803 if (!code)
3804 return nullptr;
3805 return space->allocate<ICGetName_Fallback>(code);
3806 }
3807
3808 class Compiler : public ICStubCompiler {
3809 protected:
3810 bool generateStubCode(MacroAssembler &masm);
3811
3812 public:
3813 Compiler(JSContext *cx)
3814 : ICStubCompiler(cx, ICStub::GetName_Fallback)
3815 { }
3816
3817 ICStub *getStub(ICStubSpace *space) {
3818 ICGetName_Fallback *stub = ICGetName_Fallback::New(space, getStubCode());
3819 if (!stub || !stub->initMonitoringChain(cx, space))
3820 return nullptr;
3821 return stub;
3822 }
3823 };
3824 };
3825
3826 // Optimized GETGNAME/CALLGNAME stub.
3827 class ICGetName_Global : public ICMonitoredStub
3828 {
3829 friend class ICStubSpace;
3830
3831 protected: // Protected to silence Clang warning.
3832 HeapPtrShape shape_;
3833 uint32_t slot_;
3834
3835 ICGetName_Global(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape, uint32_t slot);
3836
3837 public:
3838 static inline ICGetName_Global *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
3839 HandleShape shape, uint32_t slot)
3840 {
3841 if (!code)
3842 return nullptr;
3843 return space->allocate<ICGetName_Global>(code, firstMonitorStub, shape, slot);
3844 }
3845
3846 HeapPtrShape &shape() {
3847 return shape_;
3848 }
3849 static size_t offsetOfShape() {
3850 return offsetof(ICGetName_Global, shape_);
3851 }
3852 static size_t offsetOfSlot() {
3853 return offsetof(ICGetName_Global, slot_);
3854 }
3855
3856 class Compiler : public ICStubCompiler {
3857 ICStub *firstMonitorStub_;
3858 RootedShape shape_;
3859 uint32_t slot_;
3860
3861 protected:
3862 bool generateStubCode(MacroAssembler &masm);
3863
3864 public:
3865 Compiler(JSContext *cx, ICStub *firstMonitorStub, Shape *shape, uint32_t slot)
3866 : ICStubCompiler(cx, ICStub::GetName_Global),
3867 firstMonitorStub_(firstMonitorStub),
3868 shape_(cx, shape),
3869 slot_(slot)
3870 {}
3871
3872 ICStub *getStub(ICStubSpace *space) {
3873 return ICGetName_Global::New(space, getStubCode(), firstMonitorStub_, shape_, slot_);
3874 }
3875 };
3876 };
3877
3878 // Optimized GETNAME/CALLNAME stub, making a variable number of hops to get an
3879 // 'own' property off some scope object. Unlike GETPROP on an object's
3880 // prototype, there is no teleporting optimization to take advantage of and
3881 // shape checks are required all along the scope chain.
3882 template <size_t NumHops>
3883 class ICGetName_Scope : public ICMonitoredStub
3884 {
3885 friend class ICStubSpace;
3886
3887 static const size_t MAX_HOPS = 6;
3888
3889 mozilla::Array<HeapPtrShape, NumHops + 1> shapes_;
3890 uint32_t offset_;
3891
3892 ICGetName_Scope(JitCode *stubCode, ICStub *firstMonitorStub,
3893 AutoShapeVector *shapes, uint32_t offset);
3894
3895 static Kind GetStubKind() {
3896 return (Kind) (GetName_Scope0 + NumHops);
3897 }
3898
3899 public:
3900 static inline ICGetName_Scope *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
3901 AutoShapeVector *shapes, uint32_t offset)
3902 {
3903 if (!code)
3904 return nullptr;
3905 return space->allocate<ICGetName_Scope<NumHops> >(code, firstMonitorStub, shapes, offset);
3906 }
3907
3908 void traceScopes(JSTracer *trc) {
3909 for (size_t i = 0; i < NumHops + 1; i++)
3910 MarkShape(trc, &shapes_[i], "baseline-scope-stub-shape");
3911 }
3912
3913 static size_t offsetOfShape(size_t index) {
3914 JS_ASSERT(index <= NumHops);
3915 return offsetof(ICGetName_Scope, shapes_) + (index * sizeof(HeapPtrShape));
3916 }
3917 static size_t offsetOfOffset() {
3918 return offsetof(ICGetName_Scope, offset_);
3919 }
3920
3921 class Compiler : public ICStubCompiler {
3922 ICStub *firstMonitorStub_;
3923 AutoShapeVector *shapes_;
3924 bool isFixedSlot_;
3925 uint32_t offset_;
3926
3927 protected:
3928 bool generateStubCode(MacroAssembler &masm);
3929
3930 protected:
3931 virtual int32_t getKey() const {
3932 return static_cast<int32_t>(kind) | (static_cast<int32_t>(isFixedSlot_) << 16);
3933 }
3934
3935 public:
3936 Compiler(JSContext *cx, ICStub *firstMonitorStub,
3937 AutoShapeVector *shapes, bool isFixedSlot, uint32_t offset)
3938 : ICStubCompiler(cx, GetStubKind()),
3939 firstMonitorStub_(firstMonitorStub),
3940 shapes_(shapes),
3941 isFixedSlot_(isFixedSlot),
3942 offset_(offset)
3943 {
3944 }
3945
3946 ICStub *getStub(ICStubSpace *space) {
3947 return ICGetName_Scope::New(space, getStubCode(), firstMonitorStub_, shapes_, offset_);
3948 }
3949 };
3950 };
3951
3952 // BindName
3953 // JSOP_BINDNAME
3954 class ICBindName_Fallback : public ICFallbackStub
3955 {
3956 friend class ICStubSpace;
3957
3958 ICBindName_Fallback(JitCode *stubCode)
3959 : ICFallbackStub(ICStub::BindName_Fallback, stubCode)
3960 { }
3961
3962 public:
3963 static inline ICBindName_Fallback *New(ICStubSpace *space, JitCode *code) {
3964 if (!code)
3965 return nullptr;
3966 return space->allocate<ICBindName_Fallback>(code);
3967 }
3968
3969 class Compiler : public ICStubCompiler {
3970 protected:
3971 bool generateStubCode(MacroAssembler &masm);
3972
3973 public:
3974 Compiler(JSContext *cx)
3975 : ICStubCompiler(cx, ICStub::BindName_Fallback)
3976 { }
3977
3978 ICStub *getStub(ICStubSpace *space) {
3979 return ICBindName_Fallback::New(space, getStubCode());
3980 }
3981 };
3982 };
3983
3984 // GetIntrinsic
3985 // JSOP_GETINTRINSIC
3986 class ICGetIntrinsic_Fallback : public ICMonitoredFallbackStub
3987 {
3988 friend class ICStubSpace;
3989
3990 ICGetIntrinsic_Fallback(JitCode *stubCode)
3991 : ICMonitoredFallbackStub(ICStub::GetIntrinsic_Fallback, stubCode)
3992 { }
3993
3994 public:
3995 static inline ICGetIntrinsic_Fallback *New(ICStubSpace *space, JitCode *code) {
3996 if (!code)
3997 return nullptr;
3998 return space->allocate<ICGetIntrinsic_Fallback>(code);
3999 }
4000
4001 class Compiler : public ICStubCompiler {
4002 protected:
4003 bool generateStubCode(MacroAssembler &masm);
4004
4005 public:
4006 Compiler(JSContext *cx)
4007 : ICStubCompiler(cx, ICStub::GetIntrinsic_Fallback)
4008 { }
4009
4010 ICStub *getStub(ICStubSpace *space) {
4011 ICGetIntrinsic_Fallback *stub = ICGetIntrinsic_Fallback::New(space, getStubCode());
4012 if (!stub || !stub->initMonitoringChain(cx, space))
4013 return nullptr;
4014 return stub;
4015 }
4016 };
4017 };
4018
4019 // Stub that loads the constant result of a GETINTRINSIC operation.
4020 class ICGetIntrinsic_Constant : public ICStub
4021 {
4022 friend class ICStubSpace;
4023
4024 HeapValue value_;
4025
4026 ICGetIntrinsic_Constant(JitCode *stubCode, HandleValue value);
4027 ~ICGetIntrinsic_Constant();
4028
4029 public:
4030 static inline ICGetIntrinsic_Constant *New(ICStubSpace *space, JitCode *code,
4031 HandleValue value)
4032 {
4033 if (!code)
4034 return nullptr;
4035 return space->allocate<ICGetIntrinsic_Constant>(code, value);
4036 }
4037
4038 HeapValue &value() {
4039 return value_;
4040 }
4041 static size_t offsetOfValue() {
4042 return offsetof(ICGetIntrinsic_Constant, value_);
4043 }
4044
4045 class Compiler : public ICStubCompiler {
4046 bool generateStubCode(MacroAssembler &masm);
4047
4048 HandleValue value_;
4049
4050 public:
4051 Compiler(JSContext *cx, HandleValue value)
4052 : ICStubCompiler(cx, ICStub::GetIntrinsic_Constant),
4053 value_(value)
4054 {}
4055
4056 ICStub *getStub(ICStubSpace *space) {
4057 return ICGetIntrinsic_Constant::New(space, getStubCode(), value_);
4058 }
4059 };
4060 };
4061
4062 class ICGetProp_Fallback : public ICMonitoredFallbackStub
4063 {
4064 friend class ICStubSpace;
4065
4066 ICGetProp_Fallback(JitCode *stubCode)
4067 : ICMonitoredFallbackStub(ICStub::GetProp_Fallback, stubCode)
4068 { }
4069
4070 public:
4071 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
4072
4073 static inline ICGetProp_Fallback *New(ICStubSpace *space, JitCode *code) {
4074 if (!code)
4075 return nullptr;
4076 return space->allocate<ICGetProp_Fallback>(code);
4077 }
4078
4079 static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
4080 static const size_t ACCESSED_GETTER_BIT = 1;
4081
4082 void noteUnoptimizableAccess() {
4083 extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
4084 }
4085 bool hadUnoptimizableAccess() const {
4086 return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
4087 }
4088
4089 void noteAccessedGetter() {
4090 extra_ |= (1u << ACCESSED_GETTER_BIT);
4091 }
4092 bool hasAccessedGetter() const {
4093 return extra_ & (1u << ACCESSED_GETTER_BIT);
4094 }
4095
4096 class Compiler : public ICStubCompiler {
4097 protected:
4098 uint32_t returnFromIonOffset_;
4099 uint32_t returnFromStubOffset_;
4100 bool generateStubCode(MacroAssembler &masm);
4101 bool postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code);
4102
4103 public:
4104 Compiler(JSContext *cx)
4105 : ICStubCompiler(cx, ICStub::GetProp_Fallback)
4106 { }
4107
4108 ICStub *getStub(ICStubSpace *space) {
4109 ICGetProp_Fallback *stub = ICGetProp_Fallback::New(space, getStubCode());
4110 if (!stub || !stub->initMonitoringChain(cx, space))
4111 return nullptr;
4112 return stub;
4113 }
4114 };
4115 };
4116
4117 // Stub for accessing a dense array's length.
4118 class ICGetProp_ArrayLength : public ICStub
4119 {
4120 friend class ICStubSpace;
4121
4122 ICGetProp_ArrayLength(JitCode *stubCode)
4123 : ICStub(GetProp_ArrayLength, stubCode)
4124 {}
4125
4126 public:
4127 static inline ICGetProp_ArrayLength *New(ICStubSpace *space, JitCode *code) {
4128 if (!code)
4129 return nullptr;
4130 return space->allocate<ICGetProp_ArrayLength>(code);
4131 }
4132
4133 class Compiler : public ICStubCompiler {
4134 bool generateStubCode(MacroAssembler &masm);
4135
4136 public:
4137 Compiler(JSContext *cx)
4138 : ICStubCompiler(cx, ICStub::GetProp_ArrayLength)
4139 {}
4140
4141 ICStub *getStub(ICStubSpace *space) {
4142 return ICGetProp_ArrayLength::New(space, getStubCode());
4143 }
4144 };
4145 };
4146
4147 // Stub for accessing a typed array's length.
4148 class ICGetProp_TypedArrayLength : public ICStub
4149 {
4150 friend class ICStubSpace;
4151
4152 ICGetProp_TypedArrayLength(JitCode *stubCode)
4153 : ICStub(GetProp_TypedArrayLength, stubCode)
4154 {}
4155
4156 public:
4157 static inline ICGetProp_TypedArrayLength *New(ICStubSpace *space, JitCode *code) {
4158 if (!code)
4159 return nullptr;
4160 return space->allocate<ICGetProp_TypedArrayLength>(code);
4161 }
4162
4163 class Compiler : public ICStubCompiler {
4164 bool generateStubCode(MacroAssembler &masm);
4165
4166 public:
4167 Compiler(JSContext *cx)
4168 : ICStubCompiler(cx, ICStub::GetProp_TypedArrayLength)
4169 {}
4170
4171 ICStub *getStub(ICStubSpace *space) {
4172 return ICGetProp_TypedArrayLength::New(space, getStubCode());
4173 }
4174 };
4175 };
4176
4177 // Stub for accessing a property on a primitive's prototype.
4178 class ICGetProp_Primitive : public ICMonitoredStub
4179 {
4180 friend class ICStubSpace;
4181
4182 protected: // Protected to silence Clang warning.
4183 // Shape of String.prototype/Number.prototype to check for.
4184 HeapPtrShape protoShape_;
4185
4186 // Fixed or dynamic slot offset.
4187 uint32_t offset_;
4188
4189 ICGetProp_Primitive(JitCode *stubCode, ICStub *firstMonitorStub,
4190 HandleShape protoShape, uint32_t offset);
4191
4192 public:
4193 static inline ICGetProp_Primitive *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
4194 HandleShape protoShape, uint32_t offset)
4195 {
4196 if (!code)
4197 return nullptr;
4198 return space->allocate<ICGetProp_Primitive>(code, firstMonitorStub, protoShape, offset);
4199 }
4200
4201 HeapPtrShape &protoShape() {
4202 return protoShape_;
4203 }
4204 static size_t offsetOfProtoShape() {
4205 return offsetof(ICGetProp_Primitive, protoShape_);
4206 }
4207
4208 static size_t offsetOfOffset() {
4209 return offsetof(ICGetProp_Primitive, offset_);
4210 }
4211
4212 class Compiler : public ICStubCompiler {
4213 ICStub *firstMonitorStub_;
4214 JSValueType primitiveType_;
4215 RootedObject prototype_;
4216 bool isFixedSlot_;
4217 uint32_t offset_;
4218
4219 bool generateStubCode(MacroAssembler &masm);
4220
4221 protected:
4222 virtual int32_t getKey() const {
4223 static_assert(sizeof(JSValueType) == 1, "JSValueType should fit in one byte");
4224 return static_cast<int32_t>(kind)
4225 | (static_cast<int32_t>(isFixedSlot_) << 16)
4226 | (static_cast<int32_t>(primitiveType_) << 24);
4227 }
4228
4229 public:
4230 Compiler(JSContext *cx, ICStub *firstMonitorStub, JSValueType primitiveType,
4231 HandleObject prototype, bool isFixedSlot, uint32_t offset)
4232 : ICStubCompiler(cx, ICStub::GetProp_Primitive),
4233 firstMonitorStub_(firstMonitorStub),
4234 primitiveType_(primitiveType),
4235 prototype_(cx, prototype),
4236 isFixedSlot_(isFixedSlot),
4237 offset_(offset)
4238 {}
4239
4240 ICStub *getStub(ICStubSpace *space) {
4241 RootedShape protoShape(cx, prototype_->lastProperty());
4242 return ICGetProp_Primitive::New(space, getStubCode(), firstMonitorStub_,
4243 protoShape, offset_);
4244 }
4245 };
4246 };
4247
4248 // Stub for accessing a string's length.
4249 class ICGetProp_StringLength : public ICStub
4250 {
4251 friend class ICStubSpace;
4252
4253 ICGetProp_StringLength(JitCode *stubCode)
4254 : ICStub(GetProp_StringLength, stubCode)
4255 {}
4256
4257 public:
4258 static inline ICGetProp_StringLength *New(ICStubSpace *space, JitCode *code) {
4259 if (!code)
4260 return nullptr;
4261 return space->allocate<ICGetProp_StringLength>(code);
4262 }
4263
4264 class Compiler : public ICStubCompiler {
4265 bool generateStubCode(MacroAssembler &masm);
4266
4267 public:
4268 Compiler(JSContext *cx)
4269 : ICStubCompiler(cx, ICStub::GetProp_StringLength)
4270 {}
4271
4272 ICStub *getStub(ICStubSpace *space) {
4273 return ICGetProp_StringLength::New(space, getStubCode());
4274 }
4275 };
4276 };
4277
4278 // Base class for GetProp_Native and GetProp_NativePrototype stubs.
4279 class ICGetPropNativeStub : public ICMonitoredStub
4280 {
4281 // Object shape (lastProperty).
4282 HeapPtrShape shape_;
4283
4284 // Fixed or dynamic slot offset.
4285 uint32_t offset_;
4286
4287 protected:
4288 ICGetPropNativeStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
4289 HandleShape shape, uint32_t offset);
4290
4291 public:
4292 HeapPtrShape &shape() {
4293 return shape_;
4294 }
4295 uint32_t offset() const {
4296 return offset_;
4297 }
4298 static size_t offsetOfShape() {
4299 return offsetof(ICGetPropNativeStub, shape_);
4300 }
4301 static size_t offsetOfOffset() {
4302 return offsetof(ICGetPropNativeStub, offset_);
4303 }
4304 };
4305
4306 // Stub for accessing an own property on a native object.
4307 class ICGetProp_Native : public ICGetPropNativeStub
4308 {
4309 friend class ICStubSpace;
4310
4311 ICGetProp_Native(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
4312 uint32_t offset)
4313 : ICGetPropNativeStub(GetProp_Native, stubCode, firstMonitorStub, shape, offset)
4314 {}
4315
4316 public:
4317 static inline ICGetProp_Native *New(ICStubSpace *space, JitCode *code,
4318 ICStub *firstMonitorStub, HandleShape shape,
4319 uint32_t offset)
4320 {
4321 if (!code)
4322 return nullptr;
4323 return space->allocate<ICGetProp_Native>(code, firstMonitorStub, shape, offset);
4324 }
4325 };
4326
4327 // Stub for accessing a property on a native object's prototype. Note that due to
4328 // the shape teleporting optimization, we only have to guard on the object's shape
4329 // and the holder's shape.
4330 class ICGetProp_NativePrototype : public ICGetPropNativeStub
4331 {
4332 friend class ICStubSpace;
4333
4334 protected:
4335 // Holder and its shape.
4336 HeapPtrObject holder_;
4337 HeapPtrShape holderShape_;
4338
4339 ICGetProp_NativePrototype(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
4340 uint32_t offset, HandleObject holder, HandleShape holderShape);
4341
4342 public:
4343 static inline ICGetProp_NativePrototype *New(ICStubSpace *space, JitCode *code,
4344 ICStub *firstMonitorStub, HandleShape shape,
4345 uint32_t offset, HandleObject holder,
4346 HandleShape holderShape)
4347 {
4348 if (!code)
4349 return nullptr;
4350 return space->allocate<ICGetProp_NativePrototype>(code, firstMonitorStub, shape, offset,
4351 holder, holderShape);
4352 }
4353
4354 public:
4355 HeapPtrObject &holder() {
4356 return holder_;
4357 }
4358 HeapPtrShape &holderShape() {
4359 return holderShape_;
4360 }
4361 static size_t offsetOfHolder() {
4362 return offsetof(ICGetProp_NativePrototype, holder_);
4363 }
4364 static size_t offsetOfHolderShape() {
4365 return offsetof(ICGetProp_NativePrototype, holderShape_);
4366 }
4367 };
4368
4369
4370 // Compiler for GetProp_Native and GetProp_NativePrototype stubs.
4371 class ICGetPropNativeCompiler : public ICStubCompiler
4372 {
4373 bool isCallProp_;
4374 ICStub *firstMonitorStub_;
4375 HandleObject obj_;
4376 HandleObject holder_;
4377 HandlePropertyName propName_;
4378 bool isFixedSlot_;
4379 uint32_t offset_;
4380
4381 bool generateStubCode(MacroAssembler &masm);
4382
4383 protected:
4384 virtual int32_t getKey() const {
4385 #if JS_HAS_NO_SUCH_METHOD
4386 return static_cast<int32_t>(kind) |
4387 (static_cast<int32_t>(isCallProp_) << 16) |
4388 (static_cast<int32_t>(isFixedSlot_) << 17);
4389 #else
4390 return static_cast<int32_t>(kind) | (static_cast<int32_t>(isFixedSlot_) << 16);
4391 #endif
4392 }
4393
4394 public:
4395 ICGetPropNativeCompiler(JSContext *cx, ICStub::Kind kind, bool isCallProp,
4396 ICStub *firstMonitorStub, HandleObject obj, HandleObject holder,
4397 HandlePropertyName propName, bool isFixedSlot, uint32_t offset)
4398 : ICStubCompiler(cx, kind),
4399 isCallProp_(isCallProp),
4400 firstMonitorStub_(firstMonitorStub),
4401 obj_(obj),
4402 holder_(holder),
4403 propName_(propName),
4404 isFixedSlot_(isFixedSlot),
4405 offset_(offset)
4406 {}
4407
4408 ICStub *getStub(ICStubSpace *space) {
4409 RootedShape shape(cx, obj_->lastProperty());
4410 if (kind == ICStub::GetProp_Native) {
4411 JS_ASSERT(obj_ == holder_);
4412 return ICGetProp_Native::New(space, getStubCode(), firstMonitorStub_, shape, offset_);
4413 }
4414
4415 JS_ASSERT(obj_ != holder_);
4416 JS_ASSERT(kind == ICStub::GetProp_NativePrototype);
4417 RootedShape holderShape(cx, holder_->lastProperty());
4418 return ICGetProp_NativePrototype::New(space, getStubCode(), firstMonitorStub_, shape,
4419 offset_, holder_, holderShape);
4420 }
4421 };
4422
4423 class ICGetPropCallGetter : public ICMonitoredStub
4424 {
4425 friend class ICStubSpace;
4426
4427 protected:
4428 // We don't strictly need this for own property getters, but we need it to do
4429 // Ion optimizations, so we should keep it around.
4430 HeapPtrObject holder_;
4431
4432 HeapPtrShape holderShape_;
4433
4434 // Function to call.
4435 HeapPtrFunction getter_;
4436
4437 // PC offset of call
4438 uint32_t pcOffset_;
4439
4440 ICGetPropCallGetter(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, HandleObject holder,
4441 HandleShape holderShape, HandleFunction getter, uint32_t pcOffset);
4442
4443 public:
4444 HeapPtrObject &holder() {
4445 return holder_;
4446 }
4447 HeapPtrShape &holderShape() {
4448 return holderShape_;
4449 }
4450 HeapPtrFunction &getter() {
4451 return getter_;
4452 }
4453
4454 static size_t offsetOfHolder() {
4455 return offsetof(ICGetPropCallGetter, holder_);
4456 }
4457 static size_t offsetOfHolderShape() {
4458 return offsetof(ICGetPropCallGetter, holderShape_);
4459 }
4460 static size_t offsetOfGetter() {
4461 return offsetof(ICGetPropCallGetter, getter_);
4462 }
4463 static size_t offsetOfPCOffset() {
4464 return offsetof(ICGetPropCallGetter, pcOffset_);
4465 }
4466
4467 class Compiler : public ICStubCompiler {
4468 protected:
4469 ICStub *firstMonitorStub_;
4470 RootedObject holder_;
4471 RootedFunction getter_;
4472 uint32_t pcOffset_;
4473
4474 public:
4475 Compiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub,
4476 HandleObject holder, HandleFunction getter, uint32_t pcOffset)
4477 : ICStubCompiler(cx, kind),
4478 firstMonitorStub_(firstMonitorStub),
4479 holder_(cx, holder),
4480 getter_(cx, getter),
4481 pcOffset_(pcOffset)
4482 {
4483 JS_ASSERT(kind == ICStub::GetProp_CallScripted ||
4484 kind == ICStub::GetProp_CallNative ||
4485 kind == ICStub::GetProp_CallNativePrototype);
4486 }
4487 };
4488 };
4489
4490 // Stub for calling a getter (native or scripted) on a native object when the getter is kept on
4491 // the proto-chain.
4492 class ICGetPropCallPrototypeGetter : public ICGetPropCallGetter
4493 {
4494 friend class ICStubSpace;
4495
4496 protected:
4497 // shape of receiver object.
4498 HeapPtrShape receiverShape_;
4499
4500 ICGetPropCallPrototypeGetter(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub,
4501 HandleShape receiverShape,
4502 HandleObject holder, HandleShape holderShape,
4503 HandleFunction getter, uint32_t pcOffset);
4504
4505 public:
4506 HeapPtrShape &receiverShape() {
4507 return receiverShape_;
4508 }
4509
4510 static size_t offsetOfReceiverShape() {
4511 return offsetof(ICGetPropCallPrototypeGetter, receiverShape_);
4512 }
4513
4514 class Compiler : public ICGetPropCallGetter::Compiler {
4515 protected:
4516 RootedObject receiver_;
4517
4518 public:
4519 Compiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub,
4520 HandleObject obj, HandleObject holder, HandleFunction getter, uint32_t pcOffset)
4521 : ICGetPropCallGetter::Compiler(cx, kind, firstMonitorStub, holder, getter, pcOffset),
4522 receiver_(cx, obj)
4523 {
4524 JS_ASSERT(kind == ICStub::GetProp_CallScripted ||
4525 kind == ICStub::GetProp_CallNativePrototype);
4526 }
4527 };
4528 };
4529
4530 // Stub for calling a scripted getter on a native object when the getter is kept on the
4531 // proto-chain.
4532 class ICGetProp_CallScripted : public ICGetPropCallPrototypeGetter
4533 {
4534 friend class ICStubSpace;
4535
4536 protected:
4537 ICGetProp_CallScripted(JitCode *stubCode, ICStub *firstMonitorStub,
4538 HandleShape receiverShape, HandleObject holder, HandleShape holderShape,
4539 HandleFunction getter, uint32_t pcOffset)
4540 : ICGetPropCallPrototypeGetter(GetProp_CallScripted, stubCode, firstMonitorStub,
4541 receiverShape, holder, holderShape, getter, pcOffset)
4542 {}
4543
4544 public:
4545 static inline ICGetProp_CallScripted *New(
4546 ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
4547 HandleShape receiverShape, HandleObject holder, HandleShape holderShape,
4548 HandleFunction getter, uint32_t pcOffset)
4549 {
4550 if (!code)
4551 return nullptr;
4552 return space->allocate<ICGetProp_CallScripted>(code, firstMonitorStub,
4553 receiverShape, holder, holderShape, getter,
4554 pcOffset);
4555 }
4556
4557 class Compiler : public ICGetPropCallPrototypeGetter::Compiler {
4558 protected:
4559 bool generateStubCode(MacroAssembler &masm);
4560
4561 public:
4562 Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj,
4563 HandleObject holder, HandleFunction getter, uint32_t pcOffset)
4564 : ICGetPropCallPrototypeGetter::Compiler(cx, ICStub::GetProp_CallScripted,
4565 firstMonitorStub, obj, holder,
4566 getter, pcOffset)
4567 {}
4568
4569 ICStub *getStub(ICStubSpace *space) {
4570 RootedShape receiverShape(cx, receiver_->lastProperty());
4571 RootedShape holderShape(cx, holder_->lastProperty());
4572 return ICGetProp_CallScripted::New(space, getStubCode(), firstMonitorStub_, receiverShape,
4573 holder_, holderShape, getter_, pcOffset_);
4574 }
4575 };
4576 };
4577
4578 // Stub for calling an own native getter on a native object.
4579 class ICGetProp_CallNative : public ICGetPropCallGetter
4580 {
4581 friend class ICStubSpace;
4582
4583 protected:
4584
4585 ICGetProp_CallNative(JitCode *stubCode, ICStub *firstMonitorStub, HandleObject obj,
4586 HandleShape shape, HandleFunction getter, uint32_t pcOffset)
4587 : ICGetPropCallGetter(GetProp_CallNative, stubCode, firstMonitorStub, obj, shape,
4588 getter, pcOffset)
4589 { }
4590
4591 public:
4592 static inline ICGetProp_CallNative *New(ICStubSpace *space, JitCode *code,
4593 ICStub *firstMonitorStub, HandleObject obj,
4594 HandleShape shape, HandleFunction getter,
4595 uint32_t pcOffset)
4596 {
4597 if (!code)
4598 return nullptr;
4599 return space->allocate<ICGetProp_CallNative>(code, firstMonitorStub, obj, shape,
4600 getter, pcOffset);
4601 }
4602
4603 class Compiler : public ICGetPropCallGetter::Compiler
4604 {
4605 bool inputDefinitelyObject_;
4606 protected:
4607 bool generateStubCode(MacroAssembler &masm);
4608
4609 virtual int32_t getKey() const {
4610 return static_cast<int32_t>(kind) |
4611 (static_cast<int32_t>(inputDefinitelyObject_) << 16);
4612 }
4613
4614 public:
4615 Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj,
4616 HandleFunction getter, uint32_t pcOffset, bool inputDefinitelyObject = false)
4617 : ICGetPropCallGetter::Compiler(cx, ICStub::GetProp_CallNative, firstMonitorStub,
4618 obj, getter, pcOffset),
4619 inputDefinitelyObject_(inputDefinitelyObject)
4620 {}
4621
4622 ICStub *getStub(ICStubSpace *space) {
4623 RootedShape shape(cx, holder_->lastProperty());
4624 return ICGetProp_CallNative::New(space, getStubCode(), firstMonitorStub_, holder_,
4625 shape, getter_, pcOffset_);
4626 }
4627 };
4628 };
4629
4630 // Stub for calling an native getter on a native object when the getter is kept on the proto-chain.
4631 class ICGetProp_CallNativePrototype : public ICGetPropCallPrototypeGetter
4632 {
4633 friend class ICStubSpace;
4634
4635 protected:
4636 ICGetProp_CallNativePrototype(JitCode *stubCode, ICStub *firstMonitorStub,
4637 HandleShape receiverShape, HandleObject holder, HandleShape holderShape,
4638 HandleFunction getter, uint32_t pcOffset)
4639 : ICGetPropCallPrototypeGetter(GetProp_CallNativePrototype, stubCode, firstMonitorStub,
4640 receiverShape, holder, holderShape, getter, pcOffset)
4641 {}
4642
4643 public:
4644 static inline ICGetProp_CallNativePrototype *New(
4645 ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
4646 HandleShape receiverShape, HandleObject holder, HandleShape holderShape,
4647 HandleFunction getter, uint32_t pcOffset)
4648 {
4649 if (!code)
4650 return nullptr;
4651 return space->allocate<ICGetProp_CallNativePrototype>(code, firstMonitorStub,
4652 receiverShape, holder, holderShape,
4653 getter, pcOffset);
4654 }
4655
4656 class Compiler : public ICGetPropCallPrototypeGetter::Compiler {
4657 protected:
4658 bool generateStubCode(MacroAssembler &masm);
4659
4660 public:
4661 Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj,
4662 HandleObject holder, HandleFunction getter, uint32_t pcOffset)
4663 : ICGetPropCallPrototypeGetter::Compiler(cx, ICStub::GetProp_CallNativePrototype,
4664 firstMonitorStub, obj, holder,
4665 getter, pcOffset)
4666 {}
4667
4668 ICStub *getStub(ICStubSpace *space) {
4669 RootedShape receiverShape(cx, receiver_->lastProperty());
4670 RootedShape holderShape(cx, holder_->lastProperty());
4671 return ICGetProp_CallNativePrototype::New(space, getStubCode(), firstMonitorStub_, receiverShape,
4672 holder_, holderShape, getter_, pcOffset_);
4673 }
4674 };
4675 };
4676
4677 class ICGetPropCallDOMProxyNativeStub : public ICMonitoredStub
4678 {
4679 friend class ICStubSpace;
4680 protected:
4681 // Shape of the DOMProxy
4682 HeapPtrShape shape_;
4683
4684 // Proxy handler to check against.
4685 BaseProxyHandler *proxyHandler_;
4686
4687 // Object shape of expected expando object. (nullptr if no expando object should be there)
4688 HeapPtrShape expandoShape_;
4689
4690 // Holder and its shape.
4691 HeapPtrObject holder_;
4692 HeapPtrShape holderShape_;
4693
4694 // Function to call.
4695 HeapPtrFunction getter_;
4696
4697 // PC offset of call
4698 uint32_t pcOffset_;
4699
4700 ICGetPropCallDOMProxyNativeStub(ICStub::Kind kind, JitCode *stubCode,
4701 ICStub *firstMonitorStub, HandleShape shape,
4702 BaseProxyHandler *proxyHandler, HandleShape expandoShape,
4703 HandleObject holder, HandleShape holderShape,
4704 HandleFunction getter, uint32_t pcOffset);
4705
4706 public:
4707 HeapPtrShape &shape() {
4708 return shape_;
4709 }
4710 HeapPtrShape &expandoShape() {
4711 return expandoShape_;
4712 }
4713 HeapPtrObject &holder() {
4714 return holder_;
4715 }
4716 HeapPtrShape &holderShape() {
4717 return holderShape_;
4718 }
4719 HeapPtrFunction &getter() {
4720 return getter_;
4721 }
4722 uint32_t pcOffset() const {
4723 return pcOffset_;
4724 }
4725
4726 static size_t offsetOfShape() {
4727 return offsetof(ICGetPropCallDOMProxyNativeStub, shape_);
4728 }
4729 static size_t offsetOfProxyHandler() {
4730 return offsetof(ICGetPropCallDOMProxyNativeStub, proxyHandler_);
4731 }
4732 static size_t offsetOfExpandoShape() {
4733 return offsetof(ICGetPropCallDOMProxyNativeStub, expandoShape_);
4734 }
4735 static size_t offsetOfHolder() {
4736 return offsetof(ICGetPropCallDOMProxyNativeStub, holder_);
4737 }
4738 static size_t offsetOfHolderShape() {
4739 return offsetof(ICGetPropCallDOMProxyNativeStub, holderShape_);
4740 }
4741 static size_t offsetOfGetter() {
4742 return offsetof(ICGetPropCallDOMProxyNativeStub, getter_);
4743 }
4744 static size_t offsetOfPCOffset() {
4745 return offsetof(ICGetPropCallDOMProxyNativeStub, pcOffset_);
4746 }
4747 };
4748
4749 class ICGetProp_CallDOMProxyNative : public ICGetPropCallDOMProxyNativeStub
4750 {
4751 friend class ICStubSpace;
4752 ICGetProp_CallDOMProxyNative(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
4753 BaseProxyHandler *proxyHandler, HandleShape expandoShape,
4754 HandleObject holder, HandleShape holderShape,
4755 HandleFunction getter, uint32_t pcOffset)
4756 : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyNative, stubCode,
4757 firstMonitorStub, shape, proxyHandler, expandoShape,
4758 holder, holderShape, getter, pcOffset)
4759 {}
4760
4761 public:
4762 static inline ICGetProp_CallDOMProxyNative *New(
4763 ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
4764 HandleShape shape, BaseProxyHandler *proxyHandler,
4765 HandleShape expandoShape, HandleObject holder, HandleShape holderShape,
4766 HandleFunction getter, uint32_t pcOffset)
4767 {
4768 if (!code)
4769 return nullptr;
4770 return space->allocate<ICGetProp_CallDOMProxyNative>(code, firstMonitorStub, shape,
4771 proxyHandler, expandoShape, holder,
4772 holderShape, getter, pcOffset);
4773 }
4774 };
4775
4776 class ICGetProp_CallDOMProxyWithGenerationNative : public ICGetPropCallDOMProxyNativeStub
4777 {
4778 protected:
4779 ExpandoAndGeneration *expandoAndGeneration_;
4780 uint32_t generation_;
4781
4782 public:
4783 ICGetProp_CallDOMProxyWithGenerationNative(JitCode *stubCode, ICStub *firstMonitorStub,
4784 HandleShape shape, BaseProxyHandler *proxyHandler,
4785 ExpandoAndGeneration *expandoAndGeneration,
4786 uint32_t generation, HandleShape expandoShape,
4787 HandleObject holder, HandleShape holderShape,
4788 HandleFunction getter, uint32_t pcOffset)
4789 : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyWithGenerationNative,
4790 stubCode, firstMonitorStub, shape, proxyHandler,
4791 expandoShape, holder, holderShape, getter, pcOffset),
4792 expandoAndGeneration_(expandoAndGeneration),
4793 generation_(generation)
4794 {
4795 }
4796
4797 static inline ICGetProp_CallDOMProxyWithGenerationNative *New(
4798 ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
4799 HandleShape shape, BaseProxyHandler *proxyHandler,
4800 ExpandoAndGeneration *expandoAndGeneration, uint32_t generation,
4801 HandleShape expandoShape, HandleObject holder, HandleShape holderShape,
4802 HandleFunction getter, uint32_t pcOffset)
4803 {
4804 if (!code)
4805 return nullptr;
4806 return space->allocate<ICGetProp_CallDOMProxyWithGenerationNative>(code, firstMonitorStub,
4807 shape, proxyHandler, expandoAndGeneration,
4808 generation, expandoShape, holder, holderShape,
4809 getter, pcOffset);
4810 }
4811
4812 void *expandoAndGeneration() const {
4813 return expandoAndGeneration_;
4814 }
4815 uint32_t generation() const {
4816 return generation_;
4817 }
4818
4819 void setGeneration(uint32_t value) {
4820 generation_ = value;
4821 }
4822
4823 static size_t offsetOfInternalStruct() {
4824 return offsetof(ICGetProp_CallDOMProxyWithGenerationNative, expandoAndGeneration_);
4825 }
4826 static size_t offsetOfGeneration() {
4827 return offsetof(ICGetProp_CallDOMProxyWithGenerationNative, generation_);
4828 }
4829 };
4830
4831 class ICGetPropCallDOMProxyNativeCompiler : public ICStubCompiler {
4832 ICStub *firstMonitorStub_;
4833 Rooted<ProxyObject*> proxy_;
4834 RootedObject holder_;
4835 RootedFunction getter_;
4836 uint32_t pcOffset_;
4837
4838 bool generateStubCode(MacroAssembler &masm, Address* internalStructAddr,
4839 Address* generationAddr);
4840 bool generateStubCode(MacroAssembler &masm);
4841
4842 public:
4843 ICGetPropCallDOMProxyNativeCompiler(JSContext *cx, ICStub::Kind kind,
4844 ICStub *firstMonitorStub, Handle<ProxyObject*> proxy,
4845 HandleObject holder, HandleFunction getter,
4846 uint32_t pcOffset);
4847
4848 ICStub *getStub(ICStubSpace *space);
4849 };
4850
4851 class ICGetProp_DOMProxyShadowed : public ICMonitoredStub
4852 {
4853 friend class ICStubSpace;
4854 protected:
4855 HeapPtrShape shape_;
4856 BaseProxyHandler *proxyHandler_;
4857 HeapPtrPropertyName name_;
4858 uint32_t pcOffset_;
4859
4860 ICGetProp_DOMProxyShadowed(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
4861 BaseProxyHandler *proxyHandler, HandlePropertyName name,
4862 uint32_t pcOffset);
4863
4864 public:
4865 static inline ICGetProp_DOMProxyShadowed *New(ICStubSpace *space, JitCode *code,
4866 ICStub *firstMonitorStub, HandleShape shape,
4867 BaseProxyHandler *proxyHandler,
4868 HandlePropertyName name, uint32_t pcOffset)
4869 {
4870 if (!code)
4871 return nullptr;
4872 return space->allocate<ICGetProp_DOMProxyShadowed>(code, firstMonitorStub, shape,
4873 proxyHandler, name, pcOffset);
4874 }
4875
4876 HeapPtrShape &shape() {
4877 return shape_;
4878 }
4879 HeapPtrPropertyName &name() {
4880 return name_;
4881 }
4882
4883 static size_t offsetOfShape() {
4884 return offsetof(ICGetProp_DOMProxyShadowed, shape_);
4885 }
4886 static size_t offsetOfProxyHandler() {
4887 return offsetof(ICGetProp_DOMProxyShadowed, proxyHandler_);
4888 }
4889 static size_t offsetOfName() {
4890 return offsetof(ICGetProp_DOMProxyShadowed, name_);
4891 }
4892 static size_t offsetOfPCOffset() {
4893 return offsetof(ICGetProp_DOMProxyShadowed, pcOffset_);
4894 }
4895
4896 class Compiler : public ICStubCompiler {
4897 ICStub *firstMonitorStub_;
4898 Rooted<ProxyObject*> proxy_;
4899 RootedPropertyName name_;
4900 uint32_t pcOffset_;
4901
4902 bool generateStubCode(MacroAssembler &masm);
4903
4904 public:
4905 Compiler(JSContext *cx, ICStub *firstMonitorStub, Handle<ProxyObject*> proxy,
4906 HandlePropertyName name, uint32_t pcOffset)
4907 : ICStubCompiler(cx, ICStub::GetProp_CallNative),
4908 firstMonitorStub_(firstMonitorStub),
4909 proxy_(cx, proxy),
4910 name_(cx, name),
4911 pcOffset_(pcOffset)
4912 {}
4913
4914 ICStub *getStub(ICStubSpace *space);
4915 };
4916 };
4917
4918 class ICGetProp_ArgumentsLength : public ICStub
4919 {
4920 friend class ICStubSpace;
4921 public:
4922 enum Which { Normal, Strict, Magic };
4923
4924 protected:
4925 ICGetProp_ArgumentsLength(JitCode *stubCode)
4926 : ICStub(ICStub::GetProp_ArgumentsLength, stubCode)
4927 { }
4928
4929 public:
4930 static inline ICGetProp_ArgumentsLength *New(ICStubSpace *space, JitCode *code)
4931 {
4932 if (!code)
4933 return nullptr;
4934 return space->allocate<ICGetProp_ArgumentsLength>(code);
4935 }
4936
4937 class Compiler : public ICStubCompiler {
4938 protected:
4939 Which which_;
4940
4941 bool generateStubCode(MacroAssembler &masm);
4942
4943 virtual int32_t getKey() const {
4944 return static_cast<int32_t>(kind) | (static_cast<int32_t>(which_) << 16);
4945 }
4946
4947 public:
4948 Compiler(JSContext *cx, Which which)
4949 : ICStubCompiler(cx, ICStub::GetProp_ArgumentsLength),
4950 which_(which)
4951 {}
4952
4953 ICStub *getStub(ICStubSpace *space) {
4954 return ICGetProp_ArgumentsLength::New(space, getStubCode());
4955 }
4956 };
4957 };
4958
4959 // SetProp
4960 // JSOP_SETPROP
4961 // JSOP_SETNAME
4962 // JSOP_SETGNAME
4963 // JSOP_INITPROP
4964
4965 class ICSetProp_Fallback : public ICFallbackStub
4966 {
4967 friend class ICStubSpace;
4968
4969 ICSetProp_Fallback(JitCode *stubCode)
4970 : ICFallbackStub(ICStub::SetProp_Fallback, stubCode)
4971 { }
4972
4973 public:
4974 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
4975
4976 static inline ICSetProp_Fallback *New(ICStubSpace *space, JitCode *code) {
4977 if (!code)
4978 return nullptr;
4979 return space->allocate<ICSetProp_Fallback>(code);
4980 }
4981
4982 static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
4983 void noteUnoptimizableAccess() {
4984 extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
4985 }
4986 bool hadUnoptimizableAccess() const {
4987 return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
4988 }
4989
4990 class Compiler : public ICStubCompiler {
4991 protected:
4992 uint32_t returnFromIonOffset_;
4993 uint32_t returnFromStubOffset_;
4994 bool generateStubCode(MacroAssembler &masm);
4995 bool postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code);
4996
4997 public:
4998 Compiler(JSContext *cx)
4999 : ICStubCompiler(cx, ICStub::SetProp_Fallback)
5000 { }
5001
5002 ICStub *getStub(ICStubSpace *space) {
5003 return ICSetProp_Fallback::New(space, getStubCode());
5004 }
5005 };
5006 };
5007
5008 // Optimized SETPROP/SETGNAME/SETNAME stub.
5009 class ICSetProp_Native : public ICUpdatedStub
5010 {
5011 friend class ICStubSpace;
5012
5013 protected: // Protected to silence Clang warning.
5014 HeapPtrTypeObject type_;
5015 HeapPtrShape shape_;
5016 uint32_t offset_;
5017
5018 ICSetProp_Native(JitCode *stubCode, HandleTypeObject type, HandleShape shape, uint32_t offset);
5019
5020 public:
5021 static inline ICSetProp_Native *New(ICStubSpace *space, JitCode *code, HandleTypeObject type,
5022 HandleShape shape, uint32_t offset)
5023 {
5024 if (!code)
5025 return nullptr;
5026 return space->allocate<ICSetProp_Native>(code, type, shape, offset);
5027 }
5028 HeapPtrTypeObject &type() {
5029 return type_;
5030 }
5031 HeapPtrShape &shape() {
5032 return shape_;
5033 }
5034 static size_t offsetOfType() {
5035 return offsetof(ICSetProp_Native, type_);
5036 }
5037 static size_t offsetOfShape() {
5038 return offsetof(ICSetProp_Native, shape_);
5039 }
5040 static size_t offsetOfOffset() {
5041 return offsetof(ICSetProp_Native, offset_);
5042 }
5043
5044 class Compiler : public ICStubCompiler {
5045 RootedObject obj_;
5046 bool isFixedSlot_;
5047 uint32_t offset_;
5048
5049 protected:
5050 virtual int32_t getKey() const {
5051 return static_cast<int32_t>(kind) | (static_cast<int32_t>(isFixedSlot_) << 16);
5052 }
5053
5054 bool generateStubCode(MacroAssembler &masm);
5055
5056 public:
5057 Compiler(JSContext *cx, HandleObject obj, bool isFixedSlot, uint32_t offset)
5058 : ICStubCompiler(cx, ICStub::SetProp_Native),
5059 obj_(cx, obj),
5060 isFixedSlot_(isFixedSlot),
5061 offset_(offset)
5062 {}
5063
5064 ICUpdatedStub *getStub(ICStubSpace *space);
5065 };
5066 };
5067
5068
5069 template <size_t ProtoChainDepth> class ICSetProp_NativeAddImpl;
5070
5071 class ICSetProp_NativeAdd : public ICUpdatedStub
5072 {
5073 public:
5074 static const size_t MAX_PROTO_CHAIN_DEPTH = 4;
5075
5076 protected: // Protected to silence Clang warning.
5077 HeapPtrTypeObject type_;
5078 HeapPtrShape newShape_;
5079 uint32_t offset_;
5080
5081 ICSetProp_NativeAdd(JitCode *stubCode, HandleTypeObject type, size_t protoChainDepth,
5082 HandleShape newShape, uint32_t offset);
5083
5084 public:
5085 size_t protoChainDepth() const {
5086 return extra_;
5087 }
5088 HeapPtrTypeObject &type() {
5089 return type_;
5090 }
5091 HeapPtrShape &newShape() {
5092 return newShape_;
5093 }
5094
5095 template <size_t ProtoChainDepth>
5096 ICSetProp_NativeAddImpl<ProtoChainDepth> *toImpl() {
5097 JS_ASSERT(ProtoChainDepth == protoChainDepth());
5098 return static_cast<ICSetProp_NativeAddImpl<ProtoChainDepth> *>(this);
5099 }
5100
5101 static size_t offsetOfType() {
5102 return offsetof(ICSetProp_NativeAdd, type_);
5103 }
5104 static size_t offsetOfNewShape() {
5105 return offsetof(ICSetProp_NativeAdd, newShape_);
5106 }
5107 static size_t offsetOfOffset() {
5108 return offsetof(ICSetProp_NativeAdd, offset_);
5109 }
5110 };
5111
5112 template <size_t ProtoChainDepth>
5113 class ICSetProp_NativeAddImpl : public ICSetProp_NativeAdd
5114 {
5115 friend class ICStubSpace;
5116
5117 static const size_t NumShapes = ProtoChainDepth + 1;
5118 mozilla::Array<HeapPtrShape, NumShapes> shapes_;
5119
5120 ICSetProp_NativeAddImpl(JitCode *stubCode, HandleTypeObject type,
5121 const AutoShapeVector *shapes,
5122 HandleShape newShape, uint32_t offset);
5123
5124 public:
5125 static inline ICSetProp_NativeAddImpl *New(
5126 ICStubSpace *space, JitCode *code, HandleTypeObject type,
5127 const AutoShapeVector *shapes, HandleShape newShape, uint32_t offset)
5128 {
5129 if (!code)
5130 return nullptr;
5131 return space->allocate<ICSetProp_NativeAddImpl<ProtoChainDepth> >(
5132 code, type, shapes, newShape, offset);
5133 }
5134
5135 void traceShapes(JSTracer *trc) {
5136 for (size_t i = 0; i < NumShapes; i++)
5137 MarkShape(trc, &shapes_[i], "baseline-setpropnativeadd-stub-shape");
5138 }
5139
5140 static size_t offsetOfShape(size_t idx) {
5141 return offsetof(ICSetProp_NativeAddImpl, shapes_) + (idx * sizeof(HeapPtrShape));
5142 }
5143 };
5144
5145 class ICSetPropNativeAddCompiler : public ICStubCompiler {
5146 RootedObject obj_;
5147 RootedShape oldShape_;
5148 size_t protoChainDepth_;
5149 bool isFixedSlot_;
5150 uint32_t offset_;
5151
5152 protected:
5153 virtual int32_t getKey() const {
5154 return static_cast<int32_t>(kind) | (static_cast<int32_t>(isFixedSlot_) << 16) |
5155 (static_cast<int32_t>(protoChainDepth_) << 20);
5156 }
5157
5158 bool generateStubCode(MacroAssembler &masm);
5159
5160 public:
5161 ICSetPropNativeAddCompiler(JSContext *cx, HandleObject obj, HandleShape oldShape,
5162 size_t protoChainDepth, bool isFixedSlot, uint32_t offset);
5163
5164 template <size_t ProtoChainDepth>
5165 ICUpdatedStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes)
5166 {
5167 RootedTypeObject type(cx, obj_->getType(cx));
5168 if (!type)
5169 return nullptr;
5170
5171 RootedShape newShape(cx, obj_->lastProperty());
5172
5173 return ICSetProp_NativeAddImpl<ProtoChainDepth>::New(
5174 space, getStubCode(), type, shapes, newShape, offset_);
5175 }
5176
5177 ICUpdatedStub *getStub(ICStubSpace *space);
5178 };
5179
5180 // Base stub for calling a setters on a native object.
5181 class ICSetPropCallSetter : public ICStub
5182 {
5183 friend class ICStubSpace;
5184
5185 protected:
5186 // Object shape (lastProperty).
5187 HeapPtrShape shape_;
5188
5189 // Holder and shape.
5190 HeapPtrObject holder_;
5191 HeapPtrShape holderShape_;
5192
5193 // Function to call.
5194 HeapPtrFunction setter_;
5195
5196 // PC of call, for profiler
5197 uint32_t pcOffset_;
5198
5199 ICSetPropCallSetter(Kind kind, JitCode *stubCode, HandleShape shape, HandleObject holder,
5200 HandleShape holderShape, HandleFunction setter, uint32_t pcOffset);
5201
5202 public:
5203 HeapPtrShape &shape() {
5204 return shape_;
5205 }
5206 HeapPtrObject &holder() {
5207 return holder_;
5208 }
5209 HeapPtrShape &holderShape() {
5210 return holderShape_;
5211 }
5212 HeapPtrFunction &setter() {
5213 return setter_;
5214 }
5215
5216 static size_t offsetOfShape() {
5217 return offsetof(ICSetPropCallSetter, shape_);
5218 }
5219 static size_t offsetOfHolder() {
5220 return offsetof(ICSetPropCallSetter, holder_);
5221 }
5222 static size_t offsetOfHolderShape() {
5223 return offsetof(ICSetPropCallSetter, holderShape_);
5224 }
5225 static size_t offsetOfSetter() {
5226 return offsetof(ICSetPropCallSetter, setter_);
5227 }
5228 static size_t offsetOfPCOffset() {
5229 return offsetof(ICSetPropCallSetter, pcOffset_);
5230 }
5231
5232 class Compiler : public ICStubCompiler {
5233 protected:
5234 RootedObject obj_;
5235 RootedObject holder_;
5236 RootedFunction setter_;
5237 uint32_t pcOffset_;
5238
5239 public:
5240 Compiler(JSContext *cx, ICStub::Kind kind, HandleObject obj, HandleObject holder,
5241 HandleFunction setter, uint32_t pcOffset)
5242 : ICStubCompiler(cx, kind),
5243 obj_(cx, obj),
5244 holder_(cx, holder),
5245 setter_(cx, setter),
5246 pcOffset_(pcOffset)
5247 {
5248 JS_ASSERT(kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
5249 }
5250 };
5251 };
5252
5253 // Stub for calling a scripted setter on a native object.
5254 class ICSetProp_CallScripted : public ICSetPropCallSetter
5255 {
5256 friend class ICStubSpace;
5257
5258 protected:
5259 ICSetProp_CallScripted(JitCode *stubCode, HandleShape shape, HandleObject holder,
5260 HandleShape holderShape, HandleFunction setter, uint32_t pcOffset)
5261 : ICSetPropCallSetter(SetProp_CallScripted, stubCode, shape, holder, holderShape,
5262 setter, pcOffset)
5263 {}
5264
5265 public:
5266 static inline ICSetProp_CallScripted *New(ICStubSpace *space, JitCode *code,
5267 HandleShape shape, HandleObject holder,
5268 HandleShape holderShape, HandleFunction setter,
5269 uint32_t pcOffset)
5270 {
5271 if (!code)
5272 return nullptr;
5273 return space->allocate<ICSetProp_CallScripted>(code, shape, holder, holderShape, setter,
5274 pcOffset);
5275 }
5276
5277 class Compiler : public ICSetPropCallSetter::Compiler {
5278 protected:
5279 bool generateStubCode(MacroAssembler &masm);
5280
5281 public:
5282 Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter,
5283 uint32_t pcOffset)
5284 : ICSetPropCallSetter::Compiler(cx, ICStub::SetProp_CallScripted,
5285 obj, holder, setter, pcOffset)
5286 {}
5287
5288 ICStub *getStub(ICStubSpace *space) {
5289 RootedShape shape(cx, obj_->lastProperty());
5290 RootedShape holderShape(cx, holder_->lastProperty());
5291 return ICSetProp_CallScripted::New(space, getStubCode(), shape, holder_, holderShape,
5292 setter_, pcOffset_);
5293 }
5294 };
5295 };
5296
5297 // Stub for calling a native setter on a native object.
5298 class ICSetProp_CallNative : public ICSetPropCallSetter
5299 {
5300 friend class ICStubSpace;
5301
5302 protected:
5303 ICSetProp_CallNative(JitCode *stubCode, HandleShape shape, HandleObject holder,
5304 HandleShape holderShape, HandleFunction setter, uint32_t pcOffset)
5305 : ICSetPropCallSetter(SetProp_CallNative, stubCode, shape, holder, holderShape,
5306 setter, pcOffset)
5307 {}
5308
5309 public:
5310 static inline ICSetProp_CallNative *New(ICStubSpace *space, JitCode *code,
5311 HandleShape shape, HandleObject holder,
5312 HandleShape holderShape, HandleFunction setter,
5313 uint32_t pcOffset)
5314 {
5315 if (!code)
5316 return nullptr;
5317 return space->allocate<ICSetProp_CallNative>(code, shape, holder, holderShape, setter,
5318 pcOffset);
5319 }
5320
5321 class Compiler : public ICSetPropCallSetter::Compiler {
5322 protected:
5323 bool generateStubCode(MacroAssembler &masm);
5324
5325 public:
5326 Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter,
5327 uint32_t pcOffset)
5328 : ICSetPropCallSetter::Compiler(cx, ICStub::SetProp_CallNative,
5329 obj, holder, setter, pcOffset)
5330 {}
5331
5332 ICStub *getStub(ICStubSpace *space) {
5333 RootedShape shape(cx, obj_->lastProperty());
5334 RootedShape holderShape(cx, holder_->lastProperty());
5335 return ICSetProp_CallNative::New(space, getStubCode(), shape, holder_, holderShape,
5336 setter_, pcOffset_);
5337 }
5338 };
5339 };
5340
5341 // Call
5342 // JSOP_CALL
5343 // JSOP_FUNAPPLY
5344 // JSOP_FUNCALL
5345 // JSOP_NEW
5346
5347 class ICCallStubCompiler : public ICStubCompiler
5348 {
5349 protected:
5350 ICCallStubCompiler(JSContext *cx, ICStub::Kind kind)
5351 : ICStubCompiler(cx, kind)
5352 { }
5353
5354 enum FunApplyThing {
5355 FunApply_MagicArgs,
5356 FunApply_Array
5357 };
5358
5359 void pushCallArguments(MacroAssembler &masm, GeneralRegisterSet regs, Register argcReg);
5360 Register guardFunApply(MacroAssembler &masm, GeneralRegisterSet regs, Register argcReg,
5361 bool checkNative, FunApplyThing applyThing, Label *failure);
5362 void pushCallerArguments(MacroAssembler &masm, GeneralRegisterSet regs);
5363 void pushArrayArguments(MacroAssembler &masm, Address arrayVal, GeneralRegisterSet regs);
5364 };
5365
5366 class ICCall_Fallback : public ICMonitoredFallbackStub
5367 {
5368 friend class ICStubSpace;
5369 public:
5370 static const unsigned CONSTRUCTING_FLAG = 0x0001;
5371
5372 static const uint32_t MAX_OPTIMIZED_STUBS = 16;
5373 static const uint32_t MAX_SCRIPTED_STUBS = 7;
5374 static const uint32_t MAX_NATIVE_STUBS = 7;
5375 private:
5376
5377 ICCall_Fallback(JitCode *stubCode, bool isConstructing)
5378 : ICMonitoredFallbackStub(ICStub::Call_Fallback, stubCode)
5379 {
5380 extra_ = 0;
5381 if (isConstructing)
5382 extra_ |= CONSTRUCTING_FLAG;
5383 }
5384
5385 public:
5386
5387 static inline ICCall_Fallback *New(ICStubSpace *space, JitCode *code, bool isConstructing)
5388 {
5389 if (!code)
5390 return nullptr;
5391 return space->allocate<ICCall_Fallback>(code, isConstructing);
5392 }
5393
5394 bool isConstructing() const {
5395 return extra_ & CONSTRUCTING_FLAG;
5396 }
5397
5398 unsigned scriptedStubCount() const {
5399 return numStubsWithKind(Call_Scripted);
5400 }
5401 bool scriptedStubsAreGeneralized() const {
5402 return hasStub(Call_AnyScripted);
5403 }
5404
5405 unsigned nativeStubCount() const {
5406 return numStubsWithKind(Call_Native);
5407 }
5408 bool nativeStubsAreGeneralized() const {
5409 // Return hasStub(Call_AnyNative) after Call_AnyNative stub is added.
5410 return false;
5411 }
5412
5413 // Compiler for this stub kind.
5414 class Compiler : public ICCallStubCompiler {
5415 protected:
5416 bool isConstructing_;
5417 uint32_t returnFromIonOffset_;
5418 uint32_t returnFromStubOffset_;
5419 bool generateStubCode(MacroAssembler &masm);
5420 bool postGenerateStubCode(MacroAssembler &masm, Handle<JitCode *> code);
5421
5422 public:
5423 Compiler(JSContext *cx, bool isConstructing)
5424 : ICCallStubCompiler(cx, ICStub::Call_Fallback),
5425 isConstructing_(isConstructing)
5426 { }
5427
5428 ICStub *getStub(ICStubSpace *space) {
5429 ICCall_Fallback *stub = ICCall_Fallback::New(space, getStubCode(), isConstructing_);
5430 if (!stub || !stub->initMonitoringChain(cx, space))
5431 return nullptr;
5432 return stub;
5433 }
5434 };
5435 };
5436
5437 class ICCall_Scripted : public ICMonitoredStub
5438 {
5439 friend class ICStubSpace;
5440
5441 protected:
5442 HeapPtrScript calleeScript_;
5443 HeapPtrObject templateObject_;
5444 uint32_t pcOffset_;
5445
5446 ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
5447 HandleScript calleeScript, HandleObject templateObject,
5448 uint32_t pcOffset);
5449
5450 public:
5451 static inline ICCall_Scripted *New(
5452 ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
5453 HandleScript calleeScript, HandleObject templateObject,
5454 uint32_t pcOffset)
5455 {
5456 if (!code)
5457 return nullptr;
5458 return space->allocate<ICCall_Scripted>(code, firstMonitorStub,
5459 calleeScript, templateObject, pcOffset);
5460 }
5461
5462 HeapPtrScript &calleeScript() {
5463 return calleeScript_;
5464 }
5465 HeapPtrObject &templateObject() {
5466 return templateObject_;
5467 }
5468
5469 static size_t offsetOfCalleeScript() {
5470 return offsetof(ICCall_Scripted, calleeScript_);
5471 }
5472 static size_t offsetOfPCOffset() {
5473 return offsetof(ICCall_Scripted, pcOffset_);
5474 }
5475 };
5476
5477 class ICCall_AnyScripted : public ICMonitoredStub
5478 {
5479 friend class ICStubSpace;
5480
5481 protected:
5482 uint32_t pcOffset_;
5483
5484 ICCall_AnyScripted(JitCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset)
5485 : ICMonitoredStub(ICStub::Call_AnyScripted, stubCode, firstMonitorStub),
5486 pcOffset_(pcOffset)
5487 { }
5488
5489 public:
5490 static inline ICCall_AnyScripted *New(ICStubSpace *space, JitCode *code,
5491 ICStub *firstMonitorStub, uint32_t pcOffset)
5492 {
5493 if (!code)
5494 return nullptr;
5495 return space->allocate<ICCall_AnyScripted>(code, firstMonitorStub, pcOffset);
5496 }
5497
5498 static size_t offsetOfPCOffset() {
5499 return offsetof(ICCall_AnyScripted, pcOffset_);
5500 }
5501 };
5502
5503 // Compiler for Call_Scripted and Call_AnyScripted stubs.
5504 class ICCallScriptedCompiler : public ICCallStubCompiler {
5505 protected:
5506 ICStub *firstMonitorStub_;
5507 bool isConstructing_;
5508 RootedScript calleeScript_;
5509 RootedObject templateObject_;
5510 uint32_t pcOffset_;
5511 bool generateStubCode(MacroAssembler &masm);
5512
5513 virtual int32_t getKey() const {
5514 return static_cast<int32_t>(kind) | (static_cast<int32_t>(isConstructing_) << 16);
5515 }
5516
5517 public:
5518 ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub,
5519 HandleScript calleeScript, HandleObject templateObject,
5520 bool isConstructing, uint32_t pcOffset)
5521 : ICCallStubCompiler(cx, ICStub::Call_Scripted),
5522 firstMonitorStub_(firstMonitorStub),
5523 isConstructing_(isConstructing),
5524 calleeScript_(cx, calleeScript),
5525 templateObject_(cx, templateObject),
5526 pcOffset_(pcOffset)
5527 { }
5528
5529 ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub, bool isConstructing,
5530 uint32_t pcOffset)
5531 : ICCallStubCompiler(cx, ICStub::Call_AnyScripted),
5532 firstMonitorStub_(firstMonitorStub),
5533 isConstructing_(isConstructing),
5534 calleeScript_(cx, nullptr),
5535 templateObject_(cx, nullptr),
5536 pcOffset_(pcOffset)
5537 { }
5538
5539 ICStub *getStub(ICStubSpace *space) {
5540 if (calleeScript_) {
5541 return ICCall_Scripted::New(space, getStubCode(), firstMonitorStub_,
5542 calleeScript_, templateObject_,
5543 pcOffset_);
5544 }
5545 return ICCall_AnyScripted::New(space, getStubCode(), firstMonitorStub_, pcOffset_);
5546 }
5547 };
5548
5549 class ICCall_Native : public ICMonitoredStub
5550 {
5551 friend class ICStubSpace;
5552
5553 protected:
5554 HeapPtrFunction callee_;
5555 HeapPtrObject templateObject_;
5556 uint32_t pcOffset_;
5557
5558 #ifdef JS_ARM_SIMULATOR
5559 void *native_;
5560 #endif
5561
5562 ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
5563 HandleFunction callee, HandleObject templateObject,
5564 uint32_t pcOffset);
5565
5566 public:
5567 static inline ICCall_Native *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
5568 HandleFunction callee, HandleObject templateObject,
5569 uint32_t pcOffset)
5570 {
5571 if (!code)
5572 return nullptr;
5573 return space->allocate<ICCall_Native>(code, firstMonitorStub,
5574 callee, templateObject, pcOffset);
5575 }
5576
5577 HeapPtrFunction &callee() {
5578 return callee_;
5579 }
5580 HeapPtrObject &templateObject() {
5581 return templateObject_;
5582 }
5583
5584 static size_t offsetOfCallee() {
5585 return offsetof(ICCall_Native, callee_);
5586 }
5587 static size_t offsetOfPCOffset() {
5588 return offsetof(ICCall_Native, pcOffset_);
5589 }
5590
5591 #ifdef JS_ARM_SIMULATOR
5592 static size_t offsetOfNative() {
5593 return offsetof(ICCall_Native, native_);
5594 }
5595 #endif
5596
5597 // Compiler for this stub kind.
5598 class Compiler : public ICCallStubCompiler {
5599 protected:
5600 ICStub *firstMonitorStub_;
5601 bool isConstructing_;
5602 RootedFunction callee_;
5603 RootedObject templateObject_;
5604 uint32_t pcOffset_;
5605 bool generateStubCode(MacroAssembler &masm);
5606
5607 virtual int32_t getKey() const {
5608 return static_cast<int32_t>(kind) | (static_cast<int32_t>(isConstructing_) << 16);
5609 }
5610
5611 public:
5612 Compiler(JSContext *cx, ICStub *firstMonitorStub,
5613 HandleFunction callee, HandleObject templateObject,
5614 bool isConstructing, uint32_t pcOffset)
5615 : ICCallStubCompiler(cx, ICStub::Call_Native),
5616 firstMonitorStub_(firstMonitorStub),
5617 isConstructing_(isConstructing),
5618 callee_(cx, callee),
5619 templateObject_(cx, templateObject),
5620 pcOffset_(pcOffset)
5621 { }
5622
5623 ICStub *getStub(ICStubSpace *space) {
5624 return ICCall_Native::New(space, getStubCode(), firstMonitorStub_,
5625 callee_, templateObject_, pcOffset_);
5626 }
5627 };
5628 };
5629
5630 class ICCall_ScriptedApplyArray : public ICMonitoredStub
5631 {
5632 friend class ICStubSpace;
5633 public:
5634 // The maximum length of an inlineable funcall array.
5635 // Keep this small to avoid controllable stack overflows by attackers passing large
5636 // arrays to fun.apply.
5637 static const uint32_t MAX_ARGS_ARRAY_LENGTH = 16;
5638
5639 protected:
5640 uint32_t pcOffset_;
5641
5642 ICCall_ScriptedApplyArray(JitCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset)
5643 : ICMonitoredStub(ICStub::Call_ScriptedApplyArray, stubCode, firstMonitorStub),
5644 pcOffset_(pcOffset)
5645 {}
5646
5647 public:
5648 static inline ICCall_ScriptedApplyArray *New(ICStubSpace *space, JitCode *code,
5649 ICStub *firstMonitorStub, uint32_t pcOffset)
5650 {
5651 if (!code)
5652 return nullptr;
5653 return space->allocate<ICCall_ScriptedApplyArray>(code, firstMonitorStub, pcOffset);
5654 }
5655
5656 static size_t offsetOfPCOffset() {
5657 return offsetof(ICCall_ScriptedApplyArray, pcOffset_);
5658 }
5659
5660 // Compiler for this stub kind.
5661 class Compiler : public ICCallStubCompiler {
5662 protected:
5663 ICStub *firstMonitorStub_;
5664 uint32_t pcOffset_;
5665 bool generateStubCode(MacroAssembler &masm);
5666
5667 virtual int32_t getKey() const {
5668 return static_cast<int32_t>(kind);
5669 }
5670
5671 public:
5672 Compiler(JSContext *cx, ICStub *firstMonitorStub, uint32_t pcOffset)
5673 : ICCallStubCompiler(cx, ICStub::Call_ScriptedApplyArray),
5674 firstMonitorStub_(firstMonitorStub),
5675 pcOffset_(pcOffset)
5676 { }
5677
5678 ICStub *getStub(ICStubSpace *space) {
5679 return ICCall_ScriptedApplyArray::New(space, getStubCode(), firstMonitorStub_,
5680 pcOffset_);
5681 }
5682 };
5683 };
5684
5685 class ICCall_ScriptedApplyArguments : public ICMonitoredStub
5686 {
5687 friend class ICStubSpace;
5688
5689 protected:
5690 uint32_t pcOffset_;
5691
5692 ICCall_ScriptedApplyArguments(JitCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset)
5693 : ICMonitoredStub(ICStub::Call_ScriptedApplyArguments, stubCode, firstMonitorStub),
5694 pcOffset_(pcOffset)
5695 {}
5696
5697 public:
5698 static inline ICCall_ScriptedApplyArguments *New(ICStubSpace *space, JitCode *code,
5699 ICStub *firstMonitorStub, uint32_t pcOffset)
5700 {
5701 if (!code)
5702 return nullptr;
5703 return space->allocate<ICCall_ScriptedApplyArguments>(code, firstMonitorStub, pcOffset);
5704 }
5705
5706 static size_t offsetOfPCOffset() {
5707 return offsetof(ICCall_ScriptedApplyArguments, pcOffset_);
5708 }
5709
5710 // Compiler for this stub kind.
5711 class Compiler : public ICCallStubCompiler {
5712 protected:
5713 ICStub *firstMonitorStub_;
5714 uint32_t pcOffset_;
5715 bool generateStubCode(MacroAssembler &masm);
5716
5717 virtual int32_t getKey() const {
5718 return static_cast<int32_t>(kind);
5719 }
5720
5721 public:
5722 Compiler(JSContext *cx, ICStub *firstMonitorStub, uint32_t pcOffset)
5723 : ICCallStubCompiler(cx, ICStub::Call_ScriptedApplyArguments),
5724 firstMonitorStub_(firstMonitorStub),
5725 pcOffset_(pcOffset)
5726 { }
5727
5728 ICStub *getStub(ICStubSpace *space) {
5729 return ICCall_ScriptedApplyArguments::New(space, getStubCode(), firstMonitorStub_,
5730 pcOffset_);
5731 }
5732 };
5733 };
5734
5735 // Handles calls of the form |fun.call(...)| where fun is a scripted function.
5736 class ICCall_ScriptedFunCall : public ICMonitoredStub
5737 {
5738 friend class ICStubSpace;
5739
5740 protected:
5741 uint32_t pcOffset_;
5742
5743 ICCall_ScriptedFunCall(JitCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset)
5744 : ICMonitoredStub(ICStub::Call_ScriptedFunCall, stubCode, firstMonitorStub),
5745 pcOffset_(pcOffset)
5746 {}
5747
5748 public:
5749 static inline ICCall_ScriptedFunCall *New(ICStubSpace *space, JitCode *code,
5750 ICStub *firstMonitorStub, uint32_t pcOffset)
5751 {
5752 if (!code)
5753 return nullptr;
5754 return space->allocate<ICCall_ScriptedFunCall>(code, firstMonitorStub, pcOffset);
5755 }
5756
5757 static size_t offsetOfPCOffset() {
5758 return offsetof(ICCall_ScriptedFunCall, pcOffset_);
5759 }
5760
5761 // Compiler for this stub kind.
5762 class Compiler : public ICCallStubCompiler {
5763 protected:
5764 ICStub *firstMonitorStub_;
5765 uint32_t pcOffset_;
5766 bool generateStubCode(MacroAssembler &masm);
5767
5768 virtual int32_t getKey() const {
5769 return static_cast<int32_t>(kind);
5770 }
5771
5772 public:
5773 Compiler(JSContext *cx, ICStub *firstMonitorStub, uint32_t pcOffset)
5774 : ICCallStubCompiler(cx, ICStub::Call_ScriptedFunCall),
5775 firstMonitorStub_(firstMonitorStub),
5776 pcOffset_(pcOffset)
5777 { }
5778
5779 ICStub *getStub(ICStubSpace *space) {
5780 return ICCall_ScriptedFunCall::New(space, getStubCode(), firstMonitorStub_,
5781 pcOffset_);
5782 }
5783 };
5784 };
5785
5786 // Stub for performing a TableSwitch, updating the IC's return address to jump
5787 // to whatever point the switch is branching to.
5788 class ICTableSwitch : public ICStub
5789 {
5790 friend class ICStubSpace;
5791
5792 protected: // Protected to silence Clang warning.
5793 void **table_;
5794 int32_t min_;
5795 int32_t length_;
5796 void *defaultTarget_;
5797
5798 ICTableSwitch(JitCode *stubCode, void **table,
5799 int32_t min, int32_t length, void *defaultTarget)
5800 : ICStub(TableSwitch, stubCode), table_(table),
5801 min_(min), length_(length), defaultTarget_(defaultTarget)
5802 {}
5803
5804 public:
5805 static inline ICTableSwitch *New(ICStubSpace *space, JitCode *code, void **table,
5806 int32_t min, int32_t length, void *defaultTarget) {
5807 if (!code)
5808 return nullptr;
5809 return space->allocate<ICTableSwitch>(code, table, min, length, defaultTarget);
5810 }
5811
5812 void fixupJumpTable(JSScript *script, BaselineScript *baseline);
5813
5814 class Compiler : public ICStubCompiler {
5815 bool generateStubCode(MacroAssembler &masm);
5816
5817 jsbytecode *pc_;
5818
5819 public:
5820 Compiler(JSContext *cx, jsbytecode *pc)
5821 : ICStubCompiler(cx, ICStub::TableSwitch), pc_(pc)
5822 {}
5823
5824 ICStub *getStub(ICStubSpace *space);
5825 };
5826 };
5827
5828 // IC for constructing an iterator from an input value.
5829 class ICIteratorNew_Fallback : public ICFallbackStub
5830 {
5831 friend class ICStubSpace;
5832
5833 ICIteratorNew_Fallback(JitCode *stubCode)
5834 : ICFallbackStub(ICStub::IteratorNew_Fallback, stubCode)
5835 { }
5836
5837 public:
5838 static inline ICIteratorNew_Fallback *New(ICStubSpace *space, JitCode *code) {
5839 if (!code)
5840 return nullptr;
5841 return space->allocate<ICIteratorNew_Fallback>(code);
5842 }
5843
5844 class Compiler : public ICStubCompiler {
5845 protected:
5846 bool generateStubCode(MacroAssembler &masm);
5847
5848 public:
5849 Compiler(JSContext *cx)
5850 : ICStubCompiler(cx, ICStub::IteratorNew_Fallback)
5851 { }
5852
5853 ICStub *getStub(ICStubSpace *space) {
5854 return ICIteratorNew_Fallback::New(space, getStubCode());
5855 }
5856 };
5857 };
5858
5859 // IC for testing if there are more values in an iterator.
5860 class ICIteratorMore_Fallback : public ICFallbackStub
5861 {
5862 friend class ICStubSpace;
5863
5864 ICIteratorMore_Fallback(JitCode *stubCode)
5865 : ICFallbackStub(ICStub::IteratorMore_Fallback, stubCode)
5866 { }
5867
5868 public:
5869 static inline ICIteratorMore_Fallback *New(ICStubSpace *space, JitCode *code) {
5870 if (!code)
5871 return nullptr;
5872 return space->allocate<ICIteratorMore_Fallback>(code);
5873 }
5874
5875 class Compiler : public ICStubCompiler {
5876 protected:
5877 bool generateStubCode(MacroAssembler &masm);
5878
5879 public:
5880 Compiler(JSContext *cx)
5881 : ICStubCompiler(cx, ICStub::IteratorMore_Fallback)
5882 { }
5883
5884 ICStub *getStub(ICStubSpace *space) {
5885 return ICIteratorMore_Fallback::New(space, getStubCode());
5886 }
5887 };
5888 };
5889
5890 // IC for testing if there are more values in a native iterator.
5891 class ICIteratorMore_Native : public ICStub
5892 {
5893 friend class ICStubSpace;
5894
5895 ICIteratorMore_Native(JitCode *stubCode)
5896 : ICStub(ICStub::IteratorMore_Native, stubCode)
5897 { }
5898
5899 public:
5900 static inline ICIteratorMore_Native *New(ICStubSpace *space, JitCode *code) {
5901 if (!code)
5902 return nullptr;
5903 return space->allocate<ICIteratorMore_Native>(code);
5904 }
5905
5906 class Compiler : public ICStubCompiler {
5907 protected:
5908 bool generateStubCode(MacroAssembler &masm);
5909
5910 public:
5911 Compiler(JSContext *cx)
5912 : ICStubCompiler(cx, ICStub::IteratorMore_Native)
5913 { }
5914
5915 ICStub *getStub(ICStubSpace *space) {
5916 return ICIteratorMore_Native::New(space, getStubCode());
5917 }
5918 };
5919 };
5920
5921 // IC for getting the next value in an iterator.
5922 class ICIteratorNext_Fallback : public ICFallbackStub
5923 {
5924 friend class ICStubSpace;
5925
5926 ICIteratorNext_Fallback(JitCode *stubCode)
5927 : ICFallbackStub(ICStub::IteratorNext_Fallback, stubCode)
5928 { }
5929
5930 public:
5931 static inline ICIteratorNext_Fallback *New(ICStubSpace *space, JitCode *code) {
5932 if (!code)
5933 return nullptr;
5934 return space->allocate<ICIteratorNext_Fallback>(code);
5935 }
5936
5937 void setHasNonStringResult() {
5938 JS_ASSERT(extra_ == 0);
5939 extra_ = 1;
5940 }
5941 bool hasNonStringResult() const {
5942 return extra_;
5943 }
5944
5945 class Compiler : public ICStubCompiler {
5946 protected:
5947 bool generateStubCode(MacroAssembler &masm);
5948
5949 public:
5950 Compiler(JSContext *cx)
5951 : ICStubCompiler(cx, ICStub::IteratorNext_Fallback)
5952 { }
5953
5954 ICStub *getStub(ICStubSpace *space) {
5955 return ICIteratorNext_Fallback::New(space, getStubCode());
5956 }
5957 };
5958 };
5959
5960 // IC for getting the next value in a native iterator.
5961 class ICIteratorNext_Native : public ICStub
5962 {
5963 friend class ICStubSpace;
5964
5965 ICIteratorNext_Native(JitCode *stubCode)
5966 : ICStub(ICStub::IteratorNext_Native, stubCode)
5967 { }
5968
5969 public:
5970 static inline ICIteratorNext_Native *New(ICStubSpace *space, JitCode *code) {
5971 if (!code)
5972 return nullptr;
5973 return space->allocate<ICIteratorNext_Native>(code);
5974 }
5975
5976 class Compiler : public ICStubCompiler {
5977 protected:
5978 bool generateStubCode(MacroAssembler &masm);
5979
5980 public:
5981 Compiler(JSContext *cx)
5982 : ICStubCompiler(cx, ICStub::IteratorNext_Native)
5983 { }
5984
5985 ICStub *getStub(ICStubSpace *space) {
5986 return ICIteratorNext_Native::New(space, getStubCode());
5987 }
5988 };
5989 };
5990
5991 // IC for closing an iterator.
5992 class ICIteratorClose_Fallback : public ICFallbackStub
5993 {
5994 friend class ICStubSpace;
5995
5996 ICIteratorClose_Fallback(JitCode *stubCode)
5997 : ICFallbackStub(ICStub::IteratorClose_Fallback, stubCode)
5998 { }
5999
6000 public:
6001 static inline ICIteratorClose_Fallback *New(ICStubSpace *space, JitCode *code) {
6002 if (!code)
6003 return nullptr;
6004 return space->allocate<ICIteratorClose_Fallback>(code);
6005 }
6006
6007 class Compiler : public ICStubCompiler {
6008 protected:
6009 bool generateStubCode(MacroAssembler &masm);
6010
6011 public:
6012 Compiler(JSContext *cx)
6013 : ICStubCompiler(cx, ICStub::IteratorClose_Fallback)
6014 { }
6015
6016 ICStub *getStub(ICStubSpace *space) {
6017 return ICIteratorClose_Fallback::New(space, getStubCode());
6018 }
6019 };
6020 };
6021
6022 // InstanceOf
6023 // JSOP_INSTANCEOF
6024 class ICInstanceOf_Fallback : public ICFallbackStub
6025 {
6026 friend class ICStubSpace;
6027
6028 ICInstanceOf_Fallback(JitCode *stubCode)
6029 : ICFallbackStub(ICStub::InstanceOf_Fallback, stubCode)
6030 { }
6031
6032 public:
6033 static inline ICInstanceOf_Fallback *New(ICStubSpace *space, JitCode *code) {
6034 if (!code)
6035 return nullptr;
6036 return space->allocate<ICInstanceOf_Fallback>(code);
6037 }
6038
6039 class Compiler : public ICStubCompiler {
6040 protected:
6041 bool generateStubCode(MacroAssembler &masm);
6042
6043 public:
6044 Compiler(JSContext *cx)
6045 : ICStubCompiler(cx, ICStub::InstanceOf_Fallback)
6046 { }
6047
6048 ICStub *getStub(ICStubSpace *space) {
6049 return ICInstanceOf_Fallback::New(space, getStubCode());
6050 }
6051 };
6052 };
6053
6054 // TypeOf
6055 // JSOP_TYPEOF
6056 // JSOP_TYPEOFEXPR
6057 class ICTypeOf_Fallback : public ICFallbackStub
6058 {
6059 friend class ICStubSpace;
6060
6061 ICTypeOf_Fallback(JitCode *stubCode)
6062 : ICFallbackStub(ICStub::TypeOf_Fallback, stubCode)
6063 { }
6064
6065 public:
6066 static inline ICTypeOf_Fallback *New(ICStubSpace *space, JitCode *code) {
6067 if (!code)
6068 return nullptr;
6069 return space->allocate<ICTypeOf_Fallback>(code);
6070 }
6071
6072 class Compiler : public ICStubCompiler {
6073 protected:
6074 bool generateStubCode(MacroAssembler &masm);
6075
6076 public:
6077 Compiler(JSContext *cx)
6078 : ICStubCompiler(cx, ICStub::TypeOf_Fallback)
6079 { }
6080
6081 ICStub *getStub(ICStubSpace *space) {
6082 return ICTypeOf_Fallback::New(space, getStubCode());
6083 }
6084 };
6085 };
6086
6087 class ICTypeOf_Typed : public ICFallbackStub
6088 {
6089 friend class ICStubSpace;
6090
6091 ICTypeOf_Typed(JitCode *stubCode, JSType type)
6092 : ICFallbackStub(ICStub::TypeOf_Typed, stubCode)
6093 {
6094 extra_ = uint16_t(type);
6095 JS_ASSERT(JSType(extra_) == type);
6096 }
6097
6098 public:
6099 static inline ICTypeOf_Typed *New(ICStubSpace *space, JitCode *code, JSType type) {
6100 if (!code)
6101 return nullptr;
6102 return space->allocate<ICTypeOf_Typed>(code, type);
6103 }
6104
6105 JSType type() const {
6106 return JSType(extra_);
6107 }
6108
6109 class Compiler : public ICStubCompiler {
6110 protected:
6111 JSType type_;
6112 RootedString typeString_;
6113 bool generateStubCode(MacroAssembler &masm);
6114
6115 virtual int32_t getKey() const {
6116 return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16);
6117 }
6118
6119 public:
6120 Compiler(JSContext *cx, JSType type, HandleString string)
6121 : ICStubCompiler(cx, ICStub::TypeOf_Typed),
6122 type_(type),
6123 typeString_(cx, string)
6124 { }
6125
6126 ICStub *getStub(ICStubSpace *space) {
6127 return ICTypeOf_Typed::New(space, getStubCode(), type_);
6128 }
6129 };
6130 };
6131
6132 class ICRest_Fallback : public ICFallbackStub
6133 {
6134 friend class ICStubSpace;
6135
6136 HeapPtrObject templateObject_;
6137
6138 ICRest_Fallback(JitCode *stubCode, JSObject *templateObject)
6139 : ICFallbackStub(ICStub::Rest_Fallback, stubCode), templateObject_(templateObject)
6140 { }
6141
6142 public:
6143 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
6144
6145 static inline ICRest_Fallback *New(ICStubSpace *space, JitCode *code,
6146 JSObject *templateObject) {
6147 if (!code)
6148 return nullptr;
6149 return space->allocate<ICRest_Fallback>(code, templateObject);
6150 }
6151
6152 HeapPtrObject &templateObject() {
6153 return templateObject_;
6154 }
6155
6156 class Compiler : public ICStubCompiler {
6157 protected:
6158 RootedObject templateObject;
6159 bool generateStubCode(MacroAssembler &masm);
6160
6161 public:
6162 Compiler(JSContext *cx, JSObject *templateObject)
6163 : ICStubCompiler(cx, ICStub::Rest_Fallback),
6164 templateObject(cx, templateObject)
6165 { }
6166
6167 ICStub *getStub(ICStubSpace *space) {
6168 return ICRest_Fallback::New(space, getStubCode(), templateObject);
6169 }
6170 };
6171 };
6172
6173 // Stub for JSOP_RETSUB ("returning" from a |finally| block).
6174 class ICRetSub_Fallback : public ICFallbackStub
6175 {
6176 friend class ICStubSpace;
6177
6178 ICRetSub_Fallback(JitCode *stubCode)
6179 : ICFallbackStub(ICStub::RetSub_Fallback, stubCode)
6180 { }
6181
6182 public:
6183 static const uint32_t MAX_OPTIMIZED_STUBS = 8;
6184
6185 static inline ICRetSub_Fallback *New(ICStubSpace *space, JitCode *code) {
6186 if (!code)
6187 return nullptr;
6188 return space->allocate<ICRetSub_Fallback>(code);
6189 }
6190
6191 class Compiler : public ICStubCompiler {
6192 protected:
6193 bool generateStubCode(MacroAssembler &masm);
6194
6195 public:
6196 Compiler(JSContext *cx)
6197 : ICStubCompiler(cx, ICStub::RetSub_Fallback)
6198 { }
6199
6200 ICStub *getStub(ICStubSpace *space) {
6201 return ICRetSub_Fallback::New(space, getStubCode());
6202 }
6203 };
6204 };
6205
6206 // Optimized JSOP_RETSUB stub. Every stub maps a single pc offset to its
6207 // native code address.
6208 class ICRetSub_Resume : public ICStub
6209 {
6210 friend class ICStubSpace;
6211
6212 protected:
6213 uint32_t pcOffset_;
6214 uint8_t *addr_;
6215
6216 ICRetSub_Resume(JitCode *stubCode, uint32_t pcOffset, uint8_t *addr)
6217 : ICStub(ICStub::RetSub_Resume, stubCode),
6218 pcOffset_(pcOffset),
6219 addr_(addr)
6220 { }
6221
6222 public:
6223 static ICRetSub_Resume *New(ICStubSpace *space, JitCode *code, uint32_t pcOffset,
6224 uint8_t *addr) {
6225 if (!code)
6226 return nullptr;
6227 return space->allocate<ICRetSub_Resume>(code, pcOffset, addr);
6228 }
6229
6230 static size_t offsetOfPCOffset() {
6231 return offsetof(ICRetSub_Resume, pcOffset_);
6232 }
6233 static size_t offsetOfAddr() {
6234 return offsetof(ICRetSub_Resume, addr_);
6235 }
6236
6237 class Compiler : public ICStubCompiler {
6238 uint32_t pcOffset_;
6239 uint8_t *addr_;
6240
6241 bool generateStubCode(MacroAssembler &masm);
6242
6243 public:
6244 Compiler(JSContext *cx, uint32_t pcOffset, uint8_t *addr)
6245 : ICStubCompiler(cx, ICStub::RetSub_Resume),
6246 pcOffset_(pcOffset),
6247 addr_(addr)
6248 { }
6249
6250 ICStub *getStub(ICStubSpace *space) {
6251 return ICRetSub_Resume::New(space, getStubCode(), pcOffset_, addr_);
6252 }
6253 };
6254 };
6255
6256 } // namespace jit
6257 } // namespace js
6258
6259 #endif // JS_ION
6260
6261 #endif /* jit_BaselineIC_h */

mercurial