| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef jit_BaselineIC_h |
| #define jit_BaselineIC_h |
| |
| #ifdef JS_ION |
| |
| #include "jscntxt.h" |
| #include "jscompartment.h" |
| #include "jsgc.h" |
| #include "jsopcode.h" |
| #include "jsproxy.h" |
| #include "BaselineJIT.h" |
| #include "BaselineRegisters.h" |
| |
| #include "gc/Heap.h" |
| |
| namespace js { |
| namespace jit { |
| |
| // |
| // Baseline Inline Caches are polymorphic caches that aggressively |
| // share their stub code. |
| // |
| // Every polymorphic site contains a linked list of stubs which are |
| // specific to that site. These stubs are composed of a |StubData| |
| // structure that stores parametrization information (e.g. |
| // the shape pointer for a shape-check-and-property-get stub), any |
| // dynamic information (e.g. use counts), a pointer to the stub code, |
| // and a pointer to the next stub state in the linked list. |
| // |
| // Every BaselineScript keeps an table of |CacheDescriptor| data |
| // structures, which store the following: |
| // A pointer to the first StubData in the cache. |
| // The bytecode PC of the relevant IC. |
| // The machine-code PC where the call to the stubcode returns. |
| // |
| // A diagram: |
| // |
| // Control flow Pointers |
| // =======# ----. .----> |
| // # | | |
| // #======> \-----/ |
| // |
| // |
| // .---------------------------------------. |
| // | .-------------------------. | |
| // | | .----. | | |
| // Baseline | | | | | | |
| // JIT Code 0 ^ 1 ^ 2 ^ | | | |
| // +--------------+ .-->+-----+ +-----+ +-----+ | | | |
| // | | #=|==>| |==>| |==>| FB | | | | |
| // | | # | +-----+ +-----+ +-----+ | | | |
| // | | # | # # # | | | |
| // |==============|==# | # # # | | | |
| // |=== IC =======| | # # # | | | |
| // .->|==============|<===|======#=========#=========# | | | |
| // | | | | | | | |
| // | | | | | | | |
| // | | | | | | | |
| // | | | | v | | |
| // | | | | +---------+ | | |
| // | | | | | Fallback| | | |
| // | | | | | Stub | | | |
| // | | | | | Code | | | |
| // | | | | +---------+ | | |
| // | +--------------+ | | | |
| // | |_______ | +---------+ | | |
| // | | | | Stub |<---/ | |
| // | IC | \--. | Code | | |
| // | Descriptor | | +---------+ | |
| // | Table v | | |
| // | +-----------------+ | +---------+ | |
| // \--| Ins | PC | Stub |----/ | Stub |<-------/ |
| // +-----------------+ | Code | |
| // | ... | +---------+ |
| // +-----------------+ |
| // Shared |
| // Stub Code |
| // |
| // |
| // Type ICs |
| // ======== |
| // |
| // Type ICs are otherwise regular ICs that are actually nested within |
| // other IC chains. They serve to optimize locations in the code where the |
| // baseline compiler would have otherwise had to perform a type Monitor operation |
| // (e.g. the result of GetProp, GetElem, etc.), or locations where the baseline |
| // compiler would have had to modify a heap typeset using the type of an input |
| // value (e.g. SetProp, SetElem, etc.) |
| // |
| // There are two kinds of Type ICs: Monitor and Update. |
| // |
| // Note that type stub bodies are no-ops. The stubs only exist for their |
| // guards, and their existence simply signifies that the typeset (implicit) |
| // that is being checked already contains that type. |
| // |
| // TypeMonitor ICs |
| // --------------- |
| // Monitor ICs are shared between stubs in the general IC, and monitor the resulting |
| // types of getter operations (call returns, getprop outputs, etc.) |
| // |
| // +-----------+ +-----------+ +-----------+ +-----------+ |
| // ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub | |
| // +-----------+ +-----------+ +-----------+ +-----------+ |
| // | | | | |
| // |------------------/-----------------/ | |
| // v | |
| // +-----------+ +-----------+ +-----------+ | |
| // | Type 1 |---->| Type 2 |---->| Type FB | | |
| // +-----------+ +-----------+ +-----------+ | |
| // | | | | |
| // <----------/-----------------/------------------/------------------/ |
| // r e t u r n p a t h |
| // |
| // After an optimized IC stub successfully executes, it passes control to the type stub |
| // chain to check the resulting type. If no type stub succeeds, and the monitor fallback |
| // stub is reached, the monitor fallback stub performs a manual monitor, and also adds the |
| // appropriate type stub to the chain. |
| // |
| // The IC's main fallback, in addition to generating new mainline stubs, also generates |
| // type stubs as reflected by its returned value. |
| // |
| // NOTE: The type IC chain returns directly to the mainline code, not back to the |
| // stub it was entered from. Thus, entering a type IC is a matter of a |jump|, not |
| // a |call|. This allows us to safely call a VM Monitor function from within the monitor IC's |
| // fallback chain, since the return address (needed for stack inspection) is preserved. |
| // |
| // |
| // TypeUpdate ICs |
| // -------------- |
| // Update ICs update heap typesets and monitor the input types of setter operations |
| // (setelem, setprop inputs, etc.). Unlike monitor ICs, they are not shared |
| // between stubs on an IC, but instead are kept track of on a per-stub basis. |
| // |
| // This is because the main stubs for the operation will each identify a potentially |
| // different TypeObject to update. New input types must be tracked on a typeobject-to- |
| // typeobject basis. |
| // |
| // Type-update ICs cannot be called in tail position (they must return to the |
| // the stub that called them so that the stub may continue to perform its original |
| // purpose). This means that any VMCall to perform a manual type update from C++ must be |
| // done from within the main IC stub. This necessitates that the stub enter a |
| // "BaselineStub" frame before making the call. |
| // |
| // If the type-update IC chain could itself make the VMCall, then the BaselineStub frame |
| // must be entered before calling the type-update chain, and exited afterward. This |
| // is very expensive for a common case where we expect the type-update fallback to not |
| // be called. To avoid the cost of entering and exiting a BaselineStub frame when |
| // using the type-update IC chain, we design the chain to not perform any VM-calls |
| // in its fallback. |
| // |
| // Instead, the type-update IC chain is responsible for returning 1 or 0, depending |
| // on if a type is represented in the chain or not. The fallback stub simply returns |
| // 0, and all other optimized stubs return 1. |
| // If the chain returns 1, then the IC stub goes ahead and performs its operation. |
| // If the chain returns 0, then the IC stub performs a call to the fallback function |
| // inline (doing the requisite BaselineStub frame enter/exit). |
| // This allows us to avoid the expensive subfram enter/exit in the common case. |
| // |
| // r e t u r n p a t h |
| // <--------------.-----------------.-----------------.-----------------. |
| // | | | | |
| // +-----------+ +-----------+ +-----------+ +-----------+ |
| // ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub | |
| // +-----------+ +-----------+ +-----------+ +-----------+ |
| // | ^ | ^ | ^ |
| // | | | | | | |
| // | | | | | |----------------. |
| // | | | | v |1 |0 |
| // | | | | +-----------+ +-----------+ |
| // | | | | | Type 3.1 |--->| FB 3 | |
| // | | | | +-----------+ +-----------+ |
| // | | | | |
| // | | | \-------------.-----------------. |
| // | | | | | | |
| // | | v |1 |1 |0 |
| // | | +-----------+ +-----------+ +-----------+ |
| // | | | Type 2.1 |---->| Type 2.2 |---->| FB 2 | |
| // | | +-----------+ +-----------+ +-----------+ |
| // | | |
| // | \-------------.-----------------. |
| // | | | | |
| // v |1 |1 |0 |
| // +-----------+ +-----------+ +-----------+ |
| // | Type 1.1 |---->| Type 1.2 |---->| FB 1 | |
| // +-----------+ +-----------+ +-----------+ |
| // |
| |
| class ICStub; |
| class ICFallbackStub; |
| |
| // |
| // An entry in the Baseline IC descriptor table. |
| // |
| class ICEntry |
| { |
| private: |
| // Offset from the start of the JIT code where the IC |
| // load and call instructions are. |
| uint32_t returnOffset_; |
| |
| // The PC of this IC's bytecode op within the JSScript. |
| uint32_t pcOffset_ : 31; |
| |
| // Whether this IC is for a bytecode op. |
| uint32_t isForOp_ : 1; |
| |
| // A pointer to the baseline IC stub for this instruction. |
| ICStub *firstStub_; |
| |
| public: |
| ICEntry(uint32_t pcOffset, bool isForOp) |
| : returnOffset_(), pcOffset_(pcOffset), isForOp_(isForOp), firstStub_(NULL) |
| {} |
| |
| CodeOffsetLabel returnOffset() const { |
| return CodeOffsetLabel(returnOffset_); |
| } |
| |
| void setReturnOffset(CodeOffsetLabel offset) { |
| JS_ASSERT(offset.offset() <= (size_t) UINT32_MAX); |
| returnOffset_ = (uint32_t) offset.offset(); |
| } |
| |
| void fixupReturnOffset(MacroAssembler &masm) { |
| CodeOffsetLabel offset = returnOffset(); |
| offset.fixup(&masm); |
| JS_ASSERT(offset.offset() <= UINT32_MAX); |
| returnOffset_ = (uint32_t) offset.offset(); |
| } |
| |
| uint32_t pcOffset() const { |
| return pcOffset_; |
| } |
| |
| jsbytecode *pc(JSScript *script) const { |
| return script->code + pcOffset_; |
| } |
| |
| bool isForOp() const { |
| return isForOp_; |
| } |
| |
| bool hasStub() const { |
| return firstStub_ != NULL; |
| } |
| ICStub *firstStub() const { |
| JS_ASSERT(hasStub()); |
| return firstStub_; |
| } |
| |
| ICFallbackStub *fallbackStub() const; |
| |
| void setFirstStub(ICStub *stub) { |
| firstStub_ = stub; |
| } |
| |
| static inline size_t offsetOfFirstStub() { |
| return offsetof(ICEntry, firstStub_); |
| } |
| |
| inline ICStub **addressOfFirstStub() { |
| return &firstStub_; |
| } |
| }; |
| |
| // List of baseline IC stub kinds. |
| #define IC_STUB_KIND_LIST(_) \ |
| _(UseCount_Fallback) \ |
| \ |
| _(Profiler_Fallback) \ |
| _(Profiler_PushFunction) \ |
| \ |
| _(TypeMonitor_Fallback) \ |
| _(TypeMonitor_SingleObject) \ |
| _(TypeMonitor_TypeObject) \ |
| _(TypeMonitor_PrimitiveSet) \ |
| \ |
| _(TypeUpdate_Fallback) \ |
| _(TypeUpdate_SingleObject) \ |
| _(TypeUpdate_TypeObject) \ |
| _(TypeUpdate_PrimitiveSet) \ |
| \ |
| _(This_Fallback) \ |
| \ |
| _(NewArray_Fallback) \ |
| _(NewObject_Fallback) \ |
| \ |
| _(Compare_Fallback) \ |
| _(Compare_Int32) \ |
| _(Compare_Double) \ |
| _(Compare_NumberWithUndefined) \ |
| _(Compare_String) \ |
| _(Compare_Boolean) \ |
| _(Compare_Object) \ |
| _(Compare_ObjectWithUndefined) \ |
| _(Compare_Int32WithBoolean) \ |
| \ |
| _(ToBool_Fallback) \ |
| _(ToBool_Int32) \ |
| _(ToBool_String) \ |
| _(ToBool_NullUndefined) \ |
| _(ToBool_Double) \ |
| _(ToBool_Object) \ |
| \ |
| _(ToNumber_Fallback) \ |
| \ |
| _(BinaryArith_Fallback) \ |
| _(BinaryArith_Int32) \ |
| _(BinaryArith_Double) \ |
| _(BinaryArith_StringConcat) \ |
| _(BinaryArith_StringObjectConcat) \ |
| _(BinaryArith_BooleanWithInt32) \ |
| _(BinaryArith_DoubleWithInt32) \ |
| \ |
| _(UnaryArith_Fallback) \ |
| _(UnaryArith_Int32) \ |
| _(UnaryArith_Double) \ |
| \ |
| _(Call_Fallback) \ |
| _(Call_Scripted) \ |
| _(Call_AnyScripted) \ |
| _(Call_Native) \ |
| _(Call_ScriptedApplyArguments) \ |
| \ |
| _(GetElem_Fallback) \ |
| _(GetElem_Native) \ |
| _(GetElem_NativePrototype) \ |
| _(GetElem_String) \ |
| _(GetElem_Dense) \ |
| _(GetElem_TypedArray) \ |
| _(GetElem_Arguments) \ |
| \ |
| _(SetElem_Fallback) \ |
| _(SetElem_Dense) \ |
| _(SetElem_DenseAdd) \ |
| _(SetElem_TypedArray) \ |
| \ |
| _(In_Fallback) \ |
| \ |
| _(GetName_Fallback) \ |
| _(GetName_Global) \ |
| _(GetName_Scope0) \ |
| _(GetName_Scope1) \ |
| _(GetName_Scope2) \ |
| _(GetName_Scope3) \ |
| _(GetName_Scope4) \ |
| _(GetName_Scope5) \ |
| _(GetName_Scope6) \ |
| \ |
| _(BindName_Fallback) \ |
| \ |
| _(GetIntrinsic_Fallback) \ |
| _(GetIntrinsic_Constant) \ |
| \ |
| _(GetProp_Fallback) \ |
| _(GetProp_ArrayLength) \ |
| _(GetProp_TypedArrayLength) \ |
| _(GetProp_String) \ |
| _(GetProp_StringLength) \ |
| _(GetProp_Native) \ |
| _(GetProp_NativePrototype) \ |
| _(GetProp_CallScripted) \ |
| _(GetProp_CallNative) \ |
| _(GetProp_CallDOMProxyNative)\ |
| _(GetProp_CallDOMProxyWithGenerationNative)\ |
| _(GetProp_DOMProxyShadowed) \ |
| _(GetProp_ArgumentsLength) \ |
| \ |
| _(SetProp_Fallback) \ |
| _(SetProp_Native) \ |
| _(SetProp_NativeAdd) \ |
| _(SetProp_CallScripted) \ |
| _(SetProp_CallNative) \ |
| \ |
| _(TableSwitch) \ |
| \ |
| _(IteratorNew_Fallback) \ |
| _(IteratorMore_Fallback) \ |
| _(IteratorMore_Native) \ |
| _(IteratorNext_Fallback) \ |
| _(IteratorNext_Native) \ |
| _(IteratorClose_Fallback) \ |
| \ |
| _(InstanceOf_Fallback) \ |
| \ |
| _(TypeOf_Fallback) \ |
| _(TypeOf_Typed) \ |
| \ |
| _(Rest_Fallback) \ |
| \ |
| _(RetSub_Fallback) \ |
| _(RetSub_Resume) |
| |
| #define FORWARD_DECLARE_STUBS(kindName) class IC##kindName; |
| IC_STUB_KIND_LIST(FORWARD_DECLARE_STUBS) |
| #undef FORWARD_DECLARE_STUBS |
| |
| class ICMonitoredStub; |
| class ICMonitoredFallbackStub; |
| class ICUpdatedStub; |
| |
| // Constant iterator that traverses arbitrary chains of ICStubs. |
| // No requirements are made of the ICStub used to construct this |
| // iterator, aside from that the stub be part of a NULL-terminated |
| // chain. |
| // The iterator is considered to be at its end once it has been |
| // incremented _past_ the last stub. Thus, if 'atEnd()' returns |
| // true, the '*' and '->' operations are not valid. |
| class ICStubConstIterator |
| { |
| friend class ICStub; |
| friend class ICFallbackStub; |
| |
| private: |
| ICStub *currentStub_; |
| |
| public: |
| ICStubConstIterator(ICStub *currentStub) : currentStub_(currentStub) {} |
| |
| static ICStubConstIterator StartingAt(ICStub *stub) { |
| return ICStubConstIterator(stub); |
| } |
| static ICStubConstIterator End(ICStub *stub) { |
| return ICStubConstIterator(NULL); |
| } |
| |
| bool operator ==(const ICStubConstIterator &other) const { |
| return currentStub_ == other.currentStub_; |
| } |
| bool operator !=(const ICStubConstIterator &other) const { |
| return !(*this == other); |
| } |
| |
| ICStubConstIterator &operator++(); |
| |
| ICStubConstIterator operator++(int) { |
| ICStubConstIterator oldThis(*this); |
| ++(*this); |
| return oldThis; |
| } |
| |
| ICStub *operator *() const { |
| JS_ASSERT(currentStub_); |
| return currentStub_; |
| } |
| |
| ICStub *operator ->() const { |
| JS_ASSERT(currentStub_); |
| return currentStub_; |
| } |
| |
| bool atEnd() const { |
| return currentStub_ == NULL; |
| } |
| }; |
| |
| // Iterator that traverses "regular" IC chains that start at an ICEntry |
| // and are terminated with an ICFallbackStub. |
| // |
| // The iterator is considered to be at its end once it is _at_ the |
| // fallback stub. Thus, unlike the ICStubConstIterator, operators |
| // '*' and '->' are valid even if 'atEnd()' returns true - they |
| // will act on the fallback stub. |
| // |
| // This iterator also allows unlinking of stubs being traversed. |
| // Note that 'unlink' does not implicitly advance the iterator - |
| // it must be advanced explicitly using '++'. |
| class ICStubIterator |
| { |
| friend class ICFallbackStub; |
| |
| private: |
| ICEntry *icEntry_; |
| ICFallbackStub *fallbackStub_; |
| ICStub *previousStub_; |
| ICStub *currentStub_; |
| bool unlinked_; |
| |
| ICStubIterator(ICFallbackStub *fallbackStub, bool end=false); |
| public: |
| |
| bool operator ==(const ICStubIterator &other) const { |
| // == should only ever be called on stubs from the same chain. |
| JS_ASSERT(icEntry_ == other.icEntry_); |
| JS_ASSERT(fallbackStub_ == other.fallbackStub_); |
| return currentStub_ == other.currentStub_; |
| } |
| bool operator !=(const ICStubIterator &other) const { |
| return !(*this == other); |
| } |
| |
| ICStubIterator &operator++(); |
| |
| ICStubIterator operator++(int) { |
| ICStubIterator oldThis(*this); |
| ++(*this); |
| return oldThis; |
| } |
| |
| ICStub *operator *() const { |
| return currentStub_; |
| } |
| |
| ICStub *operator ->() const { |
| return currentStub_; |
| } |
| |
| bool atEnd() const { |
| return currentStub_ == (ICStub *) fallbackStub_; |
| } |
| |
| void unlink(Zone *zone); |
| }; |
| |
| // |
| // Base class for all IC stubs. |
| // |
| class ICStub |
| { |
| friend class ICFallbackStub; |
| |
| public: |
| enum Kind { |
| INVALID = 0, |
| #define DEF_ENUM_KIND(kindName) kindName, |
| IC_STUB_KIND_LIST(DEF_ENUM_KIND) |
| #undef DEF_ENUM_KIND |
| LIMIT |
| }; |
| |
| static inline bool IsValidKind(Kind k) { |
| return (k > INVALID) && (k < LIMIT); |
| } |
| |
| static const char *KindString(Kind k) { |
| switch(k) { |
| #define DEF_KIND_STR(kindName) case kindName: return #kindName; |
| IC_STUB_KIND_LIST(DEF_KIND_STR) |
| #undef DEF_KIND_STR |
| default: |
| JS_NOT_REACHED("Invalid kind."); |
| return "INVALID_KIND"; |
| } |
| } |
| |
| enum Trait { |
| Regular = 0x0, |
| Fallback = 0x1, |
| Monitored = 0x2, |
| MonitoredFallback = 0x3, |
| Updated = 0x4 |
| }; |
| |
| void markCode(JSTracer *trc, const char *name); |
| void updateCode(IonCode *stubCode); |
| void trace(JSTracer *trc); |
| |
| protected: |
| // The kind of the stub. |
| // High bit is 'isFallback' flag. |
| // Second high bit is 'isMonitored' flag. |
| Trait trait_ : 3; |
| Kind kind_ : 13; |
| |
| // A 16-bit field usable by subtypes of ICStub for subtype-specific small-info |
| uint16_t extra_; |
| |
| // The raw jitcode to call for this stub. |
| uint8_t *stubCode_; |
| |
| // Pointer to next IC stub. This is null for the last IC stub, which should |
| // either be a fallback or inert IC stub. |
| ICStub *next_; |
| |
| inline ICStub(Kind kind, IonCode *stubCode) |
| : trait_(Regular), |
| kind_(kind), |
| extra_(0), |
| stubCode_(stubCode->raw()), |
| next_(NULL) |
| { |
| JS_ASSERT(stubCode != NULL); |
| } |
| |
| inline ICStub(Kind kind, Trait trait, IonCode *stubCode) |
| : trait_(trait), |
| kind_(kind), |
| extra_(0), |
| stubCode_(stubCode->raw()), |
| next_(NULL) |
| { |
| JS_ASSERT(stubCode != NULL); |
| } |
| |
| inline Trait trait() const { |
| // Workaround for MSVC reading trait_ as signed value. |
| return (Trait)(trait_ & 0x7); |
| } |
| |
| public: |
| |
| inline Kind kind() const { |
| return static_cast<Kind>(kind_); |
| } |
| |
| inline bool isFallback() const { |
| return trait() == Fallback || trait() == MonitoredFallback; |
| } |
| |
| inline bool isMonitored() const { |
| return trait() == Monitored; |
| } |
| |
| inline bool isUpdated() const { |
| return trait() == Updated; |
| } |
| |
| inline bool isMonitoredFallback() const { |
| return trait() == MonitoredFallback; |
| } |
| |
| inline const ICFallbackStub *toFallbackStub() const { |
| JS_ASSERT(isFallback()); |
| return reinterpret_cast<const ICFallbackStub *>(this); |
| } |
| |
| inline ICFallbackStub *toFallbackStub() { |
| JS_ASSERT(isFallback()); |
| return reinterpret_cast<ICFallbackStub *>(this); |
| } |
| |
| inline const ICMonitoredStub *toMonitoredStub() const { |
| JS_ASSERT(isMonitored()); |
| return reinterpret_cast<const ICMonitoredStub *>(this); |
| } |
| |
| inline ICMonitoredStub *toMonitoredStub() { |
| JS_ASSERT(isMonitored()); |
| return reinterpret_cast<ICMonitoredStub *>(this); |
| } |
| |
| inline const ICMonitoredFallbackStub *toMonitoredFallbackStub() const { |
| JS_ASSERT(isMonitoredFallback()); |
| return reinterpret_cast<const ICMonitoredFallbackStub *>(this); |
| } |
| |
| inline ICMonitoredFallbackStub *toMonitoredFallbackStub() { |
| JS_ASSERT(isMonitoredFallback()); |
| return reinterpret_cast<ICMonitoredFallbackStub *>(this); |
| } |
| |
| inline const ICUpdatedStub *toUpdatedStub() const { |
| JS_ASSERT(isUpdated()); |
| return reinterpret_cast<const ICUpdatedStub *>(this); |
| } |
| |
| inline ICUpdatedStub *toUpdatedStub() { |
| JS_ASSERT(isUpdated()); |
| return reinterpret_cast<ICUpdatedStub *>(this); |
| } |
| |
| #define KIND_METHODS(kindName) \ |
| inline bool is##kindName() const { return kind() == kindName; } \ |
| inline const IC##kindName *to##kindName() const { \ |
| JS_ASSERT(is##kindName()); \ |
| return reinterpret_cast<const IC##kindName *>(this); \ |
| } \ |
| inline IC##kindName *to##kindName() { \ |
| JS_ASSERT(is##kindName()); \ |
| return reinterpret_cast<IC##kindName *>(this); \ |
| } |
| IC_STUB_KIND_LIST(KIND_METHODS) |
| #undef KIND_METHODS |
| |
| inline ICStub *next() const { |
| return next_; |
| } |
| |
| inline bool hasNext() const { |
| return next_ != NULL; |
| } |
| |
| inline void setNext(ICStub *stub) { |
| next_ = stub; |
| } |
| |
| inline ICStub **addressOfNext() { |
| return &next_; |
| } |
| |
| inline IonCode *ionCode() { |
| return IonCode::FromExecutable(stubCode_); |
| } |
| |
| inline uint8_t *rawStubCode() const { |
| return stubCode_; |
| } |
| |
| // This method is not valid on TypeUpdate stub chains! |
| inline ICFallbackStub *getChainFallback() { |
| ICStub *lastStub = this; |
| while (lastStub->next_) |
| lastStub = lastStub->next_; |
| JS_ASSERT(lastStub->isFallback()); |
| return lastStub->toFallbackStub(); |
| } |
| |
| inline ICStubConstIterator beginHere() { |
| return ICStubConstIterator::StartingAt(this); |
| } |
| |
| static inline size_t offsetOfNext() { |
| return offsetof(ICStub, next_); |
| } |
| |
| static inline size_t offsetOfStubCode() { |
| return offsetof(ICStub, stubCode_); |
| } |
| |
| static inline size_t offsetOfExtra() { |
| return offsetof(ICStub, extra_); |
| } |
| |
| static bool CanMakeCalls(ICStub::Kind kind) { |
| JS_ASSERT(IsValidKind(kind)); |
| switch (kind) { |
| case Call_Fallback: |
| case Call_Scripted: |
| case Call_AnyScripted: |
| case Call_Native: |
| case Call_ScriptedApplyArguments: |
| case UseCount_Fallback: |
| case GetProp_CallScripted: |
| case GetProp_CallNative: |
| case GetProp_CallDOMProxyNative: |
| case GetProp_CallDOMProxyWithGenerationNative: |
| case GetProp_DOMProxyShadowed: |
| case SetProp_CallScripted: |
| case SetProp_CallNative: |
| case RetSub_Fallback: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| // Optimized stubs get purged on GC. But some stubs can be active on the |
| // stack during GC - specifically the ones that can make calls. To ensure |
| // that these do not get purged, all stubs that can make calls are allocated |
| // in the fallback stub space. |
| bool allocatedInFallbackSpace() const { |
| JS_ASSERT(next()); |
| return CanMakeCalls(kind()); |
| } |
| }; |
| |
| class ICFallbackStub : public ICStub |
| { |
| friend class ICStubConstIterator; |
| protected: |
| // Fallback stubs need these fields to easily add new stubs to |
| // the linked list of stubs for an IC. |
| |
| // The IC entry for this linked list of stubs. |
| ICEntry *icEntry_; |
| |
| // The number of stubs kept in the IC entry. |
| uint32_t numOptimizedStubs_; |
| |
| // A pointer to the location stub pointer that needs to be |
| // changed to add a new "last" stub immediately before the fallback |
| // stub. This'll start out pointing to the icEntry's "firstStub_" |
| // field, and as new stubs are addd, it'll point to the current |
| // last stub's "next_" field. |
| ICStub **lastStubPtrAddr_; |
| |
| ICFallbackStub(Kind kind, IonCode *stubCode) |
| : ICStub(kind, ICStub::Fallback, stubCode), |
| icEntry_(NULL), |
| numOptimizedStubs_(0), |
| lastStubPtrAddr_(NULL) {} |
| |
| ICFallbackStub(Kind kind, Trait trait, IonCode *stubCode) |
| : ICStub(kind, trait, stubCode), |
| icEntry_(NULL), |
| numOptimizedStubs_(0), |
| lastStubPtrAddr_(NULL) |
| { |
| JS_ASSERT(trait == ICStub::Fallback || |
| trait == ICStub::MonitoredFallback); |
| } |
| |
| public: |
| inline ICEntry *icEntry() const { |
| return icEntry_; |
| } |
| |
| inline size_t numOptimizedStubs() const { |
| return (size_t) numOptimizedStubs_; |
| } |
| |
| // The icEntry and lastStubPtrAddr_ fields can't be initialized when the stub is |
| // created since the stub is created at compile time, and we won't know the IC entry |
| // address until after compile when the BaselineScript is created. This method |
| // allows these fields to be fixed up at that point. |
| void fixupICEntry(ICEntry *icEntry) { |
| JS_ASSERT(icEntry_ == NULL); |
| JS_ASSERT(lastStubPtrAddr_ == NULL); |
| icEntry_ = icEntry; |
| lastStubPtrAddr_ = icEntry_->addressOfFirstStub(); |
| } |
| |
| // Add a new stub to the IC chain terminated by this fallback stub. |
| void addNewStub(ICStub *stub) { |
| JS_ASSERT(*lastStubPtrAddr_ == this); |
| JS_ASSERT(stub->next() == NULL); |
| stub->setNext(this); |
| *lastStubPtrAddr_ = stub; |
| lastStubPtrAddr_ = stub->addressOfNext(); |
| numOptimizedStubs_++; |
| } |
| |
| ICStubConstIterator beginChainConst() const { |
| return ICStubConstIterator(icEntry_->firstStub()); |
| } |
| |
| ICStubIterator beginChain() { |
| return ICStubIterator(this); |
| } |
| |
| bool hasStub(ICStub::Kind kind) const { |
| for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) { |
| if (iter->kind() == kind) |
| return true; |
| } |
| return false; |
| } |
| |
| unsigned numStubsWithKind(ICStub::Kind kind) const { |
| unsigned count = 0; |
| for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) { |
| if (iter->kind() == kind) |
| count++; |
| } |
| return count; |
| } |
| |
| void unlinkStub(Zone *zone, ICStub *prev, ICStub *stub); |
| void unlinkStubsWithKind(JSContext *cx, ICStub::Kind kind); |
| }; |
| |
| // Monitored stubs are IC stubs that feed a single resulting value out to a |
| // type monitor operation. |
| class ICMonitoredStub : public ICStub |
| { |
| protected: |
| // Pointer to the start of the type monitoring stub chain. |
| ICStub *firstMonitorStub_; |
| |
| ICMonitoredStub(Kind kind, IonCode *stubCode, ICStub *firstMonitorStub); |
| |
| public: |
| inline void updateFirstMonitorStub(ICStub *monitorStub) { |
| // This should only be called once: when the first optimized monitor stub |
| // is added to the type monitor IC chain. |
| JS_ASSERT(firstMonitorStub_ && firstMonitorStub_->isTypeMonitor_Fallback()); |
| firstMonitorStub_ = monitorStub; |
| } |
| inline void resetFirstMonitorStub(ICStub *monitorFallback) { |
| JS_ASSERT(monitorFallback->isTypeMonitor_Fallback()); |
| firstMonitorStub_ = monitorFallback; |
| } |
| inline ICStub *firstMonitorStub() const { |
| return firstMonitorStub_; |
| } |
| |
| static inline size_t offsetOfFirstMonitorStub() { |
| return offsetof(ICMonitoredStub, firstMonitorStub_); |
| } |
| }; |
| |
| // Monitored fallback stubs - as the name implies. |
| class ICMonitoredFallbackStub : public ICFallbackStub |
| { |
| protected: |
| // Pointer to the fallback monitor stub. |
| ICTypeMonitor_Fallback *fallbackMonitorStub_; |
| |
| ICMonitoredFallbackStub(Kind kind, IonCode *stubCode) |
| : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode), |
| fallbackMonitorStub_(NULL) {} |
| |
| public: |
| bool initMonitoringChain(JSContext *cx, ICStubSpace *space); |
| bool addMonitorStubForValue(JSContext *cx, HandleScript script, HandleValue val); |
| |
| inline ICTypeMonitor_Fallback *fallbackMonitorStub() const { |
| return fallbackMonitorStub_; |
| } |
| |
| static inline size_t offsetOfFallbackMonitorStub() { |
| return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_); |
| } |
| }; |
| |
| // Updated stubs are IC stubs that use a TypeUpdate IC to track |
| // the status of heap typesets that need to be updated. |
| class ICUpdatedStub : public ICStub |
| { |
| protected: |
| // Pointer to the start of the type updating stub chain. |
| ICStub *firstUpdateStub_; |
| |
| static const uint32_t MAX_OPTIMIZED_STUBS = 8; |
| uint32_t numOptimizedStubs_; |
| |
| ICUpdatedStub(Kind kind, IonCode *stubCode) |
| : ICStub(kind, ICStub::Updated, stubCode), |
| firstUpdateStub_(NULL), |
| numOptimizedStubs_(0) |
| {} |
| |
| public: |
| bool initUpdatingChain(JSContext *cx, ICStubSpace *space); |
| |
| bool addUpdateStubForValue(JSContext *cx, HandleScript script, HandleObject obj, HandleId id, |
| HandleValue val); |
| |
| void addOptimizedUpdateStub(ICStub *stub) { |
| if (firstUpdateStub_->isTypeUpdate_Fallback()) { |
| stub->setNext(firstUpdateStub_); |
| firstUpdateStub_ = stub; |
| } else { |
| ICStub *iter = firstUpdateStub_; |
| JS_ASSERT(iter->next() != NULL); |
| while (!iter->next()->isTypeUpdate_Fallback()) |
| iter = iter->next(); |
| JS_ASSERT(iter->next()->next() == NULL); |
| stub->setNext(iter->next()); |
| iter->setNext(stub); |
| } |
| |
| numOptimizedStubs_++; |
| } |
| |
| inline ICStub *firstUpdateStub() const { |
| return firstUpdateStub_; |
| } |
| |
| bool hasTypeUpdateStub(ICStub::Kind kind) { |
| ICStub *stub = firstUpdateStub_; |
| do { |
| if (stub->kind() == kind) |
| return true; |
| |
| stub = stub->next(); |
| } while (stub); |
| |
| return false; |
| } |
| |
| inline uint32_t numOptimizedStubs() const { |
| return numOptimizedStubs_; |
| } |
| |
| static inline size_t offsetOfFirstUpdateStub() { |
| return offsetof(ICUpdatedStub, firstUpdateStub_); |
| } |
| }; |
| |
| // Base class for stubcode compilers. |
| class ICStubCompiler |
| { |
| // Prevent GC in the middle of stub compilation. |
| js::gc::AutoSuppressGC suppressGC; |
| |
| mozilla::DebugOnly<bool> entersStubFrame_; |
| |
| protected: |
| JSContext *cx; |
| ICStub::Kind kind; |
| |
| // By default the stubcode key is just the kind. |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind); |
| } |
| |
| virtual bool generateStubCode(MacroAssembler &masm) = 0; |
| virtual bool postGenerateStubCode(MacroAssembler &masm, Handle<IonCode *> genCode) { |
| return true; |
| } |
| IonCode *getStubCode(); |
| |
| ICStubCompiler(JSContext *cx, ICStub::Kind kind) |
| : suppressGC(cx), entersStubFrame_(false), cx(cx), kind(kind) |
| {} |
| |
| // Emits a tail call to a VMFunction wrapper. |
| bool tailCallVM(const VMFunction &fun, MacroAssembler &masm); |
| |
| // Emits a normal (non-tail) call to a VMFunction wrapper. |
| bool callVM(const VMFunction &fun, MacroAssembler &masm); |
| |
| // Emits a call to a type-update IC, assuming that the value to be |
| // checked is already in R0. |
| bool callTypeUpdateIC(MacroAssembler &masm, uint32_t objectOffset); |
| |
| // A stub frame is used when a stub wants to call into the VM without |
| // performing a tail call. This is required for the return address |
| // to pc mapping to work. |
| void enterStubFrame(MacroAssembler &masm, Register scratch); |
| void leaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false); |
| |
| // Some stubs need to emit SPS profiler updates. This emits the guarding |
| // jitcode for those stubs. If profiling is not enabled, jumps to the |
| // given label. |
| void guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip); |
| |
| inline GeneralRegisterSet availableGeneralRegs(size_t numInputs) const { |
| GeneralRegisterSet regs(GeneralRegisterSet::All()); |
| JS_ASSERT(!regs.has(BaselineStackReg)); |
| |
| #ifdef JS_CPU_ARM |
| JS_ASSERT(!regs.has(BaselineTailCallReg)); |
| #elif defined(JS_CPU_MIPS) |
| JS_ASSERT(!regs.has(BaselineTailCallReg)); |
| JS_ASSERT(!regs.has(BaselineSecondScratchReg)); |
| #endif |
| |
| regs.take(BaselineFrameReg); |
| regs.take(BaselineStubReg); |
| |
| #ifdef JS_CPU_X64 |
| regs.take(ExtractTemp0); |
| regs.take(ExtractTemp1); |
| #endif |
| |
| switch (numInputs) { |
| case 0: |
| break; |
| case 1: |
| regs.take(R0); |
| break; |
| case 2: |
| regs.take(R0); |
| regs.take(R1); |
| break; |
| default: |
| JS_NOT_REACHED("Invalid numInputs"); |
| } |
| |
| return regs; |
| } |
| |
| #ifdef JSGC_GENERATIONAL |
| inline bool emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, Register scratch, |
| GeneralRegisterSet saveRegs); |
| #endif |
| |
| public: |
| virtual ICStub *getStub(ICStubSpace *space) = 0; |
| |
| ICStubSpace *getStubSpace(JSScript *script) { |
| if (ICStub::CanMakeCalls(kind)) |
| return script->baselineScript()->fallbackStubSpace(); |
| return script->compartment()->ionCompartment()->optimizedStubSpace(); |
| } |
| }; |
| |
| // Base class for stub compilers that can generate multiple stubcodes. |
| // These compilers need access to the JSOp they are compiling for. |
| class ICMultiStubCompiler : public ICStubCompiler |
| { |
| protected: |
| JSOp op; |
| |
| // Stub keys for multi-stub kinds are composed of both the kind |
| // and the op they are compiled for. |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind) | (static_cast<int32_t>(op) << 16); |
| } |
| |
| ICMultiStubCompiler(JSContext *cx, ICStub::Kind kind, JSOp op) |
| : ICStubCompiler(cx, kind), op(op) {} |
| }; |
| |
| // UseCount_Fallback |
| |
| // A UseCount IC chain has only the fallback stub. |
| class ICUseCount_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICUseCount_Fallback(IonCode *stubCode) |
| : ICFallbackStub(ICStub::UseCount_Fallback, stubCode) |
| { } |
| |
| public: |
| static inline ICUseCount_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICUseCount_Fallback>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::UseCount_Fallback) |
| { } |
| |
| ICUseCount_Fallback *getStub(ICStubSpace *space) { |
| return ICUseCount_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| // Profiler_Fallback |
| |
| class ICProfiler_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICProfiler_Fallback(IonCode *stubCode) |
| : ICFallbackStub(ICStub::Profiler_Fallback, stubCode) |
| { } |
| |
| public: |
| static inline ICProfiler_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICProfiler_Fallback>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::Profiler_Fallback) |
| { } |
| |
| ICProfiler_Fallback *getStub(ICStubSpace *space) { |
| return ICProfiler_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| // Profiler_PushFunction |
| |
| class ICProfiler_PushFunction : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| protected: |
| const char *str_; |
| HeapPtrScript script_; |
| |
| ICProfiler_PushFunction(IonCode *stubCode, const char *str, HandleScript script); |
| |
| public: |
| static inline ICProfiler_PushFunction *New(ICStubSpace *space, IonCode *code, |
| const char *str, HandleScript script) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICProfiler_PushFunction>(code, str, script); |
| } |
| |
| HeapPtrScript &script() { |
| return script_; |
| } |
| |
| static size_t offsetOfStr() { |
| return offsetof(ICProfiler_PushFunction, str_); |
| } |
| static size_t offsetOfScript() { |
| return offsetof(ICProfiler_PushFunction, script_); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| const char *str_; |
| RootedScript script_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, const char *str, HandleScript script) |
| : ICStubCompiler(cx, ICStub::Profiler_PushFunction), |
| str_(str), |
| script_(cx, script) |
| { } |
| |
| ICProfiler_PushFunction *getStub(ICStubSpace *space) { |
| return ICProfiler_PushFunction::New(space, getStubCode(), str_, script_); |
| } |
| }; |
| }; |
| |
| |
| // TypeCheckPrimitiveSetStub |
| // Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given |
| // value's type falls within a set of primitive types. |
| |
| class TypeCheckPrimitiveSetStub : public ICStub |
| { |
| friend class ICStubSpace; |
| protected: |
| inline static uint16_t TypeToFlag(JSValueType type) { |
| return 1u << static_cast<unsigned>(type); |
| } |
| |
| inline static uint16_t ValidFlags() { |
| return ((TypeToFlag(JSVAL_TYPE_OBJECT) << 1) - 1) & ~TypeToFlag(JSVAL_TYPE_MAGIC); |
| } |
| |
| TypeCheckPrimitiveSetStub(Kind kind, IonCode *stubCode, uint16_t flags) |
| : ICStub(kind, stubCode) |
| { |
| JS_ASSERT(kind == TypeMonitor_PrimitiveSet || kind == TypeUpdate_PrimitiveSet); |
| JS_ASSERT(flags && !(flags & ~ValidFlags())); |
| extra_ = flags; |
| } |
| |
| TypeCheckPrimitiveSetStub *updateTypesAndCode(uint16_t flags, IonCode *code) { |
| JS_ASSERT(flags && !(flags & ~ValidFlags())); |
| if (!code) |
| return NULL; |
| extra_ = flags; |
| updateCode(code); |
| return this; |
| } |
| |
| public: |
| uint16_t typeFlags() const { |
| return extra_; |
| } |
| |
| bool containsType(JSValueType type) const { |
| JS_ASSERT(type <= JSVAL_TYPE_OBJECT); |
| JS_ASSERT(type != JSVAL_TYPE_MAGIC); |
| return extra_ & TypeToFlag(type); |
| } |
| |
| ICTypeMonitor_PrimitiveSet *toMonitorStub() { |
| return toTypeMonitor_PrimitiveSet(); |
| } |
| |
| ICTypeUpdate_PrimitiveSet *toUpdateStub() { |
| return toTypeUpdate_PrimitiveSet(); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| TypeCheckPrimitiveSetStub *existingStub_; |
| uint16_t flags_; |
| |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind) | (static_cast<int32_t>(flags_) << 16); |
| } |
| |
| public: |
| Compiler(JSContext *cx, Kind kind, TypeCheckPrimitiveSetStub *existingStub, |
| JSValueType type) |
| : ICStubCompiler(cx, kind), |
| existingStub_(existingStub), |
| flags_((existingStub ? existingStub->typeFlags() : 0) | TypeToFlag(type)) |
| { |
| JS_ASSERT_IF(existingStub_, flags_ != existingStub_->typeFlags()); |
| } |
| |
| TypeCheckPrimitiveSetStub *updateStub() { |
| JS_ASSERT(existingStub_); |
| return existingStub_->updateTypesAndCode(flags_, getStubCode()); |
| } |
| }; |
| }; |
| |
| // TypeMonitor |
| |
| // The TypeMonitor fallback stub is not always a regular fallback stub. When |
| // used for monitoring the values pushed by a bytecode it doesn't hold a |
| // pointer to the IC entry, but rather back to the main fallback stub for the |
| // IC (from which a pointer to the IC entry can be retrieved). When monitoring |
| // the types of 'this', arguments or other values with no associated IC, there |
| // is no main fallback stub, and the IC entry is referenced directly. |
| class ICTypeMonitor_Fallback : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| static const uint32_t MAX_OPTIMIZED_STUBS = 8; |
| |
| // Pointer to the main fallback stub for the IC or to the main IC entry, |
| // depending on hasFallbackStub. |
| union { |
| ICMonitoredFallbackStub *mainFallbackStub_; |
| ICEntry *icEntry_; |
| }; |
| |
| // Pointer to the first monitor stub. |
| ICStub *firstMonitorStub_; |
| |
| // Address of the last monitor stub's field pointing to this |
| // fallback monitor stub. This will get updated when new |
| // monitor stubs are created and added. |
| ICStub **lastMonitorStubPtrAddr_; |
| |
| // Count of optimized type monitor stubs in this chain. |
| uint32_t numOptimizedMonitorStubs_ : 8; |
| |
| // Whether this has a fallback stub referring to the IC entry. |
| bool hasFallbackStub_ : 1; |
| |
| // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX |
| // if this is monitoring the types of values pushed at some bytecode. |
| uint32_t argumentIndex_ : 23; |
| |
| static const uint32_t BYTECODE_INDEX = (1 << 23) - 1; |
| |
| ICTypeMonitor_Fallback(IonCode *stubCode, ICMonitoredFallbackStub *mainFallbackStub, |
| uint32_t argumentIndex) |
| : ICStub(ICStub::TypeMonitor_Fallback, stubCode), |
| mainFallbackStub_(mainFallbackStub), |
| firstMonitorStub_(thisFromCtor()), |
| lastMonitorStubPtrAddr_(NULL), |
| numOptimizedMonitorStubs_(0), |
| hasFallbackStub_(mainFallbackStub != NULL), |
| argumentIndex_(argumentIndex) |
| { } |
| |
| ICTypeMonitor_Fallback *thisFromCtor() { |
| return this; |
| } |
| |
| void addOptimizedMonitorStub(ICStub *stub) { |
| stub->setNext(this); |
| |
| JS_ASSERT((lastMonitorStubPtrAddr_ != NULL) == |
| (numOptimizedMonitorStubs_ || !hasFallbackStub_)); |
| |
| if (lastMonitorStubPtrAddr_) |
| *lastMonitorStubPtrAddr_ = stub; |
| |
| if (numOptimizedMonitorStubs_ == 0) { |
| JS_ASSERT(firstMonitorStub_ == this); |
| firstMonitorStub_ = stub; |
| } else { |
| JS_ASSERT(firstMonitorStub_ != NULL); |
| } |
| |
| lastMonitorStubPtrAddr_ = stub->addressOfNext(); |
| numOptimizedMonitorStubs_++; |
| } |
| |
| public: |
| static inline ICTypeMonitor_Fallback *New( |
| ICStubSpace *space, IonCode *code, ICMonitoredFallbackStub *mainFbStub, |
| uint32_t argumentIndex) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICTypeMonitor_Fallback>(code, mainFbStub, argumentIndex); |
| } |
| |
| bool hasStub(ICStub::Kind kind) { |
| ICStub *stub = firstMonitorStub_; |
| do { |
| if (stub->kind() == kind) |
| return true; |
| |
| stub = stub->next(); |
| } while (stub); |
| |
| return false; |
| } |
| |
| inline ICFallbackStub *mainFallbackStub() const { |
| JS_ASSERT(hasFallbackStub_); |
| return mainFallbackStub_; |
| } |
| |
| inline ICEntry *icEntry() const { |
| return hasFallbackStub_ ? mainFallbackStub()->icEntry() : icEntry_; |
| } |
| |
| inline ICStub *firstMonitorStub() const { |
| return firstMonitorStub_; |
| } |
| |
| static inline size_t offsetOfFirstMonitorStub() { |
| return offsetof(ICTypeMonitor_Fallback, firstMonitorStub_); |
| } |
| |
| inline uint32_t numOptimizedMonitorStubs() const { |
| return numOptimizedMonitorStubs_; |
| } |
| |
| inline bool monitorsThis() const { |
| return argumentIndex_ == 0; |
| } |
| |
| inline bool monitorsArgument(uint32_t *pargument) const { |
| if (argumentIndex_ > 0 && argumentIndex_ < BYTECODE_INDEX) { |
| *pargument = argumentIndex_ - 1; |
| return true; |
| } |
| return false; |
| } |
| |
| inline bool monitorsBytecode() const { |
| return argumentIndex_ == BYTECODE_INDEX; |
| } |
| |
| // Fixup the IC entry as for a normal fallback stub, for this/arguments. |
| void fixupICEntry(ICEntry *icEntry) { |
| JS_ASSERT(!hasFallbackStub_); |
| JS_ASSERT(icEntry_ == NULL); |
| JS_ASSERT(lastMonitorStubPtrAddr_ == NULL); |
| icEntry_ = icEntry; |
| lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub(); |
| } |
| |
| // Create a new monitor stub for the type of the given value, and |
| // add it to this chain. |
| bool addMonitorStubForValue(JSContext *cx, HandleScript script, HandleValue val); |
| |
| void resetMonitorStubChain(Zone *zone); |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| ICMonitoredFallbackStub *mainFallbackStub_; |
| uint32_t argumentIndex_; |
| |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, ICMonitoredFallbackStub *mainFallbackStub) |
| : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback), |
| mainFallbackStub_(mainFallbackStub), |
| argumentIndex_(BYTECODE_INDEX) |
| { } |
| |
| Compiler(JSContext *cx, uint32_t argumentIndex) |
| : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback), |
| mainFallbackStub_(NULL), |
| argumentIndex_(argumentIndex) |
| { } |
| |
| ICTypeMonitor_Fallback *getStub(ICStubSpace *space) { |
| return ICTypeMonitor_Fallback::New(space, getStubCode(), mainFallbackStub_, |
| argumentIndex_); |
| } |
| }; |
| }; |
| |
| class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub |
| { |
| friend class ICStubSpace; |
| |
| ICTypeMonitor_PrimitiveSet(IonCode *stubCode, uint16_t flags) |
| : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags) |
| {} |
| |
| public: |
| static inline ICTypeMonitor_PrimitiveSet *New(ICStubSpace *space, IonCode *code, |
| uint16_t flags) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICTypeMonitor_PrimitiveSet>(code, flags); |
| } |
| |
| class Compiler : public TypeCheckPrimitiveSetStub::Compiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, ICTypeMonitor_PrimitiveSet *existingStub, JSValueType type) |
| : TypeCheckPrimitiveSetStub::Compiler(cx, TypeMonitor_PrimitiveSet, existingStub, type) |
| {} |
| |
| ICTypeMonitor_PrimitiveSet *updateStub() { |
| TypeCheckPrimitiveSetStub *stub = |
| this->TypeCheckPrimitiveSetStub::Compiler::updateStub(); |
| if (!stub) |
| return NULL; |
| return stub->toMonitorStub(); |
| } |
| |
| ICTypeMonitor_PrimitiveSet *getStub(ICStubSpace *space) { |
| JS_ASSERT(!existingStub_); |
| return ICTypeMonitor_PrimitiveSet::New(space, getStubCode(), flags_); |
| } |
| }; |
| }; |
| |
| class ICTypeMonitor_SingleObject : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| HeapPtrObject obj_; |
| |
| ICTypeMonitor_SingleObject(IonCode *stubCode, HandleObject obj); |
| |
| public: |
| static inline ICTypeMonitor_SingleObject *New( |
| ICStubSpace *space, IonCode *code, HandleObject obj) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICTypeMonitor_SingleObject>(code, obj); |
| } |
| |
| HeapPtrObject &object() { |
| return obj_; |
| } |
| |
| static size_t offsetOfObject() { |
| return offsetof(ICTypeMonitor_SingleObject, obj_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| HandleObject obj_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, HandleObject obj) |
| : ICStubCompiler(cx, TypeMonitor_SingleObject), |
| obj_(obj) |
| { } |
| |
| ICTypeMonitor_SingleObject *getStub(ICStubSpace *space) { |
| return ICTypeMonitor_SingleObject::New(space, getStubCode(), obj_); |
| } |
| }; |
| }; |
| |
| class ICTypeMonitor_TypeObject : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| HeapPtrTypeObject type_; |
| |
| ICTypeMonitor_TypeObject(IonCode *stubCode, HandleTypeObject type); |
| |
| public: |
| static inline ICTypeMonitor_TypeObject *New( |
| ICStubSpace *space, IonCode *code, HandleTypeObject type) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICTypeMonitor_TypeObject>(code, type); |
| } |
| |
| HeapPtrTypeObject &type() { |
| return type_; |
| } |
| |
| static size_t offsetOfType() { |
| return offsetof(ICTypeMonitor_TypeObject, type_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| HandleTypeObject type_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, HandleTypeObject type) |
| : ICStubCompiler(cx, TypeMonitor_TypeObject), |
| type_(type) |
| { } |
| |
| ICTypeMonitor_TypeObject *getStub(ICStubSpace *space) { |
| return ICTypeMonitor_TypeObject::New(space, getStubCode(), type_); |
| } |
| }; |
| }; |
| |
| // TypeUpdate |
| |
| extern const VMFunction DoTypeUpdateFallbackInfo; |
| |
| // The TypeUpdate fallback is not a regular fallback, since it just |
| // forwards to a different entry point in the main fallback stub. |
| class ICTypeUpdate_Fallback : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICTypeUpdate_Fallback(IonCode *stubCode) |
| : ICStub(ICStub::TypeUpdate_Fallback, stubCode) |
| {} |
| |
| public: |
| static inline ICTypeUpdate_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICTypeUpdate_Fallback>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::TypeUpdate_Fallback) |
| { } |
| |
| ICTypeUpdate_Fallback *getStub(ICStubSpace *space) { |
| return ICTypeUpdate_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICTypeUpdate_PrimitiveSet : public TypeCheckPrimitiveSetStub |
| { |
| friend class ICStubSpace; |
| |
| ICTypeUpdate_PrimitiveSet(IonCode *stubCode, uint16_t flags) |
| : TypeCheckPrimitiveSetStub(TypeUpdate_PrimitiveSet, stubCode, flags) |
| {} |
| |
| public: |
| static inline ICTypeUpdate_PrimitiveSet *New(ICStubSpace *space, IonCode *code, |
| uint16_t flags) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICTypeUpdate_PrimitiveSet>(code, flags); |
| } |
| |
| class Compiler : public TypeCheckPrimitiveSetStub::Compiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, ICTypeUpdate_PrimitiveSet *existingStub, JSValueType type) |
| : TypeCheckPrimitiveSetStub::Compiler(cx, TypeUpdate_PrimitiveSet, existingStub, type) |
| {} |
| |
| ICTypeUpdate_PrimitiveSet *updateStub() { |
| TypeCheckPrimitiveSetStub *stub = |
| this->TypeCheckPrimitiveSetStub::Compiler::updateStub(); |
| if (!stub) |
| return NULL; |
| return stub->toUpdateStub(); |
| } |
| |
| ICTypeUpdate_PrimitiveSet *getStub(ICStubSpace *space) { |
| JS_ASSERT(!existingStub_); |
| return ICTypeUpdate_PrimitiveSet::New(space, getStubCode(), flags_); |
| } |
| }; |
| }; |
| |
| // Type update stub to handle a singleton object. |
| class ICTypeUpdate_SingleObject : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| HeapPtrObject obj_; |
| |
| ICTypeUpdate_SingleObject(IonCode *stubCode, HandleObject obj); |
| |
| public: |
| static inline ICTypeUpdate_SingleObject *New(ICStubSpace *space, IonCode *code, |
| HandleObject obj) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICTypeUpdate_SingleObject>(code, obj); |
| } |
| |
| HeapPtrObject &object() { |
| return obj_; |
| } |
| |
| static size_t offsetOfObject() { |
| return offsetof(ICTypeUpdate_SingleObject, obj_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| HandleObject obj_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, HandleObject obj) |
| : ICStubCompiler(cx, TypeUpdate_SingleObject), |
| obj_(obj) |
| { } |
| |
| ICTypeUpdate_SingleObject *getStub(ICStubSpace *space) { |
| return ICTypeUpdate_SingleObject::New(space, getStubCode(), obj_); |
| } |
| }; |
| }; |
| |
| // Type update stub to handle a single TypeObject. |
| class ICTypeUpdate_TypeObject : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| HeapPtrTypeObject type_; |
| |
| ICTypeUpdate_TypeObject(IonCode *stubCode, HandleTypeObject type); |
| |
| public: |
| static inline ICTypeUpdate_TypeObject *New(ICStubSpace *space, IonCode *code, |
| HandleTypeObject type) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICTypeUpdate_TypeObject>(code, type); |
| } |
| |
| HeapPtrTypeObject &type() { |
| return type_; |
| } |
| |
| static size_t offsetOfType() { |
| return offsetof(ICTypeUpdate_TypeObject, type_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| HandleTypeObject type_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, HandleTypeObject type) |
| : ICStubCompiler(cx, TypeUpdate_TypeObject), |
| type_(type) |
| { } |
| |
| ICTypeUpdate_TypeObject *getStub(ICStubSpace *space) { |
| return ICTypeUpdate_TypeObject::New(space, getStubCode(), type_); |
| } |
| }; |
| }; |
| |
| // This |
| // JSOP_THIS |
| |
| class ICThis_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICThis_Fallback(IonCode *stubCode) |
| : ICFallbackStub(ICStub::This_Fallback, stubCode) {} |
| |
| public: |
| static inline ICThis_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICThis_Fallback>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::This_Fallback) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICThis_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICNewArray_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICNewArray_Fallback(IonCode *stubCode) |
| : ICFallbackStub(ICStub::NewArray_Fallback, stubCode) |
| {} |
| |
| public: |
| static inline ICNewArray_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICNewArray_Fallback>(code); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::NewArray_Fallback) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICNewArray_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICNewObject_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICNewObject_Fallback(IonCode *stubCode) |
| : ICFallbackStub(ICStub::NewObject_Fallback, stubCode) |
| {} |
| |
| public: |
| static inline ICNewObject_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICNewObject_Fallback>(code); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::NewObject_Fallback) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICNewObject_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| // Compare |
| // JSOP_LT |
| // JSOP_GT |
| |
| class ICCompare_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_Fallback(IonCode *stubCode) |
| : ICFallbackStub(ICStub::Compare_Fallback, stubCode) {} |
| |
| public: |
| static const uint32_t MAX_OPTIMIZED_STUBS = 8; |
| |
| static inline ICCompare_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_Fallback>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::Compare_Fallback) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICCompare_Int32 : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_Int32(IonCode *stubCode) |
| : ICStub(ICStub::Compare_Int32, stubCode) {} |
| |
| public: |
| static inline ICCompare_Int32 *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_Int32>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, JSOp op) |
| : ICMultiStubCompiler(cx, ICStub::Compare_Int32, op) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_Int32::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICCompare_Double : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_Double(IonCode *stubCode) |
| : ICStub(ICStub::Compare_Double, stubCode) |
| {} |
| |
| public: |
| static inline ICCompare_Double *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_Double>(code); |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, JSOp op) |
| : ICMultiStubCompiler(cx, ICStub::Compare_Double, op) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_Double::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICCompare_NumberWithUndefined : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_NumberWithUndefined(IonCode *stubCode, bool lhsIsUndefined) |
| : ICStub(ICStub::Compare_NumberWithUndefined, stubCode) |
| { |
| extra_ = lhsIsUndefined; |
| } |
| |
| public: |
| static inline ICCompare_NumberWithUndefined *New(ICStubSpace *space, IonCode *code, bool lhsIsUndefined) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_NumberWithUndefined>(code, lhsIsUndefined); |
| } |
| |
| bool lhsIsUndefined() { |
| return extra_; |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| bool lhsIsUndefined; |
| |
| public: |
| Compiler(JSContext *cx, JSOp op, bool lhsIsUndefined) |
| : ICMultiStubCompiler(cx, ICStub::Compare_NumberWithUndefined, op), |
| lhsIsUndefined(lhsIsUndefined) |
| {} |
| |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind) |
| | (static_cast<int32_t>(op) << 16) |
| | (static_cast<int32_t>(lhsIsUndefined) << 24); |
| } |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_NumberWithUndefined::New(space, getStubCode(), lhsIsUndefined); |
| } |
| }; |
| }; |
| |
| class ICCompare_String : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_String(IonCode *stubCode) |
| : ICStub(ICStub::Compare_String, stubCode) |
| {} |
| |
| public: |
| static inline ICCompare_String *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_String>(code); |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, JSOp op) |
| : ICMultiStubCompiler(cx, ICStub::Compare_String, op) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_String::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICCompare_Boolean : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_Boolean(IonCode *stubCode) |
| : ICStub(ICStub::Compare_Boolean, stubCode) |
| {} |
| |
| public: |
| static inline ICCompare_Boolean *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_Boolean>(code); |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, JSOp op) |
| : ICMultiStubCompiler(cx, ICStub::Compare_Boolean, op) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_Boolean::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICCompare_Object : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_Object(IonCode *stubCode) |
| : ICStub(ICStub::Compare_Object, stubCode) |
| {} |
| |
| public: |
| static inline ICCompare_Object *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_Object>(code); |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, JSOp op) |
| : ICMultiStubCompiler(cx, ICStub::Compare_Object, op) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_Object::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICCompare_ObjectWithUndefined : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_ObjectWithUndefined(IonCode *stubCode) |
| : ICStub(ICStub::Compare_ObjectWithUndefined, stubCode) |
| {} |
| |
| public: |
| static inline ICCompare_ObjectWithUndefined *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_ObjectWithUndefined>(code); |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| bool lhsIsUndefined; |
| bool compareWithNull; |
| |
| public: |
| Compiler(JSContext *cx, JSOp op, bool lhsIsUndefined, bool compareWithNull) |
| : ICMultiStubCompiler(cx, ICStub::Compare_ObjectWithUndefined, op), |
| lhsIsUndefined(lhsIsUndefined), |
| compareWithNull(compareWithNull) |
| {} |
| |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind) |
| | (static_cast<int32_t>(op) << 16) |
| | (static_cast<int32_t>(lhsIsUndefined) << 24) |
| | (static_cast<int32_t>(compareWithNull) << 25); |
| } |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_ObjectWithUndefined::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICCompare_Int32WithBoolean : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICCompare_Int32WithBoolean(IonCode *stubCode, bool lhsIsInt32) |
| : ICStub(ICStub::Compare_Int32WithBoolean, stubCode) |
| { |
| extra_ = lhsIsInt32; |
| } |
| |
| public: |
| static inline ICCompare_Int32WithBoolean *New(ICStubSpace *space, IonCode *code, |
| bool lhsIsInt32) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICCompare_Int32WithBoolean>(code, lhsIsInt32); |
| } |
| |
| bool lhsIsInt32() const { |
| return extra_; |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| JSOp op_; |
| bool lhsIsInt32_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| virtual int32_t getKey() const { |
| return (static_cast<int32_t>(kind) | (static_cast<int32_t>(op_) << 16) | |
| (static_cast<int32_t>(lhsIsInt32_) << 24)); |
| } |
| |
| public: |
| Compiler(JSContext *cx, JSOp op, bool lhsIsInt32) |
| : ICStubCompiler(cx, ICStub::Compare_Int32WithBoolean), |
| op_(op), |
| lhsIsInt32_(lhsIsInt32) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICCompare_Int32WithBoolean::New(space, getStubCode(), lhsIsInt32_); |
| } |
| }; |
| }; |
| |
| // ToBool |
| // JSOP_IFNE |
| |
| class ICToBool_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICToBool_Fallback(IonCode *stubCode) |
| : ICFallbackStub(ICStub::ToBool_Fallback, stubCode) {} |
| |
| public: |
| static const uint32_t MAX_OPTIMIZED_STUBS = 8; |
| |
| static inline ICToBool_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICToBool_Fallback>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::ToBool_Fallback) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICToBool_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICToBool_Int32 : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICToBool_Int32(IonCode *stubCode) |
| : ICStub(ICStub::ToBool_Int32, stubCode) {} |
| |
| public: |
| static inline ICToBool_Int32 *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICToBool_Int32>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::ToBool_Int32) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICToBool_Int32::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICToBool_String : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICToBool_String(IonCode *stubCode) |
| : ICStub(ICStub::ToBool_String, stubCode) {} |
| |
| public: |
| static inline ICToBool_String *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICToBool_String>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::ToBool_String) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICToBool_String::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICToBool_NullUndefined : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICToBool_NullUndefined(IonCode *stubCode) |
| : ICStub(ICStub::ToBool_NullUndefined, stubCode) {} |
| |
| public: |
| static inline ICToBool_NullUndefined *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICToBool_NullUndefined>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::ToBool_NullUndefined) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICToBool_NullUndefined::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICToBool_Double : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICToBool_Double(IonCode *stubCode) |
| : ICStub(ICStub::ToBool_Double, stubCode) {} |
| |
| public: |
| static inline ICToBool_Double *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICToBool_Double>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::ToBool_Double) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICToBool_Double::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICToBool_Object : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICToBool_Object(IonCode *stubCode) |
| : ICStub(ICStub::ToBool_Object, stubCode) {} |
| |
| public: |
| static inline ICToBool_Object *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICToBool_Object>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::ToBool_Object) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICToBool_Object::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| // ToNumber |
| // JSOP_POS |
| |
| class ICToNumber_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICToNumber_Fallback(IonCode *stubCode) |
| : ICFallbackStub(ICStub::ToNumber_Fallback, stubCode) {} |
| |
| public: |
| static inline ICToNumber_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICToNumber_Fallback>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::ToNumber_Fallback) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICToNumber_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| // BinaryArith |
| // JSOP_ADD |
| // JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR |
| // JSOP_LSH, JSOP_RSH, JSOP_URSH |
| |
| class ICBinaryArith_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICBinaryArith_Fallback(IonCode *stubCode) |
| : ICFallbackStub(BinaryArith_Fallback, stubCode) |
| { |
| extra_ = 0; |
| } |
| |
| public: |
| static const uint32_t MAX_OPTIMIZED_STUBS = 8; |
| |
| static inline ICBinaryArith_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICBinaryArith_Fallback>(code); |
| } |
| |
| bool sawDoubleResult() { |
| return extra_; |
| } |
| void setSawDoubleResult() { |
| extra_ = 1; |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::BinaryArith_Fallback) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICBinaryArith_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICBinaryArith_Int32 : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICBinaryArith_Int32(IonCode *stubCode, bool allowDouble) |
| : ICStub(BinaryArith_Int32, stubCode) |
| { |
| extra_ = allowDouble; |
| } |
| |
| public: |
| static inline ICBinaryArith_Int32 *New(ICStubSpace *space, IonCode *code, bool allowDouble) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICBinaryArith_Int32>(code, allowDouble); |
| } |
| bool allowDouble() const { |
| return extra_; |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| JSOp op_; |
| bool allowDouble_; |
| |
| bool generateStubCode(MacroAssembler &masm); |
| |
| // Stub keys shift-stubs need to encode the kind, the JSOp and if we allow doubles. |
| virtual int32_t getKey() const { |
| return (static_cast<int32_t>(kind) | (static_cast<int32_t>(op_) << 16) | |
| (static_cast<int32_t>(allowDouble_) << 24)); |
| } |
| |
| public: |
| Compiler(JSContext *cx, JSOp op, bool allowDouble) |
| : ICStubCompiler(cx, ICStub::BinaryArith_Int32), |
| op_(op), allowDouble_(allowDouble) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICBinaryArith_Int32::New(space, getStubCode(), allowDouble_); |
| } |
| }; |
| }; |
| |
| class ICBinaryArith_StringConcat : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICBinaryArith_StringConcat(IonCode *stubCode) |
| : ICStub(BinaryArith_StringConcat, stubCode) |
| {} |
| |
| public: |
| static inline ICBinaryArith_StringConcat *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICBinaryArith_StringConcat>(code); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::BinaryArith_StringConcat) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICBinaryArith_StringConcat::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICBinaryArith_StringObjectConcat : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICBinaryArith_StringObjectConcat(IonCode *stubCode, bool lhsIsString) |
| : ICStub(BinaryArith_StringObjectConcat, stubCode) |
| { |
| extra_ = lhsIsString; |
| } |
| |
| public: |
| static inline ICBinaryArith_StringObjectConcat *New(ICStubSpace *space, IonCode *code, |
| bool lhsIsString) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICBinaryArith_StringObjectConcat>(code, lhsIsString); |
| } |
| |
| bool lhsIsString() const { |
| return extra_; |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool lhsIsString_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind) | (static_cast<int32_t>(lhsIsString_) << 16); |
| } |
| |
| public: |
| Compiler(JSContext *cx, bool lhsIsString) |
| : ICStubCompiler(cx, ICStub::BinaryArith_StringObjectConcat), |
| lhsIsString_(lhsIsString) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICBinaryArith_StringObjectConcat::New(space, getStubCode(), lhsIsString_); |
| } |
| }; |
| }; |
| |
| class ICBinaryArith_Double : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICBinaryArith_Double(IonCode *stubCode) |
| : ICStub(BinaryArith_Double, stubCode) |
| {} |
| |
| public: |
| static inline ICBinaryArith_Double *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICBinaryArith_Double>(code); |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, JSOp op) |
| : ICMultiStubCompiler(cx, ICStub::BinaryArith_Double, op) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICBinaryArith_Double::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICBinaryArith_BooleanWithInt32 : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICBinaryArith_BooleanWithInt32(IonCode *stubCode, bool lhsIsBool, bool rhsIsBool) |
| : ICStub(BinaryArith_BooleanWithInt32, stubCode) |
| { |
| JS_ASSERT(lhsIsBool || rhsIsBool); |
| extra_ = 0; |
| if (lhsIsBool) |
| extra_ |= 1; |
| if (rhsIsBool) |
| extra_ |= 2; |
| } |
| |
| public: |
| static inline ICBinaryArith_BooleanWithInt32 *New(ICStubSpace *space, IonCode *code, |
| bool lhsIsBool, bool rhsIsBool) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICBinaryArith_BooleanWithInt32>(code, lhsIsBool, rhsIsBool); |
| } |
| |
| bool lhsIsBoolean() const { |
| return extra_ & 1; |
| } |
| |
| bool rhsIsBoolean() const { |
| return extra_ & 2; |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| JSOp op_; |
| bool lhsIsBool_; |
| bool rhsIsBool_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind) | (static_cast<int32_t>(op_) << 16) | |
| (static_cast<int32_t>(lhsIsBool_) << 24) | |
| (static_cast<int32_t>(rhsIsBool_) << 25); |
| } |
| |
| public: |
| Compiler(JSContext *cx, JSOp op, bool lhsIsBool, bool rhsIsBool) |
| : ICStubCompiler(cx, ICStub::BinaryArith_BooleanWithInt32), |
| op_(op), lhsIsBool_(lhsIsBool), rhsIsBool_(rhsIsBool) |
| { |
| JS_ASSERT(op_ == JSOP_ADD || op_ == JSOP_SUB || op_ == JSOP_BITOR || |
| op_ == JSOP_BITAND || op_ == JSOP_BITXOR); |
| JS_ASSERT(lhsIsBool_ || rhsIsBool_); |
| } |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICBinaryArith_BooleanWithInt32::New(space, getStubCode(), |
| lhsIsBool_, rhsIsBool_); |
| } |
| }; |
| }; |
| |
| class ICBinaryArith_DoubleWithInt32 : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICBinaryArith_DoubleWithInt32(IonCode *stubCode, bool lhsIsDouble) |
| : ICStub(BinaryArith_DoubleWithInt32, stubCode) |
| { |
| extra_ = lhsIsDouble; |
| } |
| |
| public: |
| static inline ICBinaryArith_DoubleWithInt32 *New(ICStubSpace *space, IonCode *code, |
| bool lhsIsDouble) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICBinaryArith_DoubleWithInt32>(code, lhsIsDouble); |
| } |
| |
| bool lhsIsDouble() const { |
| return extra_; |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool lhsIsDouble_; |
| bool generateStubCode(MacroAssembler &masm); |
| |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind) | (static_cast<int32_t>(op) << 16) | |
| (static_cast<int32_t>(lhsIsDouble_) << 24); |
| } |
| |
| public: |
| Compiler(JSContext *cx, JSOp op, bool lhsIsDouble) |
| : ICMultiStubCompiler(cx, ICStub::BinaryArith_DoubleWithInt32, op), |
| lhsIsDouble_(lhsIsDouble) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICBinaryArith_DoubleWithInt32::New(space, getStubCode(), lhsIsDouble_); |
| } |
| }; |
| }; |
| |
| // UnaryArith |
| // JSOP_BITNOT |
| // JSOP_NEG |
| |
| class ICUnaryArith_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICUnaryArith_Fallback(IonCode *stubCode) |
| : ICFallbackStub(UnaryArith_Fallback, stubCode) |
| { |
| extra_ = 0; |
| } |
| |
| public: |
| static const uint32_t MAX_OPTIMIZED_STUBS = 8; |
| |
| static inline ICUnaryArith_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICUnaryArith_Fallback>(code); |
| } |
| |
| bool sawDoubleResult() { |
| return extra_; |
| } |
| void setSawDoubleResult() { |
| extra_ = 1; |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::UnaryArith_Fallback) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICUnaryArith_Fallback::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICUnaryArith_Int32 : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICUnaryArith_Int32(IonCode *stubCode) |
| : ICStub(UnaryArith_Int32, stubCode) |
| {} |
| |
| public: |
| static inline ICUnaryArith_Int32 *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICUnaryArith_Int32>(code); |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, JSOp op) |
| : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICUnaryArith_Int32::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICUnaryArith_Double : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICUnaryArith_Double(IonCode *stubCode) |
| : ICStub(UnaryArith_Double, stubCode) |
| {} |
| |
| public: |
| static inline ICUnaryArith_Double *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICUnaryArith_Double>(code); |
| } |
| |
| class Compiler : public ICMultiStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, JSOp op) |
| : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICUnaryArith_Double::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| // GetElem |
| // JSOP_GETELEM |
| |
| class ICGetElem_Fallback : public ICMonitoredFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| ICGetElem_Fallback(IonCode *stubCode) |
| : ICMonitoredFallbackStub(ICStub::GetElem_Fallback, stubCode) |
| { } |
| |
| static const uint16_t EXTRA_NON_NATIVE = 0x1; |
| static const uint16_t EXTRA_NEGATIVE_INDEX = 0x2; |
| |
| public: |
| static const uint32_t MAX_OPTIMIZED_STUBS = 16; |
| |
| static inline ICGetElem_Fallback *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICGetElem_Fallback>(code); |
| } |
| |
| void noteNonNativeAccess() { |
| extra_ |= EXTRA_NON_NATIVE; |
| } |
| bool hasNonNativeAccess() const { |
| return extra_ & EXTRA_NON_NATIVE; |
| } |
| |
| void noteNegativeIndex() { |
| extra_ |= EXTRA_NEGATIVE_INDEX; |
| } |
| bool hasNegativeIndex() const { |
| return extra_ & EXTRA_NEGATIVE_INDEX; |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::GetElem_Fallback) |
| { } |
| |
| ICStub *getStub(ICStubSpace *space) { |
| ICGetElem_Fallback *stub = ICGetElem_Fallback::New(space, getStubCode()); |
| if (!stub) |
| return NULL; |
| if (!stub->initMonitoringChain(cx, space)) |
| return NULL; |
| return stub; |
| } |
| }; |
| }; |
| |
| class ICGetElemNativeStub : public ICMonitoredStub |
| { |
| HeapPtrShape shape_; |
| HeapValue idval_; |
| uint32_t offset_; |
| |
| protected: |
| ICGetElemNativeStub(ICStub::Kind kind, IonCode *stubCode, ICStub *firstMonitorStub, |
| HandleShape shape, HandleValue idval, |
| bool isFixedSlot, uint32_t offset); |
| |
| ~ICGetElemNativeStub(); |
| |
| public: |
| HeapPtrShape &shape() { |
| return shape_; |
| } |
| static size_t offsetOfShape() { |
| return offsetof(ICGetElemNativeStub, shape_); |
| } |
| |
| HeapValue &idval() { |
| return idval_; |
| } |
| static size_t offsetOfIdval() { |
| return offsetof(ICGetElemNativeStub, idval_); |
| } |
| |
| uint32_t offset() const { |
| return offset_; |
| } |
| static size_t offsetOfOffset() { |
| return offsetof(ICGetElemNativeStub, offset_); |
| } |
| |
| bool isFixedSlot() const { |
| return extra_; |
| } |
| }; |
| |
| class ICGetElem_Native : public ICGetElemNativeStub |
| { |
| friend class ICStubSpace; |
| ICGetElem_Native(IonCode *stubCode, ICStub *firstMonitorStub, |
| HandleShape shape, HandleValue idval, |
| bool isFixedSlot, uint32_t offset) |
| : ICGetElemNativeStub(ICStub::GetElem_Native, stubCode, firstMonitorStub, shape, idval, |
| isFixedSlot, offset) |
| {} |
| |
| public: |
| static inline ICGetElem_Native *New(ICStubSpace *space, IonCode *code, |
| ICStub *firstMonitorStub, |
| HandleShape shape, HandleValue idval, |
| bool isFixedSlot, uint32_t offset) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICGetElem_Native>(code, firstMonitorStub, shape, idval, |
| isFixedSlot, offset); |
| } |
| }; |
| |
| class ICGetElem_NativePrototype : public ICGetElemNativeStub |
| { |
| friend class ICStubSpace; |
| HeapPtrObject holder_; |
| HeapPtrShape holderShape_; |
| |
| ICGetElem_NativePrototype(IonCode *stubCode, ICStub *firstMonitorStub, |
| HandleShape shape, HandleValue idval, |
| bool isFixedSlot, uint32_t offset, |
| HandleObject holder, HandleShape holderShape); |
| |
| public: |
| static inline ICGetElem_NativePrototype *New(ICStubSpace *space, IonCode *code, |
| ICStub *firstMonitorStub, |
| HandleShape shape, HandleValue idval, |
| bool isFixedSlot, uint32_t offset, |
| HandleObject holder, HandleShape holderShape) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICGetElem_NativePrototype>(code, firstMonitorStub, shape, idval, |
| isFixedSlot, offset, holder, holderShape); |
| } |
| |
| HeapPtrObject &holder() { |
| return holder_; |
| } |
| static size_t offsetOfHolder() { |
| return offsetof(ICGetElem_NativePrototype, holder_); |
| } |
| |
| HeapPtrShape &holderShape() { |
| return holderShape_; |
| } |
| static size_t offsetOfHolderShape() { |
| return offsetof(ICGetElem_NativePrototype, holderShape_); |
| } |
| }; |
| |
| // Compiler for GetElem_Native and GetElem_NativePrototype stubs. |
| class ICGetElemNativeCompiler : public ICStubCompiler |
| { |
| ICStub *firstMonitorStub_; |
| HandleObject obj_; |
| HandleObject holder_; |
| HandleValue idval_; |
| bool isFixedSlot_; |
| uint32_t offset_; |
| |
| bool generateStubCode(MacroAssembler &masm); |
| |
| protected: |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(kind) | (static_cast<int32_t>(isFixedSlot_) << 16); |
| } |
| |
| public: |
| ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, |
| HandleObject obj, HandleObject holder, HandleValue idval, |
| bool isFixedSlot, uint32_t offset) |
| : ICStubCompiler(cx, kind), |
| firstMonitorStub_(firstMonitorStub), |
| obj_(obj), |
| holder_(holder), |
| idval_(idval), |
| isFixedSlot_(isFixedSlot), |
| offset_(offset) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| RootedShape shape(cx, obj_->lastProperty()); |
| if (kind == ICStub::GetElem_Native) { |
| JS_ASSERT(obj_ == holder_); |
| return ICGetElem_Native::New(space, getStubCode(), firstMonitorStub_, shape, idval_, |
| isFixedSlot_, offset_); |
| } |
| |
| JS_ASSERT(obj_ != holder_); |
| JS_ASSERT(kind == ICStub::GetElem_NativePrototype); |
| RootedShape holderShape(cx, holder_->lastProperty()); |
| return ICGetElem_NativePrototype::New(space, getStubCode(), firstMonitorStub_, shape, |
| idval_, isFixedSlot_, offset_, holder_, holderShape); |
| } |
| }; |
| |
| class ICGetElem_String : public ICStub |
| { |
| friend class ICStubSpace; |
| |
| ICGetElem_String(IonCode *stubCode) |
| : ICStub(ICStub::GetElem_String, stubCode) {} |
| |
| public: |
| static inline ICGetElem_String *New(ICStubSpace *space, IonCode *code) { |
| if (!code) |
| return NULL; |
| return space->allocate<ICGetElem_String>(code); |
| } |
| |
| // Compiler for this stub kind. |
| class Compiler : public ICStubCompiler { |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx) |
| : ICStubCompiler(cx, ICStub::GetElem_String) {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICGetElem_String::New(space, getStubCode()); |
| } |
| }; |
| }; |
| |
| class ICGetElem_Dense : public ICMonitoredStub |
| { |
| friend class ICStubSpace; |
| |
| HeapPtrShape shape_; |
| |
| ICGetElem_Dense(IonCode *stubCode, ICStub *firstMonitorStub, HandleShape shape); |
| |
| public: |
| static inline ICGetElem_Dense *New(ICStubSpace *space, IonCode *code, |
| ICStub *firstMonitorStub, HandleShape shape) |
| { |
| if (!code) |
| return NULL; |
| return space->allocate<ICGetElem_Dense>(code, firstMonitorStub, shape); |
| } |
| |
| static size_t offsetOfShape() { |
| return offsetof(ICGetElem_Dense, shape_); |
| } |
| |
| HeapPtrShape &shape() { |
| return shape_; |
| } |
| |
| class Compiler : public ICStubCompiler { |
| ICStub *firstMonitorStub_; |
| RootedShape shape_; |
| |
| protected: |
| bool generateStubCode(MacroAssembler &masm); |
| |
| public: |
| Compiler(JSContext *cx, ICStub *firstMonitorStub, Shape *shape) |
| : ICStubCompiler(cx, ICStub::GetElem_Dense), |
| firstMonitorStub_(firstMonitorStub), |
| shape_(cx, shape) |
| {} |
| |
| ICStub *getStub(ICStubSpace *space) { |
| return ICGetElem_Dense::New(space, getStubCode(), firstMonitorStub_, shape_); |
| } |
| }; |
| }; |
| |
| class ICGetElem_TypedArray : public ICStub |
| { |
| friend class ICStubSpace; |
| |
|