michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_BaselineIC_h michael@0: #define jit_BaselineIC_h michael@0: michael@0: #ifdef JS_ION michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: michael@0: #include "jscntxt.h" michael@0: #include "jscompartment.h" michael@0: #include "jsgc.h" michael@0: #include "jsopcode.h" michael@0: michael@0: #include "jit/BaselineJIT.h" michael@0: #include "jit/BaselineRegisters.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: // michael@0: // Baseline Inline Caches are polymorphic caches that aggressively michael@0: // share their stub code. michael@0: // michael@0: // Every polymorphic site contains a linked list of stubs which are michael@0: // specific to that site. These stubs are composed of a |StubData| michael@0: // structure that stores parametrization information (e.g. michael@0: // the shape pointer for a shape-check-and-property-get stub), any michael@0: // dynamic information (e.g. use counts), a pointer to the stub code, michael@0: // and a pointer to the next stub state in the linked list. michael@0: // michael@0: // Every BaselineScript keeps an table of |CacheDescriptor| data michael@0: // structures, which store the following: michael@0: // A pointer to the first StubData in the cache. michael@0: // The bytecode PC of the relevant IC. michael@0: // The machine-code PC where the call to the stubcode returns. michael@0: // michael@0: // A diagram: michael@0: // michael@0: // Control flow Pointers michael@0: // =======# ----. .----> michael@0: // # | | michael@0: // #======> \-----/ michael@0: // michael@0: // michael@0: // .---------------------------------------. michael@0: // | .-------------------------. | michael@0: // | | .----. | | michael@0: // Baseline | | | | | | michael@0: // JIT Code 0 ^ 1 ^ 2 ^ | | | michael@0: // +--------------+ .-->+-----+ +-----+ +-----+ | | | michael@0: // | | #=|==>| |==>| |==>| FB | | | | michael@0: // | | # | +-----+ +-----+ +-----+ | | | michael@0: // | | # | # # # | | | michael@0: // |==============|==# | # # # | | | michael@0: // |=== IC =======| | # # # | | | michael@0: // .->|==============|<===|======#=========#=========# | | | michael@0: // | | | | | | | michael@0: // | | | | | | | michael@0: // | | | | | | | michael@0: // | | | | v | | michael@0: // | | | | +---------+ | | michael@0: // | | | | | Fallback| | | michael@0: // | | | | | Stub | | | michael@0: // | | | | | Code | | | michael@0: // | | | | +---------+ | | michael@0: // | +--------------+ | | | michael@0: // | |_______ | +---------+ | | michael@0: // | | | | Stub |<---/ | michael@0: // | IC | \--. | Code | | michael@0: // | Descriptor | | +---------+ | michael@0: // | Table v | | michael@0: // | +-----------------+ | +---------+ | michael@0: // \--| Ins | PC | Stub |----/ | Stub |<-------/ michael@0: // +-----------------+ | Code | michael@0: // | ... | +---------+ michael@0: // +-----------------+ michael@0: // Shared michael@0: // Stub Code michael@0: // michael@0: // michael@0: // Type ICs michael@0: // ======== michael@0: // michael@0: // Type ICs are otherwise regular ICs that are actually nested within michael@0: // other IC chains. They serve to optimize locations in the code where the michael@0: // baseline compiler would have otherwise had to perform a type Monitor operation michael@0: // (e.g. the result of GetProp, GetElem, etc.), or locations where the baseline michael@0: // compiler would have had to modify a heap typeset using the type of an input michael@0: // value (e.g. SetProp, SetElem, etc.) michael@0: // michael@0: // There are two kinds of Type ICs: Monitor and Update. michael@0: // michael@0: // Note that type stub bodies are no-ops. The stubs only exist for their michael@0: // guards, and their existence simply signifies that the typeset (implicit) michael@0: // that is being checked already contains that type. michael@0: // michael@0: // TypeMonitor ICs michael@0: // --------------- michael@0: // Monitor ICs are shared between stubs in the general IC, and monitor the resulting michael@0: // types of getter operations (call returns, getprop outputs, etc.) michael@0: // michael@0: // +-----------+ +-----------+ +-----------+ +-----------+ michael@0: // ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub | michael@0: // +-----------+ +-----------+ +-----------+ +-----------+ michael@0: // | | | | michael@0: // |------------------/-----------------/ | michael@0: // v | michael@0: // +-----------+ +-----------+ +-----------+ | michael@0: // | Type 1 |---->| Type 2 |---->| Type FB | | michael@0: // +-----------+ +-----------+ +-----------+ | michael@0: // | | | | michael@0: // <----------/-----------------/------------------/------------------/ michael@0: // r e t u r n p a t h michael@0: // michael@0: // After an optimized IC stub successfully executes, it passes control to the type stub michael@0: // chain to check the resulting type. If no type stub succeeds, and the monitor fallback michael@0: // stub is reached, the monitor fallback stub performs a manual monitor, and also adds the michael@0: // appropriate type stub to the chain. michael@0: // michael@0: // The IC's main fallback, in addition to generating new mainline stubs, also generates michael@0: // type stubs as reflected by its returned value. michael@0: // michael@0: // NOTE: The type IC chain returns directly to the mainline code, not back to the michael@0: // stub it was entered from. Thus, entering a type IC is a matter of a |jump|, not michael@0: // a |call|. This allows us to safely call a VM Monitor function from within the monitor IC's michael@0: // fallback chain, since the return address (needed for stack inspection) is preserved. michael@0: // michael@0: // michael@0: // TypeUpdate ICs michael@0: // -------------- michael@0: // Update ICs update heap typesets and monitor the input types of setter operations michael@0: // (setelem, setprop inputs, etc.). Unlike monitor ICs, they are not shared michael@0: // between stubs on an IC, but instead are kept track of on a per-stub basis. michael@0: // michael@0: // This is because the main stubs for the operation will each identify a potentially michael@0: // different TypeObject to update. New input types must be tracked on a typeobject-to- michael@0: // typeobject basis. michael@0: // michael@0: // Type-update ICs cannot be called in tail position (they must return to the michael@0: // the stub that called them so that the stub may continue to perform its original michael@0: // purpose). This means that any VMCall to perform a manual type update from C++ must be michael@0: // done from within the main IC stub. This necessitates that the stub enter a michael@0: // "BaselineStub" frame before making the call. michael@0: // michael@0: // If the type-update IC chain could itself make the VMCall, then the BaselineStub frame michael@0: // must be entered before calling the type-update chain, and exited afterward. This michael@0: // is very expensive for a common case where we expect the type-update fallback to not michael@0: // be called. To avoid the cost of entering and exiting a BaselineStub frame when michael@0: // using the type-update IC chain, we design the chain to not perform any VM-calls michael@0: // in its fallback. michael@0: // michael@0: // Instead, the type-update IC chain is responsible for returning 1 or 0, depending michael@0: // on if a type is represented in the chain or not. The fallback stub simply returns michael@0: // 0, and all other optimized stubs return 1. michael@0: // If the chain returns 1, then the IC stub goes ahead and performs its operation. michael@0: // If the chain returns 0, then the IC stub performs a call to the fallback function michael@0: // inline (doing the requisite BaselineStub frame enter/exit). michael@0: // This allows us to avoid the expensive subfram enter/exit in the common case. michael@0: // michael@0: // r e t u r n p a t h michael@0: // <--------------.-----------------.-----------------.-----------------. michael@0: // | | | | michael@0: // +-----------+ +-----------+ +-----------+ +-----------+ michael@0: // ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub | michael@0: // +-----------+ +-----------+ +-----------+ +-----------+ michael@0: // | ^ | ^ | ^ michael@0: // | | | | | | michael@0: // | | | | | |----------------. michael@0: // | | | | v |1 |0 michael@0: // | | | | +-----------+ +-----------+ michael@0: // | | | | | Type 3.1 |--->| FB 3 | michael@0: // | | | | +-----------+ +-----------+ michael@0: // | | | | michael@0: // | | | \-------------.-----------------. michael@0: // | | | | | | michael@0: // | | v |1 |1 |0 michael@0: // | | +-----------+ +-----------+ +-----------+ michael@0: // | | | Type 2.1 |---->| Type 2.2 |---->| FB 2 | michael@0: // | | +-----------+ +-----------+ +-----------+ michael@0: // | | michael@0: // | \-------------.-----------------. michael@0: // | | | | michael@0: // v |1 |1 |0 michael@0: // +-----------+ +-----------+ +-----------+ michael@0: // | Type 1.1 |---->| Type 1.2 |---->| FB 1 | michael@0: // +-----------+ +-----------+ +-----------+ michael@0: // michael@0: michael@0: class ICStub; michael@0: class ICFallbackStub; michael@0: michael@0: // michael@0: // An entry in the Baseline IC descriptor table. michael@0: // michael@0: class ICEntry michael@0: { michael@0: private: michael@0: // A pointer to the baseline IC stub for this instruction. michael@0: ICStub *firstStub_; michael@0: michael@0: // Offset from the start of the JIT code where the IC michael@0: // load and call instructions are. michael@0: uint32_t returnOffset_; michael@0: michael@0: // The PC of this IC's bytecode op within the JSScript. michael@0: uint32_t pcOffset_ : 29; michael@0: michael@0: public: michael@0: enum Kind { michael@0: // A for-op IC entry. michael@0: Kind_Op = 0, michael@0: michael@0: // A non-op IC entry. michael@0: Kind_NonOp, michael@0: michael@0: // A fake IC entry for returning from a callVM. michael@0: Kind_CallVM, michael@0: michael@0: // A fake IC entry for returning from DebugTrapHandler. michael@0: Kind_DebugTrap, michael@0: michael@0: // A fake IC entry for returning from a callVM to michael@0: // Debug{Prologue,Epilogue}. michael@0: Kind_DebugPrologue, michael@0: Kind_DebugEpilogue michael@0: }; michael@0: michael@0: private: michael@0: // What this IC is for. michael@0: Kind kind_ : 3; michael@0: michael@0: // Set the kind and asserts that it's sane. michael@0: void setKind(Kind kind) { michael@0: kind_ = kind; michael@0: MOZ_ASSERT(this->kind() == kind); michael@0: } michael@0: michael@0: public: michael@0: ICEntry(uint32_t pcOffset, Kind kind) michael@0: : firstStub_(nullptr), returnOffset_(), pcOffset_(pcOffset) michael@0: { michael@0: // The offset must fit in at least 29 bits, since we shave off 3 for michael@0: // the Kind enum. michael@0: MOZ_ASSERT(pcOffset_ == pcOffset); michael@0: JS_STATIC_ASSERT(BaselineScript::MAX_JSSCRIPT_LENGTH < 0x1fffffffu); michael@0: MOZ_ASSERT(pcOffset <= BaselineScript::MAX_JSSCRIPT_LENGTH); michael@0: setKind(kind); michael@0: } michael@0: michael@0: CodeOffsetLabel returnOffset() const { michael@0: return CodeOffsetLabel(returnOffset_); michael@0: } michael@0: michael@0: void setReturnOffset(CodeOffsetLabel offset) { michael@0: JS_ASSERT(offset.offset() <= (size_t) UINT32_MAX); michael@0: returnOffset_ = (uint32_t) offset.offset(); michael@0: } michael@0: michael@0: void fixupReturnOffset(MacroAssembler &masm) { michael@0: CodeOffsetLabel offset = returnOffset(); michael@0: offset.fixup(&masm); michael@0: JS_ASSERT(offset.offset() <= UINT32_MAX); michael@0: returnOffset_ = (uint32_t) offset.offset(); michael@0: } michael@0: michael@0: uint32_t pcOffset() const { michael@0: return pcOffset_; michael@0: } michael@0: michael@0: jsbytecode *pc(JSScript *script) const { michael@0: return script->offsetToPC(pcOffset_); michael@0: } michael@0: michael@0: Kind kind() const { michael@0: // MSVC compiles enums as signed. michael@0: return (Kind)(kind_ & 0x7); michael@0: } michael@0: bool isForOp() const { michael@0: return kind() == Kind_Op; michael@0: } michael@0: michael@0: void setForDebugPrologue() { michael@0: MOZ_ASSERT(kind() == Kind_CallVM); michael@0: setKind(Kind_DebugPrologue); michael@0: } michael@0: void setForDebugEpilogue() { michael@0: MOZ_ASSERT(kind() == Kind_CallVM); michael@0: setKind(Kind_DebugEpilogue); michael@0: } michael@0: michael@0: bool hasStub() const { michael@0: return firstStub_ != nullptr; michael@0: } michael@0: ICStub *firstStub() const { michael@0: JS_ASSERT(hasStub()); michael@0: return firstStub_; michael@0: } michael@0: michael@0: ICFallbackStub *fallbackStub() const; michael@0: michael@0: void setFirstStub(ICStub *stub) { michael@0: firstStub_ = stub; michael@0: } michael@0: michael@0: static inline size_t offsetOfFirstStub() { michael@0: return offsetof(ICEntry, firstStub_); michael@0: } michael@0: michael@0: inline ICStub **addressOfFirstStub() { michael@0: return &firstStub_; michael@0: } michael@0: }; michael@0: michael@0: // List of baseline IC stub kinds. michael@0: #define IC_STUB_KIND_LIST(_) \ michael@0: _(UseCount_Fallback) \ michael@0: \ michael@0: _(Profiler_Fallback) \ michael@0: _(Profiler_PushFunction) \ michael@0: \ michael@0: _(TypeMonitor_Fallback) \ michael@0: _(TypeMonitor_SingleObject) \ michael@0: _(TypeMonitor_TypeObject) \ michael@0: _(TypeMonitor_PrimitiveSet) \ michael@0: \ michael@0: _(TypeUpdate_Fallback) \ michael@0: _(TypeUpdate_SingleObject) \ michael@0: _(TypeUpdate_TypeObject) \ michael@0: _(TypeUpdate_PrimitiveSet) \ michael@0: \ michael@0: _(This_Fallback) \ michael@0: \ michael@0: _(NewArray_Fallback) \ michael@0: _(NewObject_Fallback) \ michael@0: \ michael@0: _(Compare_Fallback) \ michael@0: _(Compare_Int32) \ michael@0: _(Compare_Double) \ michael@0: _(Compare_NumberWithUndefined) \ michael@0: _(Compare_String) \ michael@0: _(Compare_Boolean) \ michael@0: _(Compare_Object) \ michael@0: _(Compare_ObjectWithUndefined) \ michael@0: _(Compare_Int32WithBoolean) \ michael@0: \ michael@0: _(ToBool_Fallback) \ michael@0: _(ToBool_Int32) \ michael@0: _(ToBool_String) \ michael@0: _(ToBool_NullUndefined) \ michael@0: _(ToBool_Double) \ michael@0: _(ToBool_Object) \ michael@0: \ michael@0: _(ToNumber_Fallback) \ michael@0: \ michael@0: _(BinaryArith_Fallback) \ michael@0: _(BinaryArith_Int32) \ michael@0: _(BinaryArith_Double) \ michael@0: _(BinaryArith_StringConcat) \ michael@0: _(BinaryArith_StringObjectConcat) \ michael@0: _(BinaryArith_BooleanWithInt32) \ michael@0: _(BinaryArith_DoubleWithInt32) \ michael@0: \ michael@0: _(UnaryArith_Fallback) \ michael@0: _(UnaryArith_Int32) \ michael@0: _(UnaryArith_Double) \ michael@0: \ michael@0: _(Call_Fallback) \ michael@0: _(Call_Scripted) \ michael@0: _(Call_AnyScripted) \ michael@0: _(Call_Native) \ michael@0: _(Call_ScriptedApplyArray) \ michael@0: _(Call_ScriptedApplyArguments) \ michael@0: _(Call_ScriptedFunCall) \ michael@0: \ michael@0: _(GetElem_Fallback) \ michael@0: _(GetElem_NativeSlot) \ michael@0: _(GetElem_NativePrototypeSlot) \ michael@0: _(GetElem_NativePrototypeCallNative) \ michael@0: _(GetElem_NativePrototypeCallScripted) \ michael@0: _(GetElem_String) \ michael@0: _(GetElem_Dense) \ michael@0: _(GetElem_TypedArray) \ michael@0: _(GetElem_Arguments) \ michael@0: \ michael@0: _(SetElem_Fallback) \ michael@0: _(SetElem_Dense) \ michael@0: _(SetElem_DenseAdd) \ michael@0: _(SetElem_TypedArray) \ michael@0: \ michael@0: _(In_Fallback) \ michael@0: \ michael@0: _(GetName_Fallback) \ michael@0: _(GetName_Global) \ michael@0: _(GetName_Scope0) \ michael@0: _(GetName_Scope1) \ michael@0: _(GetName_Scope2) \ michael@0: _(GetName_Scope3) \ michael@0: _(GetName_Scope4) \ michael@0: _(GetName_Scope5) \ michael@0: _(GetName_Scope6) \ michael@0: \ michael@0: _(BindName_Fallback) \ michael@0: \ michael@0: _(GetIntrinsic_Fallback) \ michael@0: _(GetIntrinsic_Constant) \ michael@0: \ michael@0: _(GetProp_Fallback) \ michael@0: _(GetProp_ArrayLength) \ michael@0: _(GetProp_TypedArrayLength) \ michael@0: _(GetProp_Primitive) \ michael@0: _(GetProp_StringLength) \ michael@0: _(GetProp_Native) \ michael@0: _(GetProp_NativePrototype) \ michael@0: _(GetProp_CallScripted) \ michael@0: _(GetProp_CallNative) \ michael@0: _(GetProp_CallNativePrototype)\ michael@0: _(GetProp_CallDOMProxyNative)\ michael@0: _(GetProp_CallDOMProxyWithGenerationNative)\ michael@0: _(GetProp_DOMProxyShadowed) \ michael@0: _(GetProp_ArgumentsLength) \ michael@0: \ michael@0: _(SetProp_Fallback) \ michael@0: _(SetProp_Native) \ michael@0: _(SetProp_NativeAdd) \ michael@0: _(SetProp_CallScripted) \ michael@0: _(SetProp_CallNative) \ michael@0: \ michael@0: _(TableSwitch) \ michael@0: \ michael@0: _(IteratorNew_Fallback) \ michael@0: _(IteratorMore_Fallback) \ michael@0: _(IteratorMore_Native) \ michael@0: _(IteratorNext_Fallback) \ michael@0: _(IteratorNext_Native) \ michael@0: _(IteratorClose_Fallback) \ michael@0: \ michael@0: _(InstanceOf_Fallback) \ michael@0: \ michael@0: _(TypeOf_Fallback) \ michael@0: _(TypeOf_Typed) \ michael@0: \ michael@0: _(Rest_Fallback) \ michael@0: \ michael@0: _(RetSub_Fallback) \ michael@0: _(RetSub_Resume) michael@0: michael@0: #define FORWARD_DECLARE_STUBS(kindName) class IC##kindName; michael@0: IC_STUB_KIND_LIST(FORWARD_DECLARE_STUBS) michael@0: #undef FORWARD_DECLARE_STUBS michael@0: michael@0: class ICMonitoredStub; michael@0: class ICMonitoredFallbackStub; michael@0: class ICUpdatedStub; michael@0: michael@0: // Constant iterator that traverses arbitrary chains of ICStubs. michael@0: // No requirements are made of the ICStub used to construct this michael@0: // iterator, aside from that the stub be part of a nullptr-terminated michael@0: // chain. michael@0: // The iterator is considered to be at its end once it has been michael@0: // incremented _past_ the last stub. Thus, if 'atEnd()' returns michael@0: // true, the '*' and '->' operations are not valid. michael@0: class ICStubConstIterator michael@0: { michael@0: friend class ICStub; michael@0: friend class ICFallbackStub; michael@0: michael@0: private: michael@0: ICStub *currentStub_; michael@0: michael@0: public: michael@0: ICStubConstIterator(ICStub *currentStub) : currentStub_(currentStub) {} michael@0: michael@0: static ICStubConstIterator StartingAt(ICStub *stub) { michael@0: return ICStubConstIterator(stub); michael@0: } michael@0: static ICStubConstIterator End(ICStub *stub) { michael@0: return ICStubConstIterator(nullptr); michael@0: } michael@0: michael@0: bool operator ==(const ICStubConstIterator &other) const { michael@0: return currentStub_ == other.currentStub_; michael@0: } michael@0: bool operator !=(const ICStubConstIterator &other) const { michael@0: return !(*this == other); michael@0: } michael@0: michael@0: ICStubConstIterator &operator++(); michael@0: michael@0: ICStubConstIterator operator++(int) { michael@0: ICStubConstIterator oldThis(*this); michael@0: ++(*this); michael@0: return oldThis; michael@0: } michael@0: michael@0: ICStub *operator *() const { michael@0: JS_ASSERT(currentStub_); michael@0: return currentStub_; michael@0: } michael@0: michael@0: ICStub *operator ->() const { michael@0: JS_ASSERT(currentStub_); michael@0: return currentStub_; michael@0: } michael@0: michael@0: bool atEnd() const { michael@0: return currentStub_ == nullptr; michael@0: } michael@0: }; michael@0: michael@0: // Iterator that traverses "regular" IC chains that start at an ICEntry michael@0: // and are terminated with an ICFallbackStub. michael@0: // michael@0: // The iterator is considered to be at its end once it is _at_ the michael@0: // fallback stub. Thus, unlike the ICStubConstIterator, operators michael@0: // '*' and '->' are valid even if 'atEnd()' returns true - they michael@0: // will act on the fallback stub. michael@0: // michael@0: // This iterator also allows unlinking of stubs being traversed. michael@0: // Note that 'unlink' does not implicitly advance the iterator - michael@0: // it must be advanced explicitly using '++'. michael@0: class ICStubIterator michael@0: { michael@0: friend class ICFallbackStub; michael@0: michael@0: private: michael@0: ICEntry *icEntry_; michael@0: ICFallbackStub *fallbackStub_; michael@0: ICStub *previousStub_; michael@0: ICStub *currentStub_; michael@0: bool unlinked_; michael@0: michael@0: ICStubIterator(ICFallbackStub *fallbackStub, bool end=false); michael@0: public: michael@0: michael@0: bool operator ==(const ICStubIterator &other) const { michael@0: // == should only ever be called on stubs from the same chain. michael@0: JS_ASSERT(icEntry_ == other.icEntry_); michael@0: JS_ASSERT(fallbackStub_ == other.fallbackStub_); michael@0: return currentStub_ == other.currentStub_; michael@0: } michael@0: bool operator !=(const ICStubIterator &other) const { michael@0: return !(*this == other); michael@0: } michael@0: michael@0: ICStubIterator &operator++(); michael@0: michael@0: ICStubIterator operator++(int) { michael@0: ICStubIterator oldThis(*this); michael@0: ++(*this); michael@0: return oldThis; michael@0: } michael@0: michael@0: ICStub *operator *() const { michael@0: return currentStub_; michael@0: } michael@0: michael@0: ICStub *operator ->() const { michael@0: return currentStub_; michael@0: } michael@0: michael@0: bool atEnd() const { michael@0: return currentStub_ == (ICStub *) fallbackStub_; michael@0: } michael@0: michael@0: void unlink(JSContext *cx); michael@0: }; michael@0: michael@0: // michael@0: // Base class for all IC stubs. michael@0: // michael@0: class ICStub michael@0: { michael@0: friend class ICFallbackStub; michael@0: michael@0: public: michael@0: enum Kind { michael@0: INVALID = 0, michael@0: #define DEF_ENUM_KIND(kindName) kindName, michael@0: IC_STUB_KIND_LIST(DEF_ENUM_KIND) michael@0: #undef DEF_ENUM_KIND michael@0: LIMIT michael@0: }; michael@0: michael@0: static inline bool IsValidKind(Kind k) { michael@0: return (k > INVALID) && (k < LIMIT); michael@0: } michael@0: michael@0: static const char *KindString(Kind k) { michael@0: switch(k) { michael@0: #define DEF_KIND_STR(kindName) case kindName: return #kindName; michael@0: IC_STUB_KIND_LIST(DEF_KIND_STR) michael@0: #undef DEF_KIND_STR michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Invalid kind."); michael@0: } michael@0: } michael@0: michael@0: enum Trait { michael@0: Regular = 0x0, michael@0: Fallback = 0x1, michael@0: Monitored = 0x2, michael@0: MonitoredFallback = 0x3, michael@0: Updated = 0x4 michael@0: }; michael@0: michael@0: void markCode(JSTracer *trc, const char *name); michael@0: void updateCode(JitCode *stubCode); michael@0: void trace(JSTracer *trc); michael@0: michael@0: protected: michael@0: // The raw jitcode to call for this stub. michael@0: uint8_t *stubCode_; michael@0: michael@0: // Pointer to next IC stub. This is null for the last IC stub, which should michael@0: // either be a fallback or inert IC stub. michael@0: ICStub *next_; michael@0: michael@0: // A 16-bit field usable by subtypes of ICStub for subtype-specific small-info michael@0: uint16_t extra_; michael@0: michael@0: // The kind of the stub. michael@0: // High bit is 'isFallback' flag. michael@0: // Second high bit is 'isMonitored' flag. michael@0: Trait trait_ : 3; michael@0: Kind kind_ : 13; michael@0: michael@0: inline ICStub(Kind kind, JitCode *stubCode) michael@0: : stubCode_(stubCode->raw()), michael@0: next_(nullptr), michael@0: extra_(0), michael@0: trait_(Regular), michael@0: kind_(kind) michael@0: { michael@0: JS_ASSERT(stubCode != nullptr); michael@0: } michael@0: michael@0: inline ICStub(Kind kind, Trait trait, JitCode *stubCode) michael@0: : stubCode_(stubCode->raw()), michael@0: next_(nullptr), michael@0: extra_(0), michael@0: trait_(trait), michael@0: kind_(kind) michael@0: { michael@0: JS_ASSERT(stubCode != nullptr); michael@0: } michael@0: michael@0: inline Trait trait() const { michael@0: // Workaround for MSVC reading trait_ as signed value. michael@0: return (Trait)(trait_ & 0x7); michael@0: } michael@0: michael@0: public: michael@0: michael@0: inline Kind kind() const { michael@0: return static_cast(kind_); michael@0: } michael@0: michael@0: inline bool isFallback() const { michael@0: return trait() == Fallback || trait() == MonitoredFallback; michael@0: } michael@0: michael@0: inline bool isMonitored() const { michael@0: return trait() == Monitored; michael@0: } michael@0: michael@0: inline bool isUpdated() const { michael@0: return trait() == Updated; michael@0: } michael@0: michael@0: inline bool isMonitoredFallback() const { michael@0: return trait() == MonitoredFallback; michael@0: } michael@0: michael@0: inline const ICFallbackStub *toFallbackStub() const { michael@0: JS_ASSERT(isFallback()); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: inline ICFallbackStub *toFallbackStub() { michael@0: JS_ASSERT(isFallback()); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: inline const ICMonitoredStub *toMonitoredStub() const { michael@0: JS_ASSERT(isMonitored()); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: inline ICMonitoredStub *toMonitoredStub() { michael@0: JS_ASSERT(isMonitored()); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: inline const ICMonitoredFallbackStub *toMonitoredFallbackStub() const { michael@0: JS_ASSERT(isMonitoredFallback()); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: inline ICMonitoredFallbackStub *toMonitoredFallbackStub() { michael@0: JS_ASSERT(isMonitoredFallback()); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: inline const ICUpdatedStub *toUpdatedStub() const { michael@0: JS_ASSERT(isUpdated()); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: inline ICUpdatedStub *toUpdatedStub() { michael@0: JS_ASSERT(isUpdated()); michael@0: return reinterpret_cast(this); michael@0: } michael@0: michael@0: #define KIND_METHODS(kindName) \ michael@0: inline bool is##kindName() const { return kind() == kindName; } \ michael@0: inline const IC##kindName *to##kindName() const { \ michael@0: JS_ASSERT(is##kindName()); \ michael@0: return reinterpret_cast(this); \ michael@0: } \ michael@0: inline IC##kindName *to##kindName() { \ michael@0: JS_ASSERT(is##kindName()); \ michael@0: return reinterpret_cast(this); \ michael@0: } michael@0: IC_STUB_KIND_LIST(KIND_METHODS) michael@0: #undef KIND_METHODS michael@0: michael@0: inline ICStub *next() const { michael@0: return next_; michael@0: } michael@0: michael@0: inline bool hasNext() const { michael@0: return next_ != nullptr; michael@0: } michael@0: michael@0: inline void setNext(ICStub *stub) { michael@0: // Note: next_ only needs to be changed under the compilation lock for michael@0: // non-type-monitor/update ICs. michael@0: next_ = stub; michael@0: } michael@0: michael@0: inline ICStub **addressOfNext() { michael@0: return &next_; michael@0: } michael@0: michael@0: inline JitCode *jitCode() { michael@0: return JitCode::FromExecutable(stubCode_); michael@0: } michael@0: michael@0: inline uint8_t *rawStubCode() const { michael@0: return stubCode_; michael@0: } michael@0: michael@0: // This method is not valid on TypeUpdate stub chains! michael@0: inline ICFallbackStub *getChainFallback() { michael@0: ICStub *lastStub = this; michael@0: while (lastStub->next_) michael@0: lastStub = lastStub->next_; michael@0: JS_ASSERT(lastStub->isFallback()); michael@0: return lastStub->toFallbackStub(); michael@0: } michael@0: michael@0: inline ICStubConstIterator beginHere() { michael@0: return ICStubConstIterator::StartingAt(this); michael@0: } michael@0: michael@0: static inline size_t offsetOfNext() { michael@0: return offsetof(ICStub, next_); michael@0: } michael@0: michael@0: static inline size_t offsetOfStubCode() { michael@0: return offsetof(ICStub, stubCode_); michael@0: } michael@0: michael@0: static inline size_t offsetOfExtra() { michael@0: return offsetof(ICStub, extra_); michael@0: } michael@0: michael@0: static bool CanMakeCalls(ICStub::Kind kind) { michael@0: JS_ASSERT(IsValidKind(kind)); michael@0: switch (kind) { michael@0: case Call_Fallback: michael@0: case Call_Scripted: michael@0: case Call_AnyScripted: michael@0: case Call_Native: michael@0: case Call_ScriptedApplyArray: michael@0: case Call_ScriptedApplyArguments: michael@0: case Call_ScriptedFunCall: michael@0: case UseCount_Fallback: michael@0: case GetElem_NativeSlot: michael@0: case GetElem_NativePrototypeSlot: michael@0: case GetElem_NativePrototypeCallNative: michael@0: case GetElem_NativePrototypeCallScripted: michael@0: case GetProp_CallScripted: michael@0: case GetProp_CallNative: michael@0: case GetProp_CallNativePrototype: michael@0: case GetProp_CallDOMProxyNative: michael@0: case GetProp_CallDOMProxyWithGenerationNative: michael@0: case GetProp_DOMProxyShadowed: michael@0: case SetProp_CallScripted: michael@0: case SetProp_CallNative: michael@0: case RetSub_Fallback: michael@0: // These two fallback stubs don't actually make non-tail calls, michael@0: // but the fallback code for the bailout path needs to pop the stub frame michael@0: // pushed during the bailout. michael@0: case GetProp_Fallback: michael@0: case SetProp_Fallback: michael@0: #if JS_HAS_NO_SUCH_METHOD michael@0: case GetElem_Dense: michael@0: case GetElem_Arguments: michael@0: case GetProp_NativePrototype: michael@0: case GetProp_Native: michael@0: #endif michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // Optimized stubs get purged on GC. But some stubs can be active on the michael@0: // stack during GC - specifically the ones that can make calls. To ensure michael@0: // that these do not get purged, all stubs that can make calls are allocated michael@0: // in the fallback stub space. michael@0: bool allocatedInFallbackSpace() const { michael@0: JS_ASSERT(next()); michael@0: return CanMakeCalls(kind()); michael@0: } michael@0: }; michael@0: michael@0: class ICFallbackStub : public ICStub michael@0: { michael@0: friend class ICStubConstIterator; michael@0: protected: michael@0: // Fallback stubs need these fields to easily add new stubs to michael@0: // the linked list of stubs for an IC. michael@0: michael@0: // The IC entry for this linked list of stubs. michael@0: ICEntry *icEntry_; michael@0: michael@0: // The number of stubs kept in the IC entry. michael@0: uint32_t numOptimizedStubs_; michael@0: michael@0: // A pointer to the location stub pointer that needs to be michael@0: // changed to add a new "last" stub immediately before the fallback michael@0: // stub. This'll start out pointing to the icEntry's "firstStub_" michael@0: // field, and as new stubs are addd, it'll point to the current michael@0: // last stub's "next_" field. michael@0: ICStub **lastStubPtrAddr_; michael@0: michael@0: ICFallbackStub(Kind kind, JitCode *stubCode) michael@0: : ICStub(kind, ICStub::Fallback, stubCode), michael@0: icEntry_(nullptr), michael@0: numOptimizedStubs_(0), michael@0: lastStubPtrAddr_(nullptr) {} michael@0: michael@0: ICFallbackStub(Kind kind, Trait trait, JitCode *stubCode) michael@0: : ICStub(kind, trait, stubCode), michael@0: icEntry_(nullptr), michael@0: numOptimizedStubs_(0), michael@0: lastStubPtrAddr_(nullptr) michael@0: { michael@0: JS_ASSERT(trait == ICStub::Fallback || michael@0: trait == ICStub::MonitoredFallback); michael@0: } michael@0: michael@0: public: michael@0: inline ICEntry *icEntry() const { michael@0: return icEntry_; michael@0: } michael@0: michael@0: inline size_t numOptimizedStubs() const { michael@0: return (size_t) numOptimizedStubs_; michael@0: } michael@0: michael@0: // The icEntry and lastStubPtrAddr_ fields can't be initialized when the stub is michael@0: // created since the stub is created at compile time, and we won't know the IC entry michael@0: // address until after compile when the BaselineScript is created. This method michael@0: // allows these fields to be fixed up at that point. michael@0: void fixupICEntry(ICEntry *icEntry) { michael@0: JS_ASSERT(icEntry_ == nullptr); michael@0: JS_ASSERT(lastStubPtrAddr_ == nullptr); michael@0: icEntry_ = icEntry; michael@0: lastStubPtrAddr_ = icEntry_->addressOfFirstStub(); michael@0: } michael@0: michael@0: // Add a new stub to the IC chain terminated by this fallback stub. michael@0: void addNewStub(ICStub *stub) { michael@0: JS_ASSERT(*lastStubPtrAddr_ == this); michael@0: JS_ASSERT(stub->next() == nullptr); michael@0: stub->setNext(this); michael@0: *lastStubPtrAddr_ = stub; michael@0: lastStubPtrAddr_ = stub->addressOfNext(); michael@0: numOptimizedStubs_++; michael@0: } michael@0: michael@0: ICStubConstIterator beginChainConst() const { michael@0: return ICStubConstIterator(icEntry_->firstStub()); michael@0: } michael@0: michael@0: ICStubIterator beginChain() { michael@0: return ICStubIterator(this); michael@0: } michael@0: michael@0: bool hasStub(ICStub::Kind kind) const { michael@0: for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) { michael@0: if (iter->kind() == kind) michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: unsigned numStubsWithKind(ICStub::Kind kind) const { michael@0: unsigned count = 0; michael@0: for (ICStubConstIterator iter = beginChainConst(); !iter.atEnd(); iter++) { michael@0: if (iter->kind() == kind) michael@0: count++; michael@0: } michael@0: return count; michael@0: } michael@0: michael@0: void unlinkStub(Zone *zone, ICStub *prev, ICStub *stub); michael@0: void unlinkStubsWithKind(JSContext *cx, ICStub::Kind kind); michael@0: }; michael@0: michael@0: // Monitored stubs are IC stubs that feed a single resulting value out to a michael@0: // type monitor operation. michael@0: class ICMonitoredStub : public ICStub michael@0: { michael@0: protected: michael@0: // Pointer to the start of the type monitoring stub chain. michael@0: ICStub *firstMonitorStub_; michael@0: michael@0: ICMonitoredStub(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub); michael@0: michael@0: public: michael@0: inline void updateFirstMonitorStub(ICStub *monitorStub) { michael@0: // This should only be called once: when the first optimized monitor stub michael@0: // is added to the type monitor IC chain. michael@0: JS_ASSERT(firstMonitorStub_ && firstMonitorStub_->isTypeMonitor_Fallback()); michael@0: firstMonitorStub_ = monitorStub; michael@0: } michael@0: inline void resetFirstMonitorStub(ICStub *monitorFallback) { michael@0: JS_ASSERT(monitorFallback->isTypeMonitor_Fallback()); michael@0: firstMonitorStub_ = monitorFallback; michael@0: } michael@0: inline ICStub *firstMonitorStub() const { michael@0: return firstMonitorStub_; michael@0: } michael@0: michael@0: static inline size_t offsetOfFirstMonitorStub() { michael@0: return offsetof(ICMonitoredStub, firstMonitorStub_); michael@0: } michael@0: }; michael@0: michael@0: // Monitored fallback stubs - as the name implies. michael@0: class ICMonitoredFallbackStub : public ICFallbackStub michael@0: { michael@0: protected: michael@0: // Pointer to the fallback monitor stub. michael@0: ICTypeMonitor_Fallback *fallbackMonitorStub_; michael@0: michael@0: ICMonitoredFallbackStub(Kind kind, JitCode *stubCode) michael@0: : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode), michael@0: fallbackMonitorStub_(nullptr) {} michael@0: michael@0: public: michael@0: bool initMonitoringChain(JSContext *cx, ICStubSpace *space); michael@0: bool addMonitorStubForValue(JSContext *cx, JSScript *script, HandleValue val); michael@0: michael@0: inline ICTypeMonitor_Fallback *fallbackMonitorStub() const { michael@0: return fallbackMonitorStub_; michael@0: } michael@0: michael@0: static inline size_t offsetOfFallbackMonitorStub() { michael@0: return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_); michael@0: } michael@0: }; michael@0: michael@0: // Updated stubs are IC stubs that use a TypeUpdate IC to track michael@0: // the status of heap typesets that need to be updated. michael@0: class ICUpdatedStub : public ICStub michael@0: { michael@0: protected: michael@0: // Pointer to the start of the type updating stub chain. michael@0: ICStub *firstUpdateStub_; michael@0: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: uint32_t numOptimizedStubs_; michael@0: michael@0: ICUpdatedStub(Kind kind, JitCode *stubCode) michael@0: : ICStub(kind, ICStub::Updated, stubCode), michael@0: firstUpdateStub_(nullptr), michael@0: numOptimizedStubs_(0) michael@0: {} michael@0: michael@0: public: michael@0: bool initUpdatingChain(JSContext *cx, ICStubSpace *space); michael@0: michael@0: bool addUpdateStubForValue(JSContext *cx, HandleScript script, HandleObject obj, HandleId id, michael@0: HandleValue val); michael@0: michael@0: void addOptimizedUpdateStub(ICStub *stub) { michael@0: if (firstUpdateStub_->isTypeUpdate_Fallback()) { michael@0: stub->setNext(firstUpdateStub_); michael@0: firstUpdateStub_ = stub; michael@0: } else { michael@0: ICStub *iter = firstUpdateStub_; michael@0: JS_ASSERT(iter->next() != nullptr); michael@0: while (!iter->next()->isTypeUpdate_Fallback()) michael@0: iter = iter->next(); michael@0: JS_ASSERT(iter->next()->next() == nullptr); michael@0: stub->setNext(iter->next()); michael@0: iter->setNext(stub); michael@0: } michael@0: michael@0: numOptimizedStubs_++; michael@0: } michael@0: michael@0: inline ICStub *firstUpdateStub() const { michael@0: return firstUpdateStub_; michael@0: } michael@0: michael@0: bool hasTypeUpdateStub(ICStub::Kind kind) { michael@0: ICStub *stub = firstUpdateStub_; michael@0: do { michael@0: if (stub->kind() == kind) michael@0: return true; michael@0: michael@0: stub = stub->next(); michael@0: } while (stub); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: inline uint32_t numOptimizedStubs() const { michael@0: return numOptimizedStubs_; michael@0: } michael@0: michael@0: static inline size_t offsetOfFirstUpdateStub() { michael@0: return offsetof(ICUpdatedStub, firstUpdateStub_); michael@0: } michael@0: }; michael@0: michael@0: // Base class for stubcode compilers. michael@0: class ICStubCompiler michael@0: { michael@0: // Prevent GC in the middle of stub compilation. michael@0: js::gc::AutoSuppressGC suppressGC; michael@0: michael@0: michael@0: protected: michael@0: JSContext *cx; michael@0: ICStub::Kind kind; michael@0: #ifdef DEBUG michael@0: bool entersStubFrame_; michael@0: #endif michael@0: michael@0: // By default the stubcode key is just the kind. michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind); michael@0: } michael@0: michael@0: virtual bool generateStubCode(MacroAssembler &masm) = 0; michael@0: virtual bool postGenerateStubCode(MacroAssembler &masm, Handle genCode) { michael@0: return true; michael@0: } michael@0: JitCode *getStubCode(); michael@0: michael@0: ICStubCompiler(JSContext *cx, ICStub::Kind kind) michael@0: : suppressGC(cx), cx(cx), kind(kind) michael@0: #ifdef DEBUG michael@0: , entersStubFrame_(false) michael@0: #endif michael@0: {} michael@0: michael@0: // Emits a tail call to a VMFunction wrapper. michael@0: bool tailCallVM(const VMFunction &fun, MacroAssembler &masm); michael@0: michael@0: // Emits a normal (non-tail) call to a VMFunction wrapper. michael@0: bool callVM(const VMFunction &fun, MacroAssembler &masm); michael@0: michael@0: // Emits a call to a type-update IC, assuming that the value to be michael@0: // checked is already in R0. michael@0: bool callTypeUpdateIC(MacroAssembler &masm, uint32_t objectOffset); michael@0: michael@0: // A stub frame is used when a stub wants to call into the VM without michael@0: // performing a tail call. This is required for the return address michael@0: // to pc mapping to work. michael@0: void enterStubFrame(MacroAssembler &masm, Register scratch); michael@0: void leaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false); michael@0: void leaveStubFrameHead(MacroAssembler &masm, bool calledIntoIon = false); michael@0: void leaveStubFrameCommonTail(MacroAssembler &masm); michael@0: michael@0: // Some stubs need to emit SPS profiler updates. This emits the guarding michael@0: // jitcode for those stubs. If profiling is not enabled, jumps to the michael@0: // given label. michael@0: void guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip); michael@0: michael@0: // Higher-level helper to emit an update to the profiler pseudo-stack. michael@0: void emitProfilingUpdate(MacroAssembler &masm, Register pcIdx, Register scratch, michael@0: uint32_t stubPcOffset); michael@0: void emitProfilingUpdate(MacroAssembler &masm, GeneralRegisterSet regs, uint32_t stubPcOffset); michael@0: michael@0: inline GeneralRegisterSet availableGeneralRegs(size_t numInputs) const { michael@0: GeneralRegisterSet regs(GeneralRegisterSet::All()); michael@0: JS_ASSERT(!regs.has(BaselineStackReg)); michael@0: #if defined(JS_CODEGEN_ARM) michael@0: JS_ASSERT(!regs.has(BaselineTailCallReg)); michael@0: regs.take(BaselineSecondScratchReg); michael@0: #elif defined(JS_CODEGEN_MIPS) michael@0: JS_ASSERT(!regs.has(BaselineTailCallReg)); michael@0: JS_ASSERT(!regs.has(BaselineSecondScratchReg)); michael@0: #endif michael@0: regs.take(BaselineFrameReg); michael@0: regs.take(BaselineStubReg); michael@0: #ifdef JS_CODEGEN_X64 michael@0: regs.take(ExtractTemp0); michael@0: regs.take(ExtractTemp1); michael@0: #endif michael@0: michael@0: switch (numInputs) { michael@0: case 0: michael@0: break; michael@0: case 1: michael@0: regs.take(R0); michael@0: break; michael@0: case 2: michael@0: regs.take(R0); michael@0: regs.take(R1); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Invalid numInputs"); michael@0: } michael@0: michael@0: return regs; michael@0: } michael@0: michael@0: #ifdef JSGC_GENERATIONAL michael@0: inline bool emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val, michael@0: Register scratch, GeneralRegisterSet saveRegs); michael@0: #endif michael@0: michael@0: public: michael@0: virtual ICStub *getStub(ICStubSpace *space) = 0; michael@0: michael@0: ICStubSpace *getStubSpace(JSScript *script) { michael@0: if (ICStub::CanMakeCalls(kind)) michael@0: return script->baselineScript()->fallbackStubSpace(); michael@0: return script->zone()->jitZone()->optimizedStubSpace(); michael@0: } michael@0: }; michael@0: michael@0: // Base class for stub compilers that can generate multiple stubcodes. michael@0: // These compilers need access to the JSOp they are compiling for. michael@0: class ICMultiStubCompiler : public ICStubCompiler michael@0: { michael@0: protected: michael@0: JSOp op; michael@0: michael@0: // Stub keys for multi-stub kinds are composed of both the kind michael@0: // and the op they are compiled for. michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(op) << 16); michael@0: } michael@0: michael@0: ICMultiStubCompiler(JSContext *cx, ICStub::Kind kind, JSOp op) michael@0: : ICStubCompiler(cx, kind), op(op) {} michael@0: }; michael@0: michael@0: // UseCount_Fallback michael@0: michael@0: // A UseCount IC chain has only the fallback stub. michael@0: class ICUseCount_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICUseCount_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::UseCount_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICUseCount_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::UseCount_Fallback) michael@0: { } michael@0: michael@0: ICUseCount_Fallback *getStub(ICStubSpace *space) { michael@0: return ICUseCount_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Profiler_Fallback michael@0: michael@0: class ICProfiler_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICProfiler_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::Profiler_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICProfiler_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::Profiler_Fallback) michael@0: { } michael@0: michael@0: ICProfiler_Fallback *getStub(ICStubSpace *space) { michael@0: return ICProfiler_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Profiler_PushFunction michael@0: michael@0: class ICProfiler_PushFunction : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: const char *str_; michael@0: HeapPtrScript script_; michael@0: michael@0: ICProfiler_PushFunction(JitCode *stubCode, const char *str, HandleScript script); michael@0: michael@0: public: michael@0: static inline ICProfiler_PushFunction *New(ICStubSpace *space, JitCode *code, michael@0: const char *str, HandleScript script) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, str, script); michael@0: } michael@0: michael@0: HeapPtrScript &script() { michael@0: return script_; michael@0: } michael@0: michael@0: static size_t offsetOfStr() { michael@0: return offsetof(ICProfiler_PushFunction, str_); michael@0: } michael@0: static size_t offsetOfScript() { michael@0: return offsetof(ICProfiler_PushFunction, script_); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: const char *str_; michael@0: RootedScript script_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, const char *str, HandleScript script) michael@0: : ICStubCompiler(cx, ICStub::Profiler_PushFunction), michael@0: str_(str), michael@0: script_(cx, script) michael@0: { } michael@0: michael@0: ICProfiler_PushFunction *getStub(ICStubSpace *space) { michael@0: return ICProfiler_PushFunction::New(space, getStubCode(), str_, script_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: michael@0: // TypeCheckPrimitiveSetStub michael@0: // Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given michael@0: // value's type falls within a set of primitive types. michael@0: michael@0: class TypeCheckPrimitiveSetStub : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: protected: michael@0: inline static uint16_t TypeToFlag(JSValueType type) { michael@0: return 1u << static_cast(type); michael@0: } michael@0: michael@0: inline static uint16_t ValidFlags() { michael@0: return ((TypeToFlag(JSVAL_TYPE_OBJECT) << 1) - 1) & ~TypeToFlag(JSVAL_TYPE_MAGIC); michael@0: } michael@0: michael@0: TypeCheckPrimitiveSetStub(Kind kind, JitCode *stubCode, uint16_t flags) michael@0: : ICStub(kind, stubCode) michael@0: { michael@0: JS_ASSERT(kind == TypeMonitor_PrimitiveSet || kind == TypeUpdate_PrimitiveSet); michael@0: JS_ASSERT(flags && !(flags & ~ValidFlags())); michael@0: extra_ = flags; michael@0: } michael@0: michael@0: TypeCheckPrimitiveSetStub *updateTypesAndCode(uint16_t flags, JitCode *code) { michael@0: JS_ASSERT(flags && !(flags & ~ValidFlags())); michael@0: if (!code) michael@0: return nullptr; michael@0: extra_ = flags; michael@0: updateCode(code); michael@0: return this; michael@0: } michael@0: michael@0: public: michael@0: uint16_t typeFlags() const { michael@0: return extra_; michael@0: } michael@0: michael@0: bool containsType(JSValueType type) const { michael@0: JS_ASSERT(type <= JSVAL_TYPE_OBJECT); michael@0: JS_ASSERT(type != JSVAL_TYPE_MAGIC); michael@0: return extra_ & TypeToFlag(type); michael@0: } michael@0: michael@0: ICTypeMonitor_PrimitiveSet *toMonitorStub() { michael@0: return toTypeMonitor_PrimitiveSet(); michael@0: } michael@0: michael@0: ICTypeUpdate_PrimitiveSet *toUpdateStub() { michael@0: return toTypeUpdate_PrimitiveSet(); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: TypeCheckPrimitiveSetStub *existingStub_; michael@0: uint16_t flags_; michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(flags_) << 16); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, Kind kind, TypeCheckPrimitiveSetStub *existingStub, michael@0: JSValueType type) michael@0: : ICStubCompiler(cx, kind), michael@0: existingStub_(existingStub), michael@0: flags_((existingStub ? existingStub->typeFlags() : 0) | TypeToFlag(type)) michael@0: { michael@0: JS_ASSERT_IF(existingStub_, flags_ != existingStub_->typeFlags()); michael@0: } michael@0: michael@0: TypeCheckPrimitiveSetStub *updateStub() { michael@0: JS_ASSERT(existingStub_); michael@0: return existingStub_->updateTypesAndCode(flags_, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // TypeMonitor michael@0: michael@0: // The TypeMonitor fallback stub is not always a regular fallback stub. When michael@0: // used for monitoring the values pushed by a bytecode it doesn't hold a michael@0: // pointer to the IC entry, but rather back to the main fallback stub for the michael@0: // IC (from which a pointer to the IC entry can be retrieved). When monitoring michael@0: // the types of 'this', arguments or other values with no associated IC, there michael@0: // is no main fallback stub, and the IC entry is referenced directly. michael@0: class ICTypeMonitor_Fallback : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: // Pointer to the main fallback stub for the IC or to the main IC entry, michael@0: // depending on hasFallbackStub. michael@0: union { michael@0: ICMonitoredFallbackStub *mainFallbackStub_; michael@0: ICEntry *icEntry_; michael@0: }; michael@0: michael@0: // Pointer to the first monitor stub. michael@0: ICStub *firstMonitorStub_; michael@0: michael@0: // Address of the last monitor stub's field pointing to this michael@0: // fallback monitor stub. This will get updated when new michael@0: // monitor stubs are created and added. michael@0: ICStub **lastMonitorStubPtrAddr_; michael@0: michael@0: // Count of optimized type monitor stubs in this chain. michael@0: uint32_t numOptimizedMonitorStubs_ : 8; michael@0: michael@0: // Whether this has a fallback stub referring to the IC entry. michael@0: bool hasFallbackStub_ : 1; michael@0: michael@0: // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX michael@0: // if this is monitoring the types of values pushed at some bytecode. michael@0: uint32_t argumentIndex_ : 23; michael@0: michael@0: static const uint32_t BYTECODE_INDEX = (1 << 23) - 1; michael@0: michael@0: ICTypeMonitor_Fallback(JitCode *stubCode, ICMonitoredFallbackStub *mainFallbackStub, michael@0: uint32_t argumentIndex) michael@0: : ICStub(ICStub::TypeMonitor_Fallback, stubCode), michael@0: mainFallbackStub_(mainFallbackStub), michael@0: firstMonitorStub_(thisFromCtor()), michael@0: lastMonitorStubPtrAddr_(nullptr), michael@0: numOptimizedMonitorStubs_(0), michael@0: hasFallbackStub_(mainFallbackStub != nullptr), michael@0: argumentIndex_(argumentIndex) michael@0: { } michael@0: michael@0: ICTypeMonitor_Fallback *thisFromCtor() { michael@0: return this; michael@0: } michael@0: michael@0: void addOptimizedMonitorStub(ICStub *stub) { michael@0: stub->setNext(this); michael@0: michael@0: JS_ASSERT((lastMonitorStubPtrAddr_ != nullptr) == michael@0: (numOptimizedMonitorStubs_ || !hasFallbackStub_)); michael@0: michael@0: if (lastMonitorStubPtrAddr_) michael@0: *lastMonitorStubPtrAddr_ = stub; michael@0: michael@0: if (numOptimizedMonitorStubs_ == 0) { michael@0: JS_ASSERT(firstMonitorStub_ == this); michael@0: firstMonitorStub_ = stub; michael@0: } else { michael@0: JS_ASSERT(firstMonitorStub_ != nullptr); michael@0: } michael@0: michael@0: lastMonitorStubPtrAddr_ = stub->addressOfNext(); michael@0: numOptimizedMonitorStubs_++; michael@0: } michael@0: michael@0: public: michael@0: static inline ICTypeMonitor_Fallback *New( michael@0: ICStubSpace *space, JitCode *code, ICMonitoredFallbackStub *mainFbStub, michael@0: uint32_t argumentIndex) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, mainFbStub, argumentIndex); michael@0: } michael@0: michael@0: bool hasStub(ICStub::Kind kind) { michael@0: ICStub *stub = firstMonitorStub_; michael@0: do { michael@0: if (stub->kind() == kind) michael@0: return true; michael@0: michael@0: stub = stub->next(); michael@0: } while (stub); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: inline ICFallbackStub *mainFallbackStub() const { michael@0: JS_ASSERT(hasFallbackStub_); michael@0: return mainFallbackStub_; michael@0: } michael@0: michael@0: inline ICEntry *icEntry() const { michael@0: return hasFallbackStub_ ? mainFallbackStub()->icEntry() : icEntry_; michael@0: } michael@0: michael@0: inline ICStub *firstMonitorStub() const { michael@0: return firstMonitorStub_; michael@0: } michael@0: michael@0: static inline size_t offsetOfFirstMonitorStub() { michael@0: return offsetof(ICTypeMonitor_Fallback, firstMonitorStub_); michael@0: } michael@0: michael@0: inline uint32_t numOptimizedMonitorStubs() const { michael@0: return numOptimizedMonitorStubs_; michael@0: } michael@0: michael@0: inline bool monitorsThis() const { michael@0: return argumentIndex_ == 0; michael@0: } michael@0: michael@0: inline bool monitorsArgument(uint32_t *pargument) const { michael@0: if (argumentIndex_ > 0 && argumentIndex_ < BYTECODE_INDEX) { michael@0: *pargument = argumentIndex_ - 1; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: inline bool monitorsBytecode() const { michael@0: return argumentIndex_ == BYTECODE_INDEX; michael@0: } michael@0: michael@0: // Fixup the IC entry as for a normal fallback stub, for this/arguments. michael@0: void fixupICEntry(ICEntry *icEntry) { michael@0: JS_ASSERT(!hasFallbackStub_); michael@0: JS_ASSERT(icEntry_ == nullptr); michael@0: JS_ASSERT(lastMonitorStubPtrAddr_ == nullptr); michael@0: icEntry_ = icEntry; michael@0: lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub(); michael@0: } michael@0: michael@0: // Create a new monitor stub for the type of the given value, and michael@0: // add it to this chain. michael@0: bool addMonitorStubForValue(JSContext *cx, JSScript *script, HandleValue val); michael@0: michael@0: void resetMonitorStubChain(Zone *zone); michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: ICMonitoredFallbackStub *mainFallbackStub_; michael@0: uint32_t argumentIndex_; michael@0: michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICMonitoredFallbackStub *mainFallbackStub) michael@0: : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback), michael@0: mainFallbackStub_(mainFallbackStub), michael@0: argumentIndex_(BYTECODE_INDEX) michael@0: { } michael@0: michael@0: Compiler(JSContext *cx, uint32_t argumentIndex) michael@0: : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback), michael@0: mainFallbackStub_(nullptr), michael@0: argumentIndex_(argumentIndex) michael@0: { } michael@0: michael@0: ICTypeMonitor_Fallback *getStub(ICStubSpace *space) { michael@0: return ICTypeMonitor_Fallback::New(space, getStubCode(), mainFallbackStub_, michael@0: argumentIndex_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICTypeMonitor_PrimitiveSet(JitCode *stubCode, uint16_t flags) michael@0: : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICTypeMonitor_PrimitiveSet *New(ICStubSpace *space, JitCode *code, michael@0: uint16_t flags) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, flags); michael@0: } michael@0: michael@0: class Compiler : public TypeCheckPrimitiveSetStub::Compiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICTypeMonitor_PrimitiveSet *existingStub, JSValueType type) michael@0: : TypeCheckPrimitiveSetStub::Compiler(cx, TypeMonitor_PrimitiveSet, existingStub, type) michael@0: {} michael@0: michael@0: ICTypeMonitor_PrimitiveSet *updateStub() { michael@0: TypeCheckPrimitiveSetStub *stub = michael@0: this->TypeCheckPrimitiveSetStub::Compiler::updateStub(); michael@0: if (!stub) michael@0: return nullptr; michael@0: return stub->toMonitorStub(); michael@0: } michael@0: michael@0: ICTypeMonitor_PrimitiveSet *getStub(ICStubSpace *space) { michael@0: JS_ASSERT(!existingStub_); michael@0: return ICTypeMonitor_PrimitiveSet::New(space, getStubCode(), flags_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICTypeMonitor_SingleObject : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrObject obj_; michael@0: michael@0: ICTypeMonitor_SingleObject(JitCode *stubCode, HandleObject obj); michael@0: michael@0: public: michael@0: static inline ICTypeMonitor_SingleObject *New( michael@0: ICStubSpace *space, JitCode *code, HandleObject obj) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, obj); michael@0: } michael@0: michael@0: HeapPtrObject &object() { michael@0: return obj_; michael@0: } michael@0: michael@0: static size_t offsetOfObject() { michael@0: return offsetof(ICTypeMonitor_SingleObject, obj_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: HandleObject obj_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, HandleObject obj) michael@0: : ICStubCompiler(cx, TypeMonitor_SingleObject), michael@0: obj_(obj) michael@0: { } michael@0: michael@0: ICTypeMonitor_SingleObject *getStub(ICStubSpace *space) { michael@0: return ICTypeMonitor_SingleObject::New(space, getStubCode(), obj_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICTypeMonitor_TypeObject : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrTypeObject type_; michael@0: michael@0: ICTypeMonitor_TypeObject(JitCode *stubCode, HandleTypeObject type); michael@0: michael@0: public: michael@0: static inline ICTypeMonitor_TypeObject *New( michael@0: ICStubSpace *space, JitCode *code, HandleTypeObject type) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, type); michael@0: } michael@0: michael@0: HeapPtrTypeObject &type() { michael@0: return type_; michael@0: } michael@0: michael@0: static size_t offsetOfType() { michael@0: return offsetof(ICTypeMonitor_TypeObject, type_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: HandleTypeObject type_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, HandleTypeObject type) michael@0: : ICStubCompiler(cx, TypeMonitor_TypeObject), michael@0: type_(type) michael@0: { } michael@0: michael@0: ICTypeMonitor_TypeObject *getStub(ICStubSpace *space) { michael@0: return ICTypeMonitor_TypeObject::New(space, getStubCode(), type_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // TypeUpdate michael@0: michael@0: extern const VMFunction DoTypeUpdateFallbackInfo; michael@0: michael@0: // The TypeUpdate fallback is not a regular fallback, since it just michael@0: // forwards to a different entry point in the main fallback stub. michael@0: class ICTypeUpdate_Fallback : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICTypeUpdate_Fallback(JitCode *stubCode) michael@0: : ICStub(ICStub::TypeUpdate_Fallback, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICTypeUpdate_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::TypeUpdate_Fallback) michael@0: { } michael@0: michael@0: ICTypeUpdate_Fallback *getStub(ICStubSpace *space) { michael@0: return ICTypeUpdate_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICTypeUpdate_PrimitiveSet : public TypeCheckPrimitiveSetStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICTypeUpdate_PrimitiveSet(JitCode *stubCode, uint16_t flags) michael@0: : TypeCheckPrimitiveSetStub(TypeUpdate_PrimitiveSet, stubCode, flags) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICTypeUpdate_PrimitiveSet *New(ICStubSpace *space, JitCode *code, michael@0: uint16_t flags) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, flags); michael@0: } michael@0: michael@0: class Compiler : public TypeCheckPrimitiveSetStub::Compiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICTypeUpdate_PrimitiveSet *existingStub, JSValueType type) michael@0: : TypeCheckPrimitiveSetStub::Compiler(cx, TypeUpdate_PrimitiveSet, existingStub, type) michael@0: {} michael@0: michael@0: ICTypeUpdate_PrimitiveSet *updateStub() { michael@0: TypeCheckPrimitiveSetStub *stub = michael@0: this->TypeCheckPrimitiveSetStub::Compiler::updateStub(); michael@0: if (!stub) michael@0: return nullptr; michael@0: return stub->toUpdateStub(); michael@0: } michael@0: michael@0: ICTypeUpdate_PrimitiveSet *getStub(ICStubSpace *space) { michael@0: JS_ASSERT(!existingStub_); michael@0: return ICTypeUpdate_PrimitiveSet::New(space, getStubCode(), flags_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Type update stub to handle a singleton object. michael@0: class ICTypeUpdate_SingleObject : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrObject obj_; michael@0: michael@0: ICTypeUpdate_SingleObject(JitCode *stubCode, HandleObject obj); michael@0: michael@0: public: michael@0: static inline ICTypeUpdate_SingleObject *New(ICStubSpace *space, JitCode *code, michael@0: HandleObject obj) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, obj); michael@0: } michael@0: michael@0: HeapPtrObject &object() { michael@0: return obj_; michael@0: } michael@0: michael@0: static size_t offsetOfObject() { michael@0: return offsetof(ICTypeUpdate_SingleObject, obj_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: HandleObject obj_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, HandleObject obj) michael@0: : ICStubCompiler(cx, TypeUpdate_SingleObject), michael@0: obj_(obj) michael@0: { } michael@0: michael@0: ICTypeUpdate_SingleObject *getStub(ICStubSpace *space) { michael@0: return ICTypeUpdate_SingleObject::New(space, getStubCode(), obj_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Type update stub to handle a single TypeObject. michael@0: class ICTypeUpdate_TypeObject : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrTypeObject type_; michael@0: michael@0: ICTypeUpdate_TypeObject(JitCode *stubCode, HandleTypeObject type); michael@0: michael@0: public: michael@0: static inline ICTypeUpdate_TypeObject *New(ICStubSpace *space, JitCode *code, michael@0: HandleTypeObject type) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, type); michael@0: } michael@0: michael@0: HeapPtrTypeObject &type() { michael@0: return type_; michael@0: } michael@0: michael@0: static size_t offsetOfType() { michael@0: return offsetof(ICTypeUpdate_TypeObject, type_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: HandleTypeObject type_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, HandleTypeObject type) michael@0: : ICStubCompiler(cx, TypeUpdate_TypeObject), michael@0: type_(type) michael@0: { } michael@0: michael@0: ICTypeUpdate_TypeObject *getStub(ICStubSpace *space) { michael@0: return ICTypeUpdate_TypeObject::New(space, getStubCode(), type_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // This michael@0: // JSOP_THIS michael@0: michael@0: class ICThis_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICThis_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::This_Fallback, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICThis_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::This_Fallback) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICThis_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICNewArray_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrObject templateObject_; michael@0: michael@0: ICNewArray_Fallback(JitCode *stubCode, JSObject *templateObject) michael@0: : ICFallbackStub(ICStub::NewArray_Fallback, stubCode), templateObject_(templateObject) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICNewArray_Fallback *New(ICStubSpace *space, JitCode *code, michael@0: JSObject *templateObject) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, templateObject); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: RootedObject templateObject; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSObject *templateObject) michael@0: : ICStubCompiler(cx, ICStub::NewArray_Fallback), michael@0: templateObject(cx, templateObject) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICNewArray_Fallback::New(space, getStubCode(), templateObject); michael@0: } michael@0: }; michael@0: michael@0: HeapPtrObject &templateObject() { michael@0: return templateObject_; michael@0: } michael@0: }; michael@0: michael@0: class ICNewObject_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrObject templateObject_; michael@0: michael@0: ICNewObject_Fallback(JitCode *stubCode, JSObject *templateObject) michael@0: : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(templateObject) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICNewObject_Fallback *New(ICStubSpace *space, JitCode *code, michael@0: JSObject *templateObject) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, templateObject); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: RootedObject templateObject; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSObject *templateObject) michael@0: : ICStubCompiler(cx, ICStub::NewObject_Fallback), michael@0: templateObject(cx, templateObject) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICNewObject_Fallback::New(space, getStubCode(), templateObject); michael@0: } michael@0: }; michael@0: michael@0: HeapPtrObject &templateObject() { michael@0: return templateObject_; michael@0: } michael@0: }; michael@0: michael@0: // Compare michael@0: // JSOP_LT michael@0: // JSOP_GT michael@0: michael@0: class ICCompare_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::Compare_Fallback, stubCode) {} michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICCompare_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::Compare_Fallback) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCompare_Int32 : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_Int32(JitCode *stubCode) michael@0: : ICStub(ICStub::Compare_Int32, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICCompare_Int32 *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op) michael@0: : ICMultiStubCompiler(cx, ICStub::Compare_Int32, op) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_Int32::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCompare_Double : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_Double(JitCode *stubCode) michael@0: : ICStub(ICStub::Compare_Double, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICCompare_Double *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op) michael@0: : ICMultiStubCompiler(cx, ICStub::Compare_Double, op) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_Double::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCompare_NumberWithUndefined : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_NumberWithUndefined(JitCode *stubCode, bool lhsIsUndefined) michael@0: : ICStub(ICStub::Compare_NumberWithUndefined, stubCode) michael@0: { michael@0: extra_ = lhsIsUndefined; michael@0: } michael@0: michael@0: public: michael@0: static inline ICCompare_NumberWithUndefined *New(ICStubSpace *space, JitCode *code, bool lhsIsUndefined) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, lhsIsUndefined); michael@0: } michael@0: michael@0: bool lhsIsUndefined() { michael@0: return extra_; michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: bool lhsIsUndefined; michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op, bool lhsIsUndefined) michael@0: : ICMultiStubCompiler(cx, ICStub::Compare_NumberWithUndefined, op), michael@0: lhsIsUndefined(lhsIsUndefined) michael@0: {} michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) michael@0: | (static_cast(op) << 16) michael@0: | (static_cast(lhsIsUndefined) << 24); michael@0: } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_NumberWithUndefined::New(space, getStubCode(), lhsIsUndefined); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCompare_String : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_String(JitCode *stubCode) michael@0: : ICStub(ICStub::Compare_String, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICCompare_String *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op) michael@0: : ICMultiStubCompiler(cx, ICStub::Compare_String, op) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_String::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCompare_Boolean : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_Boolean(JitCode *stubCode) michael@0: : ICStub(ICStub::Compare_Boolean, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICCompare_Boolean *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op) michael@0: : ICMultiStubCompiler(cx, ICStub::Compare_Boolean, op) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_Boolean::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCompare_Object : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_Object(JitCode *stubCode) michael@0: : ICStub(ICStub::Compare_Object, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICCompare_Object *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op) michael@0: : ICMultiStubCompiler(cx, ICStub::Compare_Object, op) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_Object::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCompare_ObjectWithUndefined : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_ObjectWithUndefined(JitCode *stubCode) michael@0: : ICStub(ICStub::Compare_ObjectWithUndefined, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICCompare_ObjectWithUndefined *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: bool lhsIsUndefined; michael@0: bool compareWithNull; michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op, bool lhsIsUndefined, bool compareWithNull) michael@0: : ICMultiStubCompiler(cx, ICStub::Compare_ObjectWithUndefined, op), michael@0: lhsIsUndefined(lhsIsUndefined), michael@0: compareWithNull(compareWithNull) michael@0: {} michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) michael@0: | (static_cast(op) << 16) michael@0: | (static_cast(lhsIsUndefined) << 24) michael@0: | (static_cast(compareWithNull) << 25); michael@0: } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_ObjectWithUndefined::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCompare_Int32WithBoolean : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICCompare_Int32WithBoolean(JitCode *stubCode, bool lhsIsInt32) michael@0: : ICStub(ICStub::Compare_Int32WithBoolean, stubCode) michael@0: { michael@0: extra_ = lhsIsInt32; michael@0: } michael@0: michael@0: public: michael@0: static inline ICCompare_Int32WithBoolean *New(ICStubSpace *space, JitCode *code, michael@0: bool lhsIsInt32) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, lhsIsInt32); michael@0: } michael@0: michael@0: bool lhsIsInt32() const { michael@0: return extra_; michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: JSOp op_; michael@0: bool lhsIsInt32_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return (static_cast(kind) | (static_cast(op_) << 16) | michael@0: (static_cast(lhsIsInt32_) << 24)); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op, bool lhsIsInt32) michael@0: : ICStubCompiler(cx, ICStub::Compare_Int32WithBoolean), michael@0: op_(op), michael@0: lhsIsInt32_(lhsIsInt32) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCompare_Int32WithBoolean::New(space, getStubCode(), lhsIsInt32_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // ToBool michael@0: // JSOP_IFNE michael@0: michael@0: class ICToBool_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICToBool_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::ToBool_Fallback, stubCode) {} michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICToBool_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::ToBool_Fallback) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICToBool_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICToBool_Int32 : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICToBool_Int32(JitCode *stubCode) michael@0: : ICStub(ICStub::ToBool_Int32, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICToBool_Int32 *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::ToBool_Int32) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICToBool_Int32::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICToBool_String : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICToBool_String(JitCode *stubCode) michael@0: : ICStub(ICStub::ToBool_String, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICToBool_String *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::ToBool_String) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICToBool_String::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICToBool_NullUndefined : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICToBool_NullUndefined(JitCode *stubCode) michael@0: : ICStub(ICStub::ToBool_NullUndefined, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICToBool_NullUndefined *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::ToBool_NullUndefined) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICToBool_NullUndefined::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICToBool_Double : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICToBool_Double(JitCode *stubCode) michael@0: : ICStub(ICStub::ToBool_Double, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICToBool_Double *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::ToBool_Double) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICToBool_Double::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICToBool_Object : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICToBool_Object(JitCode *stubCode) michael@0: : ICStub(ICStub::ToBool_Object, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICToBool_Object *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::ToBool_Object) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICToBool_Object::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // ToNumber michael@0: // JSOP_POS michael@0: michael@0: class ICToNumber_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICToNumber_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::ToNumber_Fallback, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICToNumber_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::ToNumber_Fallback) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICToNumber_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // BinaryArith michael@0: // JSOP_ADD michael@0: // JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR michael@0: // JSOP_LSH, JSOP_RSH, JSOP_URSH michael@0: michael@0: class ICBinaryArith_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICBinaryArith_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(BinaryArith_Fallback, stubCode) michael@0: { michael@0: extra_ = 0; michael@0: } michael@0: michael@0: static const uint16_t SAW_DOUBLE_RESULT_BIT = 0x1; michael@0: static const uint16_t UNOPTIMIZABLE_OPERANDS_BIT = 0x2; michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICBinaryArith_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: bool sawDoubleResult() const { michael@0: return extra_ & SAW_DOUBLE_RESULT_BIT; michael@0: } michael@0: void setSawDoubleResult() { michael@0: extra_ |= SAW_DOUBLE_RESULT_BIT; michael@0: } michael@0: bool hadUnoptimizableOperands() const { michael@0: return extra_ & UNOPTIMIZABLE_OPERANDS_BIT; michael@0: } michael@0: void noteUnoptimizableOperands() { michael@0: extra_ |= UNOPTIMIZABLE_OPERANDS_BIT; michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::BinaryArith_Fallback) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICBinaryArith_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICBinaryArith_Int32 : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICBinaryArith_Int32(JitCode *stubCode, bool allowDouble) michael@0: : ICStub(BinaryArith_Int32, stubCode) michael@0: { michael@0: extra_ = allowDouble; michael@0: } michael@0: michael@0: public: michael@0: static inline ICBinaryArith_Int32 *New(ICStubSpace *space, JitCode *code, bool allowDouble) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, allowDouble); michael@0: } michael@0: bool allowDouble() const { michael@0: return extra_; michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: JSOp op_; michael@0: bool allowDouble_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: // Stub keys shift-stubs need to encode the kind, the JSOp and if we allow doubles. michael@0: virtual int32_t getKey() const { michael@0: return (static_cast(kind) | (static_cast(op_) << 16) | michael@0: (static_cast(allowDouble_) << 24)); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op, bool allowDouble) michael@0: : ICStubCompiler(cx, ICStub::BinaryArith_Int32), michael@0: op_(op), allowDouble_(allowDouble) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICBinaryArith_Int32::New(space, getStubCode(), allowDouble_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICBinaryArith_StringConcat : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICBinaryArith_StringConcat(JitCode *stubCode) michael@0: : ICStub(BinaryArith_StringConcat, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICBinaryArith_StringConcat *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::BinaryArith_StringConcat) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICBinaryArith_StringConcat::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICBinaryArith_StringObjectConcat : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICBinaryArith_StringObjectConcat(JitCode *stubCode, bool lhsIsString) michael@0: : ICStub(BinaryArith_StringObjectConcat, stubCode) michael@0: { michael@0: extra_ = lhsIsString; michael@0: } michael@0: michael@0: public: michael@0: static inline ICBinaryArith_StringObjectConcat *New(ICStubSpace *space, JitCode *code, michael@0: bool lhsIsString) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, lhsIsString); michael@0: } michael@0: michael@0: bool lhsIsString() const { michael@0: return extra_; michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool lhsIsString_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(lhsIsString_) << 16); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, bool lhsIsString) michael@0: : ICStubCompiler(cx, ICStub::BinaryArith_StringObjectConcat), michael@0: lhsIsString_(lhsIsString) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICBinaryArith_StringObjectConcat::New(space, getStubCode(), lhsIsString_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICBinaryArith_Double : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICBinaryArith_Double(JitCode *stubCode) michael@0: : ICStub(BinaryArith_Double, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICBinaryArith_Double *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op) michael@0: : ICMultiStubCompiler(cx, ICStub::BinaryArith_Double, op) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICBinaryArith_Double::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICBinaryArith_BooleanWithInt32 : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICBinaryArith_BooleanWithInt32(JitCode *stubCode, bool lhsIsBool, bool rhsIsBool) michael@0: : ICStub(BinaryArith_BooleanWithInt32, stubCode) michael@0: { michael@0: JS_ASSERT(lhsIsBool || rhsIsBool); michael@0: extra_ = 0; michael@0: if (lhsIsBool) michael@0: extra_ |= 1; michael@0: if (rhsIsBool) michael@0: extra_ |= 2; michael@0: } michael@0: michael@0: public: michael@0: static inline ICBinaryArith_BooleanWithInt32 *New(ICStubSpace *space, JitCode *code, michael@0: bool lhsIsBool, bool rhsIsBool) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, lhsIsBool, rhsIsBool); michael@0: } michael@0: michael@0: bool lhsIsBoolean() const { michael@0: return extra_ & 1; michael@0: } michael@0: michael@0: bool rhsIsBoolean() const { michael@0: return extra_ & 2; michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: JSOp op_; michael@0: bool lhsIsBool_; michael@0: bool rhsIsBool_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(op_) << 16) | michael@0: (static_cast(lhsIsBool_) << 24) | michael@0: (static_cast(rhsIsBool_) << 25); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op, bool lhsIsBool, bool rhsIsBool) michael@0: : ICStubCompiler(cx, ICStub::BinaryArith_BooleanWithInt32), michael@0: op_(op), lhsIsBool_(lhsIsBool), rhsIsBool_(rhsIsBool) michael@0: { michael@0: JS_ASSERT(op_ == JSOP_ADD || op_ == JSOP_SUB || op_ == JSOP_BITOR || michael@0: op_ == JSOP_BITAND || op_ == JSOP_BITXOR); michael@0: JS_ASSERT(lhsIsBool_ || rhsIsBool_); michael@0: } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICBinaryArith_BooleanWithInt32::New(space, getStubCode(), michael@0: lhsIsBool_, rhsIsBool_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICBinaryArith_DoubleWithInt32 : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICBinaryArith_DoubleWithInt32(JitCode *stubCode, bool lhsIsDouble) michael@0: : ICStub(BinaryArith_DoubleWithInt32, stubCode) michael@0: { michael@0: extra_ = lhsIsDouble; michael@0: } michael@0: michael@0: public: michael@0: static inline ICBinaryArith_DoubleWithInt32 *New(ICStubSpace *space, JitCode *code, michael@0: bool lhsIsDouble) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, lhsIsDouble); michael@0: } michael@0: michael@0: bool lhsIsDouble() const { michael@0: return extra_; michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool lhsIsDouble_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(op) << 16) | michael@0: (static_cast(lhsIsDouble_) << 24); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op, bool lhsIsDouble) michael@0: : ICMultiStubCompiler(cx, ICStub::BinaryArith_DoubleWithInt32, op), michael@0: lhsIsDouble_(lhsIsDouble) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICBinaryArith_DoubleWithInt32::New(space, getStubCode(), lhsIsDouble_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // UnaryArith michael@0: // JSOP_BITNOT michael@0: // JSOP_NEG michael@0: michael@0: class ICUnaryArith_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICUnaryArith_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(UnaryArith_Fallback, stubCode) michael@0: { michael@0: extra_ = 0; michael@0: } michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICUnaryArith_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: bool sawDoubleResult() { michael@0: return extra_; michael@0: } michael@0: void setSawDoubleResult() { michael@0: extra_ = 1; michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::UnaryArith_Fallback) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICUnaryArith_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICUnaryArith_Int32 : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICUnaryArith_Int32(JitCode *stubCode) michael@0: : ICStub(UnaryArith_Int32, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICUnaryArith_Int32 *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op) michael@0: : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICUnaryArith_Int32::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICUnaryArith_Double : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICUnaryArith_Double(JitCode *stubCode) michael@0: : ICStub(UnaryArith_Double, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICUnaryArith_Double *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICMultiStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSOp op) michael@0: : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICUnaryArith_Double::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // GetElem michael@0: // JSOP_GETELEM michael@0: michael@0: class ICGetElem_Fallback : public ICMonitoredFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetElem_Fallback(JitCode *stubCode) michael@0: : ICMonitoredFallbackStub(ICStub::GetElem_Fallback, stubCode) michael@0: { } michael@0: michael@0: static const uint16_t EXTRA_NON_NATIVE = 0x1; michael@0: static const uint16_t EXTRA_NEGATIVE_INDEX = 0x2; michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 16; michael@0: michael@0: static inline ICGetElem_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: void noteNonNativeAccess() { michael@0: extra_ |= EXTRA_NON_NATIVE; michael@0: } michael@0: bool hasNonNativeAccess() const { michael@0: return extra_ & EXTRA_NON_NATIVE; michael@0: } michael@0: michael@0: void noteNegativeIndex() { michael@0: extra_ |= EXTRA_NEGATIVE_INDEX; michael@0: } michael@0: bool hasNegativeIndex() const { michael@0: return extra_ & EXTRA_NEGATIVE_INDEX; michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::GetElem_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: ICGetElem_Fallback *stub = ICGetElem_Fallback::New(space, getStubCode()); michael@0: if (!stub) michael@0: return nullptr; michael@0: if (!stub->initMonitoringChain(cx, space)) michael@0: return nullptr; michael@0: return stub; michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICGetElemNativeStub : public ICMonitoredStub michael@0: { michael@0: public: michael@0: enum AccessType { FixedSlot = 0, DynamicSlot, NativeGetter, ScriptedGetter }; michael@0: michael@0: protected: michael@0: HeapPtrShape shape_; michael@0: HeapPtrPropertyName name_; michael@0: michael@0: static const unsigned NEEDS_ATOMIZE_SHIFT = 0; michael@0: static const uint16_t NEEDS_ATOMIZE_MASK = 0x1; michael@0: michael@0: static const unsigned ACCESSTYPE_SHIFT = 1; michael@0: static const uint16_t ACCESSTYPE_MASK = 0x3; michael@0: michael@0: ICGetElemNativeStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, AccessType acctype, michael@0: bool needsAtomize); michael@0: michael@0: ~ICGetElemNativeStub(); michael@0: michael@0: public: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICGetElemNativeStub, shape_); michael@0: } michael@0: michael@0: HeapPtrPropertyName &name() { michael@0: return name_; michael@0: } michael@0: static size_t offsetOfName() { michael@0: return offsetof(ICGetElemNativeStub, name_); michael@0: } michael@0: michael@0: AccessType accessType() const { michael@0: return static_cast((extra_ >> ACCESSTYPE_SHIFT) & ACCESSTYPE_MASK); michael@0: } michael@0: michael@0: bool needsAtomize() const { michael@0: return (extra_ >> NEEDS_ATOMIZE_SHIFT) & NEEDS_ATOMIZE_MASK; michael@0: } michael@0: }; michael@0: michael@0: class ICGetElemNativeSlotStub : public ICGetElemNativeStub michael@0: { michael@0: protected: michael@0: uint32_t offset_; michael@0: michael@0: ICGetElemNativeSlotStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, michael@0: AccessType acctype, bool needsAtomize, uint32_t offset) michael@0: : ICGetElemNativeStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize), michael@0: offset_(offset) michael@0: { michael@0: JS_ASSERT(kind == GetElem_NativeSlot || kind == GetElem_NativePrototypeSlot); michael@0: JS_ASSERT(acctype == FixedSlot || acctype == DynamicSlot); michael@0: } michael@0: michael@0: public: michael@0: uint32_t offset() const { michael@0: return offset_; michael@0: } michael@0: michael@0: static size_t offsetOfOffset() { michael@0: return offsetof(ICGetElemNativeSlotStub, offset_); michael@0: } michael@0: }; michael@0: michael@0: class ICGetElemNativeGetterStub : public ICGetElemNativeStub michael@0: { michael@0: protected: michael@0: HeapPtrFunction getter_; michael@0: uint32_t pcOffset_; michael@0: michael@0: ICGetElemNativeGetterStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, AccessType acctype, michael@0: bool needsAtomize, HandleFunction getter, uint32_t pcOffset); michael@0: michael@0: public: michael@0: HeapPtrFunction &getter() { michael@0: return getter_; michael@0: } michael@0: static size_t offsetOfGetter() { michael@0: return offsetof(ICGetElemNativeGetterStub, getter_); michael@0: } michael@0: michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICGetElemNativeGetterStub, pcOffset_); michael@0: } michael@0: }; michael@0: michael@0: class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub michael@0: { michael@0: friend class ICStubSpace; michael@0: ICGetElem_NativeSlot(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, michael@0: AccessType acctype, bool needsAtomize, uint32_t offset) michael@0: : ICGetElemNativeSlotStub(ICStub::GetElem_NativeSlot, stubCode, firstMonitorStub, shape, michael@0: name, acctype, needsAtomize, offset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetElem_NativeSlot *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, michael@0: AccessType acctype, bool needsAtomize, uint32_t offset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, shape, name, michael@0: acctype, needsAtomize, offset); michael@0: } michael@0: }; michael@0: michael@0: class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub michael@0: { michael@0: friend class ICStubSpace; michael@0: HeapPtrObject holder_; michael@0: HeapPtrShape holderShape_; michael@0: michael@0: ICGetElem_NativePrototypeSlot(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, michael@0: AccessType acctype, bool needsAtomize, uint32_t offset, michael@0: HandleObject holder, HandleShape holderShape); michael@0: michael@0: public: michael@0: static inline ICGetElem_NativePrototypeSlot *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, michael@0: AccessType acctype, bool needsAtomize, michael@0: uint32_t offset, HandleObject holder, michael@0: HandleShape holderShape) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate( michael@0: code, firstMonitorStub, shape, name, acctype, needsAtomize, offset, holder, michael@0: holderShape); michael@0: } michael@0: michael@0: HeapPtrObject &holder() { michael@0: return holder_; michael@0: } michael@0: static size_t offsetOfHolder() { michael@0: return offsetof(ICGetElem_NativePrototypeSlot, holder_); michael@0: } michael@0: michael@0: HeapPtrShape &holderShape() { michael@0: return holderShape_; michael@0: } michael@0: static size_t offsetOfHolderShape() { michael@0: return offsetof(ICGetElem_NativePrototypeSlot, holderShape_); michael@0: } michael@0: }; michael@0: michael@0: class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub michael@0: { michael@0: friend class ICStubSpace; michael@0: HeapPtrObject holder_; michael@0: HeapPtrShape holderShape_; michael@0: michael@0: protected: michael@0: ICGetElemNativePrototypeCallStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, michael@0: AccessType acctype, bool needsAtomize, HandleFunction getter, michael@0: uint32_t pcOffset, HandleObject holder, michael@0: HandleShape holderShape); michael@0: michael@0: public: michael@0: HeapPtrObject &holder() { michael@0: return holder_; michael@0: } michael@0: static size_t offsetOfHolder() { michael@0: return offsetof(ICGetElemNativePrototypeCallStub, holder_); michael@0: } michael@0: michael@0: HeapPtrShape &holderShape() { michael@0: return holderShape_; michael@0: } michael@0: static size_t offsetOfHolderShape() { michael@0: return offsetof(ICGetElemNativePrototypeCallStub, holderShape_); michael@0: } michael@0: }; michael@0: michael@0: class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetElem_NativePrototypeCallNative(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, michael@0: AccessType acctype, bool needsAtomize, michael@0: HandleFunction getter, uint32_t pcOffset, michael@0: HandleObject holder, HandleShape holderShape) michael@0: : ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallNative, michael@0: stubCode, firstMonitorStub, shape, name, michael@0: acctype, needsAtomize, getter, pcOffset, holder, michael@0: holderShape) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetElem_NativePrototypeCallNative *New( michael@0: ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, AccessType acctype, michael@0: bool needsAtomize, HandleFunction getter, uint32_t pcOffset, michael@0: HandleObject holder, HandleShape holderShape) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate( michael@0: code, firstMonitorStub, shape, name, acctype, needsAtomize, getter, michael@0: pcOffset, holder, holderShape); michael@0: } michael@0: }; michael@0: michael@0: class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetElem_NativePrototypeCallScripted(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, michael@0: AccessType acctype, bool needsAtomize, michael@0: HandleFunction getter, uint32_t pcOffset, michael@0: HandleObject holder, HandleShape holderShape) michael@0: : ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallScripted, michael@0: stubCode, firstMonitorStub, shape, name, michael@0: acctype, needsAtomize, getter, pcOffset, holder, michael@0: holderShape) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetElem_NativePrototypeCallScripted *New( michael@0: ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleShape shape, HandlePropertyName name, AccessType acctype, michael@0: bool needsAtomize, HandleFunction getter, uint32_t pcOffset, michael@0: HandleObject holder, HandleShape holderShape) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate( michael@0: code, firstMonitorStub, shape, name, acctype, needsAtomize, getter, michael@0: pcOffset, holder, holderShape); michael@0: } michael@0: }; michael@0: michael@0: // Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs. michael@0: class ICGetElemNativeCompiler : public ICStubCompiler michael@0: { michael@0: bool isCallElem_; michael@0: ICStub *firstMonitorStub_; michael@0: HandleObject obj_; michael@0: HandleObject holder_; michael@0: HandlePropertyName name_; michael@0: ICGetElemNativeStub::AccessType acctype_; michael@0: bool needsAtomize_; michael@0: uint32_t offset_; michael@0: HandleFunction getter_; michael@0: uint32_t pcOffset_; michael@0: michael@0: bool emitCallNative(MacroAssembler &masm, Register objReg); michael@0: bool emitCallScripted(MacroAssembler &masm, Register objReg); michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: protected: michael@0: virtual int32_t getKey() const { michael@0: #if JS_HAS_NO_SUCH_METHOD michael@0: return static_cast(kind) | michael@0: (static_cast(isCallElem_) << 16) | michael@0: (static_cast(needsAtomize_) << 17) | michael@0: (static_cast(acctype_) << 18); michael@0: #else michael@0: return static_cast(kind) | (static_cast(needsAtomize_) << 16) | michael@0: (static_cast(acctype_) << 17); michael@0: #endif michael@0: } michael@0: michael@0: public: michael@0: ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, bool isCallElem, michael@0: ICStub *firstMonitorStub, HandleObject obj, HandleObject holder, michael@0: HandlePropertyName name, ICGetElemNativeStub::AccessType acctype, michael@0: bool needsAtomize, uint32_t offset) michael@0: : ICStubCompiler(cx, kind), michael@0: isCallElem_(isCallElem), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: obj_(obj), michael@0: holder_(holder), michael@0: name_(name), michael@0: acctype_(acctype), michael@0: needsAtomize_(needsAtomize), michael@0: offset_(offset), michael@0: getter_(js::NullPtr()), michael@0: pcOffset_(0) michael@0: {} michael@0: michael@0: ICGetElemNativeCompiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, michael@0: HandleObject obj, HandleObject holder, HandlePropertyName name, michael@0: ICGetElemNativeStub::AccessType acctype, bool needsAtomize, michael@0: HandleFunction getter, uint32_t pcOffset, bool isCallElem) michael@0: : ICStubCompiler(cx, kind), michael@0: isCallElem_(false), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: obj_(obj), michael@0: holder_(holder), michael@0: name_(name), michael@0: acctype_(acctype), michael@0: needsAtomize_(needsAtomize), michael@0: offset_(0), michael@0: getter_(getter), michael@0: pcOffset_(pcOffset) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: RootedShape shape(cx, obj_->lastProperty()); michael@0: if (kind == ICStub::GetElem_NativeSlot) { michael@0: JS_ASSERT(obj_ == holder_); michael@0: return ICGetElem_NativeSlot::New( michael@0: space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_, michael@0: offset_); michael@0: } michael@0: michael@0: JS_ASSERT(obj_ != holder_); michael@0: RootedShape holderShape(cx, holder_->lastProperty()); michael@0: if (kind == ICStub::GetElem_NativePrototypeSlot) { michael@0: return ICGetElem_NativePrototypeSlot::New( michael@0: space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_, michael@0: offset_, holder_, holderShape); michael@0: } michael@0: michael@0: if (kind == ICStub::GetElem_NativePrototypeCallNative) { michael@0: return ICGetElem_NativePrototypeCallNative::New( michael@0: space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_, michael@0: getter_, pcOffset_, holder_, holderShape); michael@0: } michael@0: michael@0: JS_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScripted); michael@0: if (kind == ICStub::GetElem_NativePrototypeCallScripted) { michael@0: return ICGetElem_NativePrototypeCallScripted::New( michael@0: space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_, michael@0: getter_, pcOffset_, holder_, holderShape); michael@0: } michael@0: michael@0: MOZ_ASSUME_UNREACHABLE("Invalid kind."); michael@0: return nullptr; michael@0: } michael@0: }; michael@0: michael@0: class ICGetElem_String : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetElem_String(JitCode *stubCode) michael@0: : ICStub(ICStub::GetElem_String, stubCode) {} michael@0: michael@0: public: michael@0: static inline ICGetElem_String *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::GetElem_String) {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetElem_String::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICGetElem_Dense : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrShape shape_; michael@0: michael@0: ICGetElem_Dense(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape); michael@0: michael@0: public: michael@0: static inline ICGetElem_Dense *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, HandleShape shape) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, shape); michael@0: } michael@0: michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICGetElem_Dense, shape_); michael@0: } michael@0: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: ICStub *firstMonitorStub_; michael@0: RootedShape shape_; michael@0: bool isCallElem_; michael@0: michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: #if JS_HAS_NO_SUCH_METHOD michael@0: return static_cast(kind) | (static_cast(isCallElem_) << 16); michael@0: #else michael@0: return static_cast(kind); michael@0: #endif michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, Shape *shape, bool isCallElem) michael@0: : ICStubCompiler(cx, ICStub::GetElem_Dense), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: shape_(cx, shape), michael@0: isCallElem_(isCallElem) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetElem_Dense::New(space, getStubCode(), firstMonitorStub_, shape_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICGetElem_TypedArray : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: // Protected to silence Clang warning. michael@0: HeapPtrShape shape_; michael@0: michael@0: ICGetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type); michael@0: michael@0: public: michael@0: static inline ICGetElem_TypedArray *New(ICStubSpace *space, JitCode *code, michael@0: HandleShape shape, uint32_t type) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, shape, type); michael@0: } michael@0: michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICGetElem_TypedArray, shape_); michael@0: } michael@0: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: RootedShape shape_; michael@0: uint32_t type_; michael@0: michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(type_) << 16); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, Shape *shape, uint32_t type) michael@0: : ICStubCompiler(cx, ICStub::GetElem_TypedArray), michael@0: shape_(cx, shape), michael@0: type_(type) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetElem_TypedArray::New(space, getStubCode(), shape_, type_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICGetElem_Arguments : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: public: michael@0: enum Which { Normal, Strict, Magic }; michael@0: michael@0: private: michael@0: ICGetElem_Arguments(JitCode *stubCode, ICStub *firstMonitorStub, Which which) michael@0: : ICMonitoredStub(ICStub::GetElem_Arguments, stubCode, firstMonitorStub) michael@0: { michael@0: extra_ = static_cast(which); michael@0: } michael@0: michael@0: public: michael@0: static inline ICGetElem_Arguments *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, Which which) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, which); michael@0: } michael@0: michael@0: Which which() const { michael@0: return static_cast(extra_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: ICStub *firstMonitorStub_; michael@0: Which which_; michael@0: bool isCallElem_; michael@0: michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: #if JS_HAS_NO_SUCH_METHOD michael@0: return static_cast(kind) | michael@0: static_cast(isCallElem_ << 16) | michael@0: (static_cast(which_) << 17); michael@0: #else michael@0: return static_cast(kind) | (static_cast(which_) << 16); michael@0: #endif michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, Which which, bool isCallElem) michael@0: : ICStubCompiler(cx, ICStub::GetElem_Arguments), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: which_(which), michael@0: isCallElem_(isCallElem) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetElem_Arguments::New(space, getStubCode(), firstMonitorStub_, which_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // SetElem michael@0: // JSOP_SETELEM michael@0: // JSOP_INITELEM michael@0: michael@0: class ICSetElem_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICSetElem_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::SetElem_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICSetElem_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: void noteArrayWriteHole() { michael@0: extra_ = 1; michael@0: } michael@0: bool hasArrayWriteHole() const { michael@0: return extra_; michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::SetElem_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICSetElem_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICSetElem_Dense : public ICUpdatedStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrShape shape_; michael@0: HeapPtrTypeObject type_; michael@0: michael@0: ICSetElem_Dense(JitCode *stubCode, HandleShape shape, HandleTypeObject type); michael@0: michael@0: public: michael@0: static inline ICSetElem_Dense *New(ICStubSpace *space, JitCode *code, HandleShape shape, michael@0: HandleTypeObject type) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, shape, type); michael@0: } michael@0: michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICSetElem_Dense, shape_); michael@0: } michael@0: static size_t offsetOfType() { michael@0: return offsetof(ICSetElem_Dense, type_); michael@0: } michael@0: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: HeapPtrTypeObject &type() { michael@0: return type_; michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: RootedShape shape_; michael@0: michael@0: // Compiler is only live on stack during compilation, it should michael@0: // outlive any RootedTypeObject it's passed. So it can just michael@0: // use the handle. michael@0: HandleTypeObject type_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, Shape *shape, HandleTypeObject type) michael@0: : ICStubCompiler(cx, ICStub::SetElem_Dense), michael@0: shape_(cx, shape), michael@0: type_(type) michael@0: {} michael@0: michael@0: ICUpdatedStub *getStub(ICStubSpace *space) { michael@0: ICSetElem_Dense *stub = ICSetElem_Dense::New(space, getStubCode(), shape_, type_); michael@0: if (!stub || !stub->initUpdatingChain(cx, space)) michael@0: return nullptr; michael@0: return stub; michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: template class ICSetElem_DenseAddImpl; michael@0: michael@0: class ICSetElem_DenseAdd : public ICUpdatedStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: public: michael@0: static const size_t MAX_PROTO_CHAIN_DEPTH = 4; michael@0: michael@0: protected: michael@0: HeapPtrTypeObject type_; michael@0: michael@0: ICSetElem_DenseAdd(JitCode *stubCode, types::TypeObject *type, size_t protoChainDepth); michael@0: michael@0: public: michael@0: static size_t offsetOfType() { michael@0: return offsetof(ICSetElem_DenseAdd, type_); michael@0: } michael@0: michael@0: HeapPtrTypeObject &type() { michael@0: return type_; michael@0: } michael@0: size_t protoChainDepth() const { michael@0: MOZ_ASSERT(extra_ <= MAX_PROTO_CHAIN_DEPTH); michael@0: return extra_; michael@0: } michael@0: michael@0: template michael@0: ICSetElem_DenseAddImpl *toImplUnchecked() { michael@0: return static_cast *>(this); michael@0: } michael@0: michael@0: template michael@0: ICSetElem_DenseAddImpl *toImpl() { michael@0: JS_ASSERT(ProtoChainDepth == protoChainDepth()); michael@0: return toImplUnchecked(); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: class ICSetElem_DenseAddImpl : public ICSetElem_DenseAdd michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: static const size_t NumShapes = ProtoChainDepth + 1; michael@0: mozilla::Array shapes_; michael@0: michael@0: ICSetElem_DenseAddImpl(JitCode *stubCode, types::TypeObject *type, michael@0: const AutoShapeVector *shapes) michael@0: : ICSetElem_DenseAdd(stubCode, type, ProtoChainDepth) michael@0: { michael@0: JS_ASSERT(shapes->length() == NumShapes); michael@0: for (size_t i = 0; i < NumShapes; i++) michael@0: shapes_[i].init((*shapes)[i]); michael@0: } michael@0: michael@0: public: michael@0: static inline ICSetElem_DenseAddImpl *New(ICStubSpace *space, JitCode *code, michael@0: types::TypeObject *type, michael@0: const AutoShapeVector *shapes) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate >(code, type, shapes); michael@0: } michael@0: michael@0: void traceShapes(JSTracer *trc) { michael@0: for (size_t i = 0; i < NumShapes; i++) michael@0: MarkShape(trc, &shapes_[i], "baseline-setelem-denseadd-stub-shape"); michael@0: } michael@0: Shape *shape(size_t i) const { michael@0: JS_ASSERT(i < NumShapes); michael@0: return shapes_[i]; michael@0: } michael@0: static size_t offsetOfShape(size_t idx) { michael@0: return offsetof(ICSetElem_DenseAddImpl, shapes_) + idx * sizeof(HeapPtrShape); michael@0: } michael@0: }; michael@0: michael@0: class ICSetElemDenseAddCompiler : public ICStubCompiler { michael@0: RootedObject obj_; michael@0: size_t protoChainDepth_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: protected: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(protoChainDepth_) << 16); michael@0: } michael@0: michael@0: public: michael@0: ICSetElemDenseAddCompiler(JSContext *cx, HandleObject obj, size_t protoChainDepth) michael@0: : ICStubCompiler(cx, ICStub::SetElem_DenseAdd), michael@0: obj_(cx, obj), michael@0: protoChainDepth_(protoChainDepth) michael@0: {} michael@0: michael@0: template michael@0: ICUpdatedStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes); michael@0: michael@0: ICUpdatedStub *getStub(ICStubSpace *space); michael@0: }; michael@0: michael@0: class ICSetElem_TypedArray : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: // Protected to silence Clang warning. michael@0: HeapPtrShape shape_; michael@0: michael@0: ICSetElem_TypedArray(JitCode *stubCode, HandleShape shape, uint32_t type, michael@0: bool expectOutOfBounds); michael@0: michael@0: public: michael@0: static inline ICSetElem_TypedArray *New(ICStubSpace *space, JitCode *code, michael@0: HandleShape shape, uint32_t type, michael@0: bool expectOutOfBounds) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, shape, type, expectOutOfBounds); michael@0: } michael@0: michael@0: uint32_t type() const { michael@0: return extra_ & 0xff; michael@0: } michael@0: michael@0: bool expectOutOfBounds() const { michael@0: return (extra_ >> 8) & 1; michael@0: } michael@0: michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICSetElem_TypedArray, shape_); michael@0: } michael@0: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: RootedShape shape_; michael@0: uint32_t type_; michael@0: bool expectOutOfBounds_; michael@0: michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(type_) << 16) | michael@0: (static_cast(expectOutOfBounds_) << 24); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, Shape *shape, uint32_t type, bool expectOutOfBounds) michael@0: : ICStubCompiler(cx, ICStub::SetElem_TypedArray), michael@0: shape_(cx, shape), michael@0: type_(type), michael@0: expectOutOfBounds_(expectOutOfBounds) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICSetElem_TypedArray::New(space, getStubCode(), shape_, type_, michael@0: expectOutOfBounds_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // In michael@0: // JSOP_IN michael@0: class ICIn_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICIn_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::In_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICIn_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::In_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICIn_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // GetName michael@0: // JSOP_NAME michael@0: // JSOP_GETGNAME michael@0: class ICGetName_Fallback : public ICMonitoredFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetName_Fallback(JitCode *stubCode) michael@0: : ICMonitoredFallbackStub(ICStub::GetName_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICGetName_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::GetName_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: ICGetName_Fallback *stub = ICGetName_Fallback::New(space, getStubCode()); michael@0: if (!stub || !stub->initMonitoringChain(cx, space)) michael@0: return nullptr; michael@0: return stub; michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Optimized GETGNAME/CALLGNAME stub. michael@0: class ICGetName_Global : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: // Protected to silence Clang warning. michael@0: HeapPtrShape shape_; michael@0: uint32_t slot_; michael@0: michael@0: ICGetName_Global(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape, uint32_t slot); michael@0: michael@0: public: michael@0: static inline ICGetName_Global *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleShape shape, uint32_t slot) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, shape, slot); michael@0: } michael@0: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICGetName_Global, shape_); michael@0: } michael@0: static size_t offsetOfSlot() { michael@0: return offsetof(ICGetName_Global, slot_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: ICStub *firstMonitorStub_; michael@0: RootedShape shape_; michael@0: uint32_t slot_; michael@0: michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, Shape *shape, uint32_t slot) michael@0: : ICStubCompiler(cx, ICStub::GetName_Global), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: shape_(cx, shape), michael@0: slot_(slot) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetName_Global::New(space, getStubCode(), firstMonitorStub_, shape_, slot_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Optimized GETNAME/CALLNAME stub, making a variable number of hops to get an michael@0: // 'own' property off some scope object. Unlike GETPROP on an object's michael@0: // prototype, there is no teleporting optimization to take advantage of and michael@0: // shape checks are required all along the scope chain. michael@0: template michael@0: class ICGetName_Scope : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: static const size_t MAX_HOPS = 6; michael@0: michael@0: mozilla::Array shapes_; michael@0: uint32_t offset_; michael@0: michael@0: ICGetName_Scope(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: AutoShapeVector *shapes, uint32_t offset); michael@0: michael@0: static Kind GetStubKind() { michael@0: return (Kind) (GetName_Scope0 + NumHops); michael@0: } michael@0: michael@0: public: michael@0: static inline ICGetName_Scope *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: AutoShapeVector *shapes, uint32_t offset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate >(code, firstMonitorStub, shapes, offset); michael@0: } michael@0: michael@0: void traceScopes(JSTracer *trc) { michael@0: for (size_t i = 0; i < NumHops + 1; i++) michael@0: MarkShape(trc, &shapes_[i], "baseline-scope-stub-shape"); michael@0: } michael@0: michael@0: static size_t offsetOfShape(size_t index) { michael@0: JS_ASSERT(index <= NumHops); michael@0: return offsetof(ICGetName_Scope, shapes_) + (index * sizeof(HeapPtrShape)); michael@0: } michael@0: static size_t offsetOfOffset() { michael@0: return offsetof(ICGetName_Scope, offset_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: ICStub *firstMonitorStub_; michael@0: AutoShapeVector *shapes_; michael@0: bool isFixedSlot_; michael@0: uint32_t offset_; michael@0: michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: protected: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(isFixedSlot_) << 16); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, michael@0: AutoShapeVector *shapes, bool isFixedSlot, uint32_t offset) michael@0: : ICStubCompiler(cx, GetStubKind()), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: shapes_(shapes), michael@0: isFixedSlot_(isFixedSlot), michael@0: offset_(offset) michael@0: { michael@0: } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetName_Scope::New(space, getStubCode(), firstMonitorStub_, shapes_, offset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // BindName michael@0: // JSOP_BINDNAME michael@0: class ICBindName_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICBindName_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::BindName_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICBindName_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::BindName_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICBindName_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // GetIntrinsic michael@0: // JSOP_GETINTRINSIC michael@0: class ICGetIntrinsic_Fallback : public ICMonitoredFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetIntrinsic_Fallback(JitCode *stubCode) michael@0: : ICMonitoredFallbackStub(ICStub::GetIntrinsic_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICGetIntrinsic_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::GetIntrinsic_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: ICGetIntrinsic_Fallback *stub = ICGetIntrinsic_Fallback::New(space, getStubCode()); michael@0: if (!stub || !stub->initMonitoringChain(cx, space)) michael@0: return nullptr; michael@0: return stub; michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub that loads the constant result of a GETINTRINSIC operation. michael@0: class ICGetIntrinsic_Constant : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapValue value_; michael@0: michael@0: ICGetIntrinsic_Constant(JitCode *stubCode, HandleValue value); michael@0: ~ICGetIntrinsic_Constant(); michael@0: michael@0: public: michael@0: static inline ICGetIntrinsic_Constant *New(ICStubSpace *space, JitCode *code, michael@0: HandleValue value) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, value); michael@0: } michael@0: michael@0: HeapValue &value() { michael@0: return value_; michael@0: } michael@0: static size_t offsetOfValue() { michael@0: return offsetof(ICGetIntrinsic_Constant, value_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: HandleValue value_; michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, HandleValue value) michael@0: : ICStubCompiler(cx, ICStub::GetIntrinsic_Constant), michael@0: value_(value) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetIntrinsic_Constant::New(space, getStubCode(), value_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICGetProp_Fallback : public ICMonitoredFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetProp_Fallback(JitCode *stubCode) michael@0: : ICMonitoredFallbackStub(ICStub::GetProp_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICGetProp_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0; michael@0: static const size_t ACCESSED_GETTER_BIT = 1; michael@0: michael@0: void noteUnoptimizableAccess() { michael@0: extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT); michael@0: } michael@0: bool hadUnoptimizableAccess() const { michael@0: return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT); michael@0: } michael@0: michael@0: void noteAccessedGetter() { michael@0: extra_ |= (1u << ACCESSED_GETTER_BIT); michael@0: } michael@0: bool hasAccessedGetter() const { michael@0: return extra_ & (1u << ACCESSED_GETTER_BIT); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: uint32_t returnFromIonOffset_; michael@0: uint32_t returnFromStubOffset_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: bool postGenerateStubCode(MacroAssembler &masm, Handle code); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::GetProp_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: ICGetProp_Fallback *stub = ICGetProp_Fallback::New(space, getStubCode()); michael@0: if (!stub || !stub->initMonitoringChain(cx, space)) michael@0: return nullptr; michael@0: return stub; michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for accessing a dense array's length. michael@0: class ICGetProp_ArrayLength : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetProp_ArrayLength(JitCode *stubCode) michael@0: : ICStub(GetProp_ArrayLength, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetProp_ArrayLength *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::GetProp_ArrayLength) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetProp_ArrayLength::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for accessing a typed array's length. michael@0: class ICGetProp_TypedArrayLength : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetProp_TypedArrayLength(JitCode *stubCode) michael@0: : ICStub(GetProp_TypedArrayLength, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetProp_TypedArrayLength *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::GetProp_TypedArrayLength) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetProp_TypedArrayLength::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for accessing a property on a primitive's prototype. michael@0: class ICGetProp_Primitive : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: // Protected to silence Clang warning. michael@0: // Shape of String.prototype/Number.prototype to check for. michael@0: HeapPtrShape protoShape_; michael@0: michael@0: // Fixed or dynamic slot offset. michael@0: uint32_t offset_; michael@0: michael@0: ICGetProp_Primitive(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape protoShape, uint32_t offset); michael@0: michael@0: public: michael@0: static inline ICGetProp_Primitive *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleShape protoShape, uint32_t offset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, protoShape, offset); michael@0: } michael@0: michael@0: HeapPtrShape &protoShape() { michael@0: return protoShape_; michael@0: } michael@0: static size_t offsetOfProtoShape() { michael@0: return offsetof(ICGetProp_Primitive, protoShape_); michael@0: } michael@0: michael@0: static size_t offsetOfOffset() { michael@0: return offsetof(ICGetProp_Primitive, offset_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: ICStub *firstMonitorStub_; michael@0: JSValueType primitiveType_; michael@0: RootedObject prototype_; michael@0: bool isFixedSlot_; michael@0: uint32_t offset_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: protected: michael@0: virtual int32_t getKey() const { michael@0: static_assert(sizeof(JSValueType) == 1, "JSValueType should fit in one byte"); michael@0: return static_cast(kind) michael@0: | (static_cast(isFixedSlot_) << 16) michael@0: | (static_cast(primitiveType_) << 24); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, JSValueType primitiveType, michael@0: HandleObject prototype, bool isFixedSlot, uint32_t offset) michael@0: : ICStubCompiler(cx, ICStub::GetProp_Primitive), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: primitiveType_(primitiveType), michael@0: prototype_(cx, prototype), michael@0: isFixedSlot_(isFixedSlot), michael@0: offset_(offset) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: RootedShape protoShape(cx, prototype_->lastProperty()); michael@0: return ICGetProp_Primitive::New(space, getStubCode(), firstMonitorStub_, michael@0: protoShape, offset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for accessing a string's length. michael@0: class ICGetProp_StringLength : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetProp_StringLength(JitCode *stubCode) michael@0: : ICStub(GetProp_StringLength, stubCode) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetProp_StringLength *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::GetProp_StringLength) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetProp_StringLength::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Base class for GetProp_Native and GetProp_NativePrototype stubs. michael@0: class ICGetPropNativeStub : public ICMonitoredStub michael@0: { michael@0: // Object shape (lastProperty). michael@0: HeapPtrShape shape_; michael@0: michael@0: // Fixed or dynamic slot offset. michael@0: uint32_t offset_; michael@0: michael@0: protected: michael@0: ICGetPropNativeStub(ICStub::Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, uint32_t offset); michael@0: michael@0: public: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: uint32_t offset() const { michael@0: return offset_; michael@0: } michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICGetPropNativeStub, shape_); michael@0: } michael@0: static size_t offsetOfOffset() { michael@0: return offsetof(ICGetPropNativeStub, offset_); michael@0: } michael@0: }; michael@0: michael@0: // Stub for accessing an own property on a native object. michael@0: class ICGetProp_Native : public ICGetPropNativeStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICGetProp_Native(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape, michael@0: uint32_t offset) michael@0: : ICGetPropNativeStub(GetProp_Native, stubCode, firstMonitorStub, shape, offset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetProp_Native *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, HandleShape shape, michael@0: uint32_t offset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, shape, offset); michael@0: } michael@0: }; michael@0: michael@0: // Stub for accessing a property on a native object's prototype. Note that due to michael@0: // the shape teleporting optimization, we only have to guard on the object's shape michael@0: // and the holder's shape. michael@0: class ICGetProp_NativePrototype : public ICGetPropNativeStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: // Holder and its shape. michael@0: HeapPtrObject holder_; michael@0: HeapPtrShape holderShape_; michael@0: michael@0: ICGetProp_NativePrototype(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape, michael@0: uint32_t offset, HandleObject holder, HandleShape holderShape); michael@0: michael@0: public: michael@0: static inline ICGetProp_NativePrototype *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, HandleShape shape, michael@0: uint32_t offset, HandleObject holder, michael@0: HandleShape holderShape) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, shape, offset, michael@0: holder, holderShape); michael@0: } michael@0: michael@0: public: michael@0: HeapPtrObject &holder() { michael@0: return holder_; michael@0: } michael@0: HeapPtrShape &holderShape() { michael@0: return holderShape_; michael@0: } michael@0: static size_t offsetOfHolder() { michael@0: return offsetof(ICGetProp_NativePrototype, holder_); michael@0: } michael@0: static size_t offsetOfHolderShape() { michael@0: return offsetof(ICGetProp_NativePrototype, holderShape_); michael@0: } michael@0: }; michael@0: michael@0: michael@0: // Compiler for GetProp_Native and GetProp_NativePrototype stubs. michael@0: class ICGetPropNativeCompiler : public ICStubCompiler michael@0: { michael@0: bool isCallProp_; michael@0: ICStub *firstMonitorStub_; michael@0: HandleObject obj_; michael@0: HandleObject holder_; michael@0: HandlePropertyName propName_; michael@0: bool isFixedSlot_; michael@0: uint32_t offset_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: protected: michael@0: virtual int32_t getKey() const { michael@0: #if JS_HAS_NO_SUCH_METHOD michael@0: return static_cast(kind) | michael@0: (static_cast(isCallProp_) << 16) | michael@0: (static_cast(isFixedSlot_) << 17); michael@0: #else michael@0: return static_cast(kind) | (static_cast(isFixedSlot_) << 16); michael@0: #endif michael@0: } michael@0: michael@0: public: michael@0: ICGetPropNativeCompiler(JSContext *cx, ICStub::Kind kind, bool isCallProp, michael@0: ICStub *firstMonitorStub, HandleObject obj, HandleObject holder, michael@0: HandlePropertyName propName, bool isFixedSlot, uint32_t offset) michael@0: : ICStubCompiler(cx, kind), michael@0: isCallProp_(isCallProp), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: obj_(obj), michael@0: holder_(holder), michael@0: propName_(propName), michael@0: isFixedSlot_(isFixedSlot), michael@0: offset_(offset) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: RootedShape shape(cx, obj_->lastProperty()); michael@0: if (kind == ICStub::GetProp_Native) { michael@0: JS_ASSERT(obj_ == holder_); michael@0: return ICGetProp_Native::New(space, getStubCode(), firstMonitorStub_, shape, offset_); michael@0: } michael@0: michael@0: JS_ASSERT(obj_ != holder_); michael@0: JS_ASSERT(kind == ICStub::GetProp_NativePrototype); michael@0: RootedShape holderShape(cx, holder_->lastProperty()); michael@0: return ICGetProp_NativePrototype::New(space, getStubCode(), firstMonitorStub_, shape, michael@0: offset_, holder_, holderShape); michael@0: } michael@0: }; michael@0: michael@0: class ICGetPropCallGetter : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: // We don't strictly need this for own property getters, but we need it to do michael@0: // Ion optimizations, so we should keep it around. michael@0: HeapPtrObject holder_; michael@0: michael@0: HeapPtrShape holderShape_; michael@0: michael@0: // Function to call. michael@0: HeapPtrFunction getter_; michael@0: michael@0: // PC offset of call michael@0: uint32_t pcOffset_; michael@0: michael@0: ICGetPropCallGetter(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, HandleObject holder, michael@0: HandleShape holderShape, HandleFunction getter, uint32_t pcOffset); michael@0: michael@0: public: michael@0: HeapPtrObject &holder() { michael@0: return holder_; michael@0: } michael@0: HeapPtrShape &holderShape() { michael@0: return holderShape_; michael@0: } michael@0: HeapPtrFunction &getter() { michael@0: return getter_; michael@0: } michael@0: michael@0: static size_t offsetOfHolder() { michael@0: return offsetof(ICGetPropCallGetter, holder_); michael@0: } michael@0: static size_t offsetOfHolderShape() { michael@0: return offsetof(ICGetPropCallGetter, holderShape_); michael@0: } michael@0: static size_t offsetOfGetter() { michael@0: return offsetof(ICGetPropCallGetter, getter_); michael@0: } michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICGetPropCallGetter, pcOffset_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: ICStub *firstMonitorStub_; michael@0: RootedObject holder_; michael@0: RootedFunction getter_; michael@0: uint32_t pcOffset_; michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, michael@0: HandleObject holder, HandleFunction getter, uint32_t pcOffset) michael@0: : ICStubCompiler(cx, kind), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: holder_(cx, holder), michael@0: getter_(cx, getter), michael@0: pcOffset_(pcOffset) michael@0: { michael@0: JS_ASSERT(kind == ICStub::GetProp_CallScripted || michael@0: kind == ICStub::GetProp_CallNative || michael@0: kind == ICStub::GetProp_CallNativePrototype); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for calling a getter (native or scripted) on a native object when the getter is kept on michael@0: // the proto-chain. michael@0: class ICGetPropCallPrototypeGetter : public ICGetPropCallGetter michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: // shape of receiver object. michael@0: HeapPtrShape receiverShape_; michael@0: michael@0: ICGetPropCallPrototypeGetter(Kind kind, JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape receiverShape, michael@0: HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset); michael@0: michael@0: public: michael@0: HeapPtrShape &receiverShape() { michael@0: return receiverShape_; michael@0: } michael@0: michael@0: static size_t offsetOfReceiverShape() { michael@0: return offsetof(ICGetPropCallPrototypeGetter, receiverShape_); michael@0: } michael@0: michael@0: class Compiler : public ICGetPropCallGetter::Compiler { michael@0: protected: michael@0: RootedObject receiver_; michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub::Kind kind, ICStub *firstMonitorStub, michael@0: HandleObject obj, HandleObject holder, HandleFunction getter, uint32_t pcOffset) michael@0: : ICGetPropCallGetter::Compiler(cx, kind, firstMonitorStub, holder, getter, pcOffset), michael@0: receiver_(cx, obj) michael@0: { michael@0: JS_ASSERT(kind == ICStub::GetProp_CallScripted || michael@0: kind == ICStub::GetProp_CallNativePrototype); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for calling a scripted getter on a native object when the getter is kept on the michael@0: // proto-chain. michael@0: class ICGetProp_CallScripted : public ICGetPropCallPrototypeGetter michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: ICGetProp_CallScripted(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape receiverShape, HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset) michael@0: : ICGetPropCallPrototypeGetter(GetProp_CallScripted, stubCode, firstMonitorStub, michael@0: receiverShape, holder, holderShape, getter, pcOffset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetProp_CallScripted *New( michael@0: ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleShape receiverShape, HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, michael@0: receiverShape, holder, holderShape, getter, michael@0: pcOffset); michael@0: } michael@0: michael@0: class Compiler : public ICGetPropCallPrototypeGetter::Compiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj, michael@0: HandleObject holder, HandleFunction getter, uint32_t pcOffset) michael@0: : ICGetPropCallPrototypeGetter::Compiler(cx, ICStub::GetProp_CallScripted, michael@0: firstMonitorStub, obj, holder, michael@0: getter, pcOffset) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: RootedShape receiverShape(cx, receiver_->lastProperty()); michael@0: RootedShape holderShape(cx, holder_->lastProperty()); michael@0: return ICGetProp_CallScripted::New(space, getStubCode(), firstMonitorStub_, receiverShape, michael@0: holder_, holderShape, getter_, pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for calling an own native getter on a native object. michael@0: class ICGetProp_CallNative : public ICGetPropCallGetter michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: michael@0: ICGetProp_CallNative(JitCode *stubCode, ICStub *firstMonitorStub, HandleObject obj, michael@0: HandleShape shape, HandleFunction getter, uint32_t pcOffset) michael@0: : ICGetPropCallGetter(GetProp_CallNative, stubCode, firstMonitorStub, obj, shape, michael@0: getter, pcOffset) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICGetProp_CallNative *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, HandleObject obj, michael@0: HandleShape shape, HandleFunction getter, michael@0: uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, obj, shape, michael@0: getter, pcOffset); michael@0: } michael@0: michael@0: class Compiler : public ICGetPropCallGetter::Compiler michael@0: { michael@0: bool inputDefinitelyObject_; michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | michael@0: (static_cast(inputDefinitelyObject_) << 16); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj, michael@0: HandleFunction getter, uint32_t pcOffset, bool inputDefinitelyObject = false) michael@0: : ICGetPropCallGetter::Compiler(cx, ICStub::GetProp_CallNative, firstMonitorStub, michael@0: obj, getter, pcOffset), michael@0: inputDefinitelyObject_(inputDefinitelyObject) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: RootedShape shape(cx, holder_->lastProperty()); michael@0: return ICGetProp_CallNative::New(space, getStubCode(), firstMonitorStub_, holder_, michael@0: shape, getter_, pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for calling an native getter on a native object when the getter is kept on the proto-chain. michael@0: class ICGetProp_CallNativePrototype : public ICGetPropCallPrototypeGetter michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: ICGetProp_CallNativePrototype(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape receiverShape, HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset) michael@0: : ICGetPropCallPrototypeGetter(GetProp_CallNativePrototype, stubCode, firstMonitorStub, michael@0: receiverShape, holder, holderShape, getter, pcOffset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetProp_CallNativePrototype *New( michael@0: ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleShape receiverShape, HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, michael@0: receiverShape, holder, holderShape, michael@0: getter, pcOffset); michael@0: } michael@0: michael@0: class Compiler : public ICGetPropCallPrototypeGetter::Compiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj, michael@0: HandleObject holder, HandleFunction getter, uint32_t pcOffset) michael@0: : ICGetPropCallPrototypeGetter::Compiler(cx, ICStub::GetProp_CallNativePrototype, michael@0: firstMonitorStub, obj, holder, michael@0: getter, pcOffset) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: RootedShape receiverShape(cx, receiver_->lastProperty()); michael@0: RootedShape holderShape(cx, holder_->lastProperty()); michael@0: return ICGetProp_CallNativePrototype::New(space, getStubCode(), firstMonitorStub_, receiverShape, michael@0: holder_, holderShape, getter_, pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICGetPropCallDOMProxyNativeStub : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: protected: michael@0: // Shape of the DOMProxy michael@0: HeapPtrShape shape_; michael@0: michael@0: // Proxy handler to check against. michael@0: BaseProxyHandler *proxyHandler_; michael@0: michael@0: // Object shape of expected expando object. (nullptr if no expando object should be there) michael@0: HeapPtrShape expandoShape_; michael@0: michael@0: // Holder and its shape. michael@0: HeapPtrObject holder_; michael@0: HeapPtrShape holderShape_; michael@0: michael@0: // Function to call. michael@0: HeapPtrFunction getter_; michael@0: michael@0: // PC offset of call michael@0: uint32_t pcOffset_; michael@0: michael@0: ICGetPropCallDOMProxyNativeStub(ICStub::Kind kind, JitCode *stubCode, michael@0: ICStub *firstMonitorStub, HandleShape shape, michael@0: BaseProxyHandler *proxyHandler, HandleShape expandoShape, michael@0: HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset); michael@0: michael@0: public: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: HeapPtrShape &expandoShape() { michael@0: return expandoShape_; michael@0: } michael@0: HeapPtrObject &holder() { michael@0: return holder_; michael@0: } michael@0: HeapPtrShape &holderShape() { michael@0: return holderShape_; michael@0: } michael@0: HeapPtrFunction &getter() { michael@0: return getter_; michael@0: } michael@0: uint32_t pcOffset() const { michael@0: return pcOffset_; michael@0: } michael@0: michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICGetPropCallDOMProxyNativeStub, shape_); michael@0: } michael@0: static size_t offsetOfProxyHandler() { michael@0: return offsetof(ICGetPropCallDOMProxyNativeStub, proxyHandler_); michael@0: } michael@0: static size_t offsetOfExpandoShape() { michael@0: return offsetof(ICGetPropCallDOMProxyNativeStub, expandoShape_); michael@0: } michael@0: static size_t offsetOfHolder() { michael@0: return offsetof(ICGetPropCallDOMProxyNativeStub, holder_); michael@0: } michael@0: static size_t offsetOfHolderShape() { michael@0: return offsetof(ICGetPropCallDOMProxyNativeStub, holderShape_); michael@0: } michael@0: static size_t offsetOfGetter() { michael@0: return offsetof(ICGetPropCallDOMProxyNativeStub, getter_); michael@0: } michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICGetPropCallDOMProxyNativeStub, pcOffset_); michael@0: } michael@0: }; michael@0: michael@0: class ICGetProp_CallDOMProxyNative : public ICGetPropCallDOMProxyNativeStub michael@0: { michael@0: friend class ICStubSpace; michael@0: ICGetProp_CallDOMProxyNative(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape, michael@0: BaseProxyHandler *proxyHandler, HandleShape expandoShape, michael@0: HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset) michael@0: : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyNative, stubCode, michael@0: firstMonitorStub, shape, proxyHandler, expandoShape, michael@0: holder, holderShape, getter, pcOffset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICGetProp_CallDOMProxyNative *New( michael@0: ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleShape shape, BaseProxyHandler *proxyHandler, michael@0: HandleShape expandoShape, HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, shape, michael@0: proxyHandler, expandoShape, holder, michael@0: holderShape, getter, pcOffset); michael@0: } michael@0: }; michael@0: michael@0: class ICGetProp_CallDOMProxyWithGenerationNative : public ICGetPropCallDOMProxyNativeStub michael@0: { michael@0: protected: michael@0: ExpandoAndGeneration *expandoAndGeneration_; michael@0: uint32_t generation_; michael@0: michael@0: public: michael@0: ICGetProp_CallDOMProxyWithGenerationNative(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleShape shape, BaseProxyHandler *proxyHandler, michael@0: ExpandoAndGeneration *expandoAndGeneration, michael@0: uint32_t generation, HandleShape expandoShape, michael@0: HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset) michael@0: : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyWithGenerationNative, michael@0: stubCode, firstMonitorStub, shape, proxyHandler, michael@0: expandoShape, holder, holderShape, getter, pcOffset), michael@0: expandoAndGeneration_(expandoAndGeneration), michael@0: generation_(generation) michael@0: { michael@0: } michael@0: michael@0: static inline ICGetProp_CallDOMProxyWithGenerationNative *New( michael@0: ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleShape shape, BaseProxyHandler *proxyHandler, michael@0: ExpandoAndGeneration *expandoAndGeneration, uint32_t generation, michael@0: HandleShape expandoShape, HandleObject holder, HandleShape holderShape, michael@0: HandleFunction getter, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, michael@0: shape, proxyHandler, expandoAndGeneration, michael@0: generation, expandoShape, holder, holderShape, michael@0: getter, pcOffset); michael@0: } michael@0: michael@0: void *expandoAndGeneration() const { michael@0: return expandoAndGeneration_; michael@0: } michael@0: uint32_t generation() const { michael@0: return generation_; michael@0: } michael@0: michael@0: void setGeneration(uint32_t value) { michael@0: generation_ = value; michael@0: } michael@0: michael@0: static size_t offsetOfInternalStruct() { michael@0: return offsetof(ICGetProp_CallDOMProxyWithGenerationNative, expandoAndGeneration_); michael@0: } michael@0: static size_t offsetOfGeneration() { michael@0: return offsetof(ICGetProp_CallDOMProxyWithGenerationNative, generation_); michael@0: } michael@0: }; michael@0: michael@0: class ICGetPropCallDOMProxyNativeCompiler : public ICStubCompiler { michael@0: ICStub *firstMonitorStub_; michael@0: Rooted proxy_; michael@0: RootedObject holder_; michael@0: RootedFunction getter_; michael@0: uint32_t pcOffset_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm, Address* internalStructAddr, michael@0: Address* generationAddr); michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: ICGetPropCallDOMProxyNativeCompiler(JSContext *cx, ICStub::Kind kind, michael@0: ICStub *firstMonitorStub, Handle proxy, michael@0: HandleObject holder, HandleFunction getter, michael@0: uint32_t pcOffset); michael@0: michael@0: ICStub *getStub(ICStubSpace *space); michael@0: }; michael@0: michael@0: class ICGetProp_DOMProxyShadowed : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: protected: michael@0: HeapPtrShape shape_; michael@0: BaseProxyHandler *proxyHandler_; michael@0: HeapPtrPropertyName name_; michael@0: uint32_t pcOffset_; michael@0: michael@0: ICGetProp_DOMProxyShadowed(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape, michael@0: BaseProxyHandler *proxyHandler, HandlePropertyName name, michael@0: uint32_t pcOffset); michael@0: michael@0: public: michael@0: static inline ICGetProp_DOMProxyShadowed *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, HandleShape shape, michael@0: BaseProxyHandler *proxyHandler, michael@0: HandlePropertyName name, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, shape, michael@0: proxyHandler, name, pcOffset); michael@0: } michael@0: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: HeapPtrPropertyName &name() { michael@0: return name_; michael@0: } michael@0: michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICGetProp_DOMProxyShadowed, shape_); michael@0: } michael@0: static size_t offsetOfProxyHandler() { michael@0: return offsetof(ICGetProp_DOMProxyShadowed, proxyHandler_); michael@0: } michael@0: static size_t offsetOfName() { michael@0: return offsetof(ICGetProp_DOMProxyShadowed, name_); michael@0: } michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICGetProp_DOMProxyShadowed, pcOffset_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: ICStub *firstMonitorStub_; michael@0: Rooted proxy_; michael@0: RootedPropertyName name_; michael@0: uint32_t pcOffset_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, Handle proxy, michael@0: HandlePropertyName name, uint32_t pcOffset) michael@0: : ICStubCompiler(cx, ICStub::GetProp_CallNative), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: proxy_(cx, proxy), michael@0: name_(cx, name), michael@0: pcOffset_(pcOffset) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space); michael@0: }; michael@0: }; michael@0: michael@0: class ICGetProp_ArgumentsLength : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: public: michael@0: enum Which { Normal, Strict, Magic }; michael@0: michael@0: protected: michael@0: ICGetProp_ArgumentsLength(JitCode *stubCode) michael@0: : ICStub(ICStub::GetProp_ArgumentsLength, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICGetProp_ArgumentsLength *New(ICStubSpace *space, JitCode *code) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: Which which_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(which_) << 16); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, Which which) michael@0: : ICStubCompiler(cx, ICStub::GetProp_ArgumentsLength), michael@0: which_(which) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICGetProp_ArgumentsLength::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // SetProp michael@0: // JSOP_SETPROP michael@0: // JSOP_SETNAME michael@0: // JSOP_SETGNAME michael@0: // JSOP_INITPROP michael@0: michael@0: class ICSetProp_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICSetProp_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::SetProp_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICSetProp_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0; michael@0: void noteUnoptimizableAccess() { michael@0: extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT); michael@0: } michael@0: bool hadUnoptimizableAccess() const { michael@0: return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: uint32_t returnFromIonOffset_; michael@0: uint32_t returnFromStubOffset_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: bool postGenerateStubCode(MacroAssembler &masm, Handle code); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::SetProp_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICSetProp_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Optimized SETPROP/SETGNAME/SETNAME stub. michael@0: class ICSetProp_Native : public ICUpdatedStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: // Protected to silence Clang warning. michael@0: HeapPtrTypeObject type_; michael@0: HeapPtrShape shape_; michael@0: uint32_t offset_; michael@0: michael@0: ICSetProp_Native(JitCode *stubCode, HandleTypeObject type, HandleShape shape, uint32_t offset); michael@0: michael@0: public: michael@0: static inline ICSetProp_Native *New(ICStubSpace *space, JitCode *code, HandleTypeObject type, michael@0: HandleShape shape, uint32_t offset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, type, shape, offset); michael@0: } michael@0: HeapPtrTypeObject &type() { michael@0: return type_; michael@0: } michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: static size_t offsetOfType() { michael@0: return offsetof(ICSetProp_Native, type_); michael@0: } michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICSetProp_Native, shape_); michael@0: } michael@0: static size_t offsetOfOffset() { michael@0: return offsetof(ICSetProp_Native, offset_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: RootedObject obj_; michael@0: bool isFixedSlot_; michael@0: uint32_t offset_; michael@0: michael@0: protected: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(isFixedSlot_) << 16); michael@0: } michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, HandleObject obj, bool isFixedSlot, uint32_t offset) michael@0: : ICStubCompiler(cx, ICStub::SetProp_Native), michael@0: obj_(cx, obj), michael@0: isFixedSlot_(isFixedSlot), michael@0: offset_(offset) michael@0: {} michael@0: michael@0: ICUpdatedStub *getStub(ICStubSpace *space); michael@0: }; michael@0: }; michael@0: michael@0: michael@0: template class ICSetProp_NativeAddImpl; michael@0: michael@0: class ICSetProp_NativeAdd : public ICUpdatedStub michael@0: { michael@0: public: michael@0: static const size_t MAX_PROTO_CHAIN_DEPTH = 4; michael@0: michael@0: protected: // Protected to silence Clang warning. michael@0: HeapPtrTypeObject type_; michael@0: HeapPtrShape newShape_; michael@0: uint32_t offset_; michael@0: michael@0: ICSetProp_NativeAdd(JitCode *stubCode, HandleTypeObject type, size_t protoChainDepth, michael@0: HandleShape newShape, uint32_t offset); michael@0: michael@0: public: michael@0: size_t protoChainDepth() const { michael@0: return extra_; michael@0: } michael@0: HeapPtrTypeObject &type() { michael@0: return type_; michael@0: } michael@0: HeapPtrShape &newShape() { michael@0: return newShape_; michael@0: } michael@0: michael@0: template michael@0: ICSetProp_NativeAddImpl *toImpl() { michael@0: JS_ASSERT(ProtoChainDepth == protoChainDepth()); michael@0: return static_cast *>(this); michael@0: } michael@0: michael@0: static size_t offsetOfType() { michael@0: return offsetof(ICSetProp_NativeAdd, type_); michael@0: } michael@0: static size_t offsetOfNewShape() { michael@0: return offsetof(ICSetProp_NativeAdd, newShape_); michael@0: } michael@0: static size_t offsetOfOffset() { michael@0: return offsetof(ICSetProp_NativeAdd, offset_); michael@0: } michael@0: }; michael@0: michael@0: template michael@0: class ICSetProp_NativeAddImpl : public ICSetProp_NativeAdd michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: static const size_t NumShapes = ProtoChainDepth + 1; michael@0: mozilla::Array shapes_; michael@0: michael@0: ICSetProp_NativeAddImpl(JitCode *stubCode, HandleTypeObject type, michael@0: const AutoShapeVector *shapes, michael@0: HandleShape newShape, uint32_t offset); michael@0: michael@0: public: michael@0: static inline ICSetProp_NativeAddImpl *New( michael@0: ICStubSpace *space, JitCode *code, HandleTypeObject type, michael@0: const AutoShapeVector *shapes, HandleShape newShape, uint32_t offset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate >( michael@0: code, type, shapes, newShape, offset); michael@0: } michael@0: michael@0: void traceShapes(JSTracer *trc) { michael@0: for (size_t i = 0; i < NumShapes; i++) michael@0: MarkShape(trc, &shapes_[i], "baseline-setpropnativeadd-stub-shape"); michael@0: } michael@0: michael@0: static size_t offsetOfShape(size_t idx) { michael@0: return offsetof(ICSetProp_NativeAddImpl, shapes_) + (idx * sizeof(HeapPtrShape)); michael@0: } michael@0: }; michael@0: michael@0: class ICSetPropNativeAddCompiler : public ICStubCompiler { michael@0: RootedObject obj_; michael@0: RootedShape oldShape_; michael@0: size_t protoChainDepth_; michael@0: bool isFixedSlot_; michael@0: uint32_t offset_; michael@0: michael@0: protected: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(isFixedSlot_) << 16) | michael@0: (static_cast(protoChainDepth_) << 20); michael@0: } michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: ICSetPropNativeAddCompiler(JSContext *cx, HandleObject obj, HandleShape oldShape, michael@0: size_t protoChainDepth, bool isFixedSlot, uint32_t offset); michael@0: michael@0: template michael@0: ICUpdatedStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes) michael@0: { michael@0: RootedTypeObject type(cx, obj_->getType(cx)); michael@0: if (!type) michael@0: return nullptr; michael@0: michael@0: RootedShape newShape(cx, obj_->lastProperty()); michael@0: michael@0: return ICSetProp_NativeAddImpl::New( michael@0: space, getStubCode(), type, shapes, newShape, offset_); michael@0: } michael@0: michael@0: ICUpdatedStub *getStub(ICStubSpace *space); michael@0: }; michael@0: michael@0: // Base stub for calling a setters on a native object. michael@0: class ICSetPropCallSetter : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: // Object shape (lastProperty). michael@0: HeapPtrShape shape_; michael@0: michael@0: // Holder and shape. michael@0: HeapPtrObject holder_; michael@0: HeapPtrShape holderShape_; michael@0: michael@0: // Function to call. michael@0: HeapPtrFunction setter_; michael@0: michael@0: // PC of call, for profiler michael@0: uint32_t pcOffset_; michael@0: michael@0: ICSetPropCallSetter(Kind kind, JitCode *stubCode, HandleShape shape, HandleObject holder, michael@0: HandleShape holderShape, HandleFunction setter, uint32_t pcOffset); michael@0: michael@0: public: michael@0: HeapPtrShape &shape() { michael@0: return shape_; michael@0: } michael@0: HeapPtrObject &holder() { michael@0: return holder_; michael@0: } michael@0: HeapPtrShape &holderShape() { michael@0: return holderShape_; michael@0: } michael@0: HeapPtrFunction &setter() { michael@0: return setter_; michael@0: } michael@0: michael@0: static size_t offsetOfShape() { michael@0: return offsetof(ICSetPropCallSetter, shape_); michael@0: } michael@0: static size_t offsetOfHolder() { michael@0: return offsetof(ICSetPropCallSetter, holder_); michael@0: } michael@0: static size_t offsetOfHolderShape() { michael@0: return offsetof(ICSetPropCallSetter, holderShape_); michael@0: } michael@0: static size_t offsetOfSetter() { michael@0: return offsetof(ICSetPropCallSetter, setter_); michael@0: } michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICSetPropCallSetter, pcOffset_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: RootedObject obj_; michael@0: RootedObject holder_; michael@0: RootedFunction setter_; michael@0: uint32_t pcOffset_; michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub::Kind kind, HandleObject obj, HandleObject holder, michael@0: HandleFunction setter, uint32_t pcOffset) michael@0: : ICStubCompiler(cx, kind), michael@0: obj_(cx, obj), michael@0: holder_(cx, holder), michael@0: setter_(cx, setter), michael@0: pcOffset_(pcOffset) michael@0: { michael@0: JS_ASSERT(kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for calling a scripted setter on a native object. michael@0: class ICSetProp_CallScripted : public ICSetPropCallSetter michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: ICSetProp_CallScripted(JitCode *stubCode, HandleShape shape, HandleObject holder, michael@0: HandleShape holderShape, HandleFunction setter, uint32_t pcOffset) michael@0: : ICSetPropCallSetter(SetProp_CallScripted, stubCode, shape, holder, holderShape, michael@0: setter, pcOffset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICSetProp_CallScripted *New(ICStubSpace *space, JitCode *code, michael@0: HandleShape shape, HandleObject holder, michael@0: HandleShape holderShape, HandleFunction setter, michael@0: uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, shape, holder, holderShape, setter, michael@0: pcOffset); michael@0: } michael@0: michael@0: class Compiler : public ICSetPropCallSetter::Compiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter, michael@0: uint32_t pcOffset) michael@0: : ICSetPropCallSetter::Compiler(cx, ICStub::SetProp_CallScripted, michael@0: obj, holder, setter, pcOffset) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: RootedShape shape(cx, obj_->lastProperty()); michael@0: RootedShape holderShape(cx, holder_->lastProperty()); michael@0: return ICSetProp_CallScripted::New(space, getStubCode(), shape, holder_, holderShape, michael@0: setter_, pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for calling a native setter on a native object. michael@0: class ICSetProp_CallNative : public ICSetPropCallSetter michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: ICSetProp_CallNative(JitCode *stubCode, HandleShape shape, HandleObject holder, michael@0: HandleShape holderShape, HandleFunction setter, uint32_t pcOffset) michael@0: : ICSetPropCallSetter(SetProp_CallNative, stubCode, shape, holder, holderShape, michael@0: setter, pcOffset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICSetProp_CallNative *New(ICStubSpace *space, JitCode *code, michael@0: HandleShape shape, HandleObject holder, michael@0: HandleShape holderShape, HandleFunction setter, michael@0: uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, shape, holder, holderShape, setter, michael@0: pcOffset); michael@0: } michael@0: michael@0: class Compiler : public ICSetPropCallSetter::Compiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter, michael@0: uint32_t pcOffset) michael@0: : ICSetPropCallSetter::Compiler(cx, ICStub::SetProp_CallNative, michael@0: obj, holder, setter, pcOffset) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: RootedShape shape(cx, obj_->lastProperty()); michael@0: RootedShape holderShape(cx, holder_->lastProperty()); michael@0: return ICSetProp_CallNative::New(space, getStubCode(), shape, holder_, holderShape, michael@0: setter_, pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Call michael@0: // JSOP_CALL michael@0: // JSOP_FUNAPPLY michael@0: // JSOP_FUNCALL michael@0: // JSOP_NEW michael@0: michael@0: class ICCallStubCompiler : public ICStubCompiler michael@0: { michael@0: protected: michael@0: ICCallStubCompiler(JSContext *cx, ICStub::Kind kind) michael@0: : ICStubCompiler(cx, kind) michael@0: { } michael@0: michael@0: enum FunApplyThing { michael@0: FunApply_MagicArgs, michael@0: FunApply_Array michael@0: }; michael@0: michael@0: void pushCallArguments(MacroAssembler &masm, GeneralRegisterSet regs, Register argcReg); michael@0: Register guardFunApply(MacroAssembler &masm, GeneralRegisterSet regs, Register argcReg, michael@0: bool checkNative, FunApplyThing applyThing, Label *failure); michael@0: void pushCallerArguments(MacroAssembler &masm, GeneralRegisterSet regs); michael@0: void pushArrayArguments(MacroAssembler &masm, Address arrayVal, GeneralRegisterSet regs); michael@0: }; michael@0: michael@0: class ICCall_Fallback : public ICMonitoredFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: public: michael@0: static const unsigned CONSTRUCTING_FLAG = 0x0001; michael@0: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 16; michael@0: static const uint32_t MAX_SCRIPTED_STUBS = 7; michael@0: static const uint32_t MAX_NATIVE_STUBS = 7; michael@0: private: michael@0: michael@0: ICCall_Fallback(JitCode *stubCode, bool isConstructing) michael@0: : ICMonitoredFallbackStub(ICStub::Call_Fallback, stubCode) michael@0: { michael@0: extra_ = 0; michael@0: if (isConstructing) michael@0: extra_ |= CONSTRUCTING_FLAG; michael@0: } michael@0: michael@0: public: michael@0: michael@0: static inline ICCall_Fallback *New(ICStubSpace *space, JitCode *code, bool isConstructing) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, isConstructing); michael@0: } michael@0: michael@0: bool isConstructing() const { michael@0: return extra_ & CONSTRUCTING_FLAG; michael@0: } michael@0: michael@0: unsigned scriptedStubCount() const { michael@0: return numStubsWithKind(Call_Scripted); michael@0: } michael@0: bool scriptedStubsAreGeneralized() const { michael@0: return hasStub(Call_AnyScripted); michael@0: } michael@0: michael@0: unsigned nativeStubCount() const { michael@0: return numStubsWithKind(Call_Native); michael@0: } michael@0: bool nativeStubsAreGeneralized() const { michael@0: // Return hasStub(Call_AnyNative) after Call_AnyNative stub is added. michael@0: return false; michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICCallStubCompiler { michael@0: protected: michael@0: bool isConstructing_; michael@0: uint32_t returnFromIonOffset_; michael@0: uint32_t returnFromStubOffset_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: bool postGenerateStubCode(MacroAssembler &masm, Handle code); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, bool isConstructing) michael@0: : ICCallStubCompiler(cx, ICStub::Call_Fallback), michael@0: isConstructing_(isConstructing) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: ICCall_Fallback *stub = ICCall_Fallback::New(space, getStubCode(), isConstructing_); michael@0: if (!stub || !stub->initMonitoringChain(cx, space)) michael@0: return nullptr; michael@0: return stub; michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCall_Scripted : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: HeapPtrScript calleeScript_; michael@0: HeapPtrObject templateObject_; michael@0: uint32_t pcOffset_; michael@0: michael@0: ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleScript calleeScript, HandleObject templateObject, michael@0: uint32_t pcOffset); michael@0: michael@0: public: michael@0: static inline ICCall_Scripted *New( michael@0: ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleScript calleeScript, HandleObject templateObject, michael@0: uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, michael@0: calleeScript, templateObject, pcOffset); michael@0: } michael@0: michael@0: HeapPtrScript &calleeScript() { michael@0: return calleeScript_; michael@0: } michael@0: HeapPtrObject &templateObject() { michael@0: return templateObject_; michael@0: } michael@0: michael@0: static size_t offsetOfCalleeScript() { michael@0: return offsetof(ICCall_Scripted, calleeScript_); michael@0: } michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICCall_Scripted, pcOffset_); michael@0: } michael@0: }; michael@0: michael@0: class ICCall_AnyScripted : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: uint32_t pcOffset_; michael@0: michael@0: ICCall_AnyScripted(JitCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: : ICMonitoredStub(ICStub::Call_AnyScripted, stubCode, firstMonitorStub), michael@0: pcOffset_(pcOffset) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICCall_AnyScripted *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, pcOffset); michael@0: } michael@0: michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICCall_AnyScripted, pcOffset_); michael@0: } michael@0: }; michael@0: michael@0: // Compiler for Call_Scripted and Call_AnyScripted stubs. michael@0: class ICCallScriptedCompiler : public ICCallStubCompiler { michael@0: protected: michael@0: ICStub *firstMonitorStub_; michael@0: bool isConstructing_; michael@0: RootedScript calleeScript_; michael@0: RootedObject templateObject_; michael@0: uint32_t pcOffset_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(isConstructing_) << 16); michael@0: } michael@0: michael@0: public: michael@0: ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub, michael@0: HandleScript calleeScript, HandleObject templateObject, michael@0: bool isConstructing, uint32_t pcOffset) michael@0: : ICCallStubCompiler(cx, ICStub::Call_Scripted), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: isConstructing_(isConstructing), michael@0: calleeScript_(cx, calleeScript), michael@0: templateObject_(cx, templateObject), michael@0: pcOffset_(pcOffset) michael@0: { } michael@0: michael@0: ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub, bool isConstructing, michael@0: uint32_t pcOffset) michael@0: : ICCallStubCompiler(cx, ICStub::Call_AnyScripted), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: isConstructing_(isConstructing), michael@0: calleeScript_(cx, nullptr), michael@0: templateObject_(cx, nullptr), michael@0: pcOffset_(pcOffset) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: if (calleeScript_) { michael@0: return ICCall_Scripted::New(space, getStubCode(), firstMonitorStub_, michael@0: calleeScript_, templateObject_, michael@0: pcOffset_); michael@0: } michael@0: return ICCall_AnyScripted::New(space, getStubCode(), firstMonitorStub_, pcOffset_); michael@0: } michael@0: }; michael@0: michael@0: class ICCall_Native : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: HeapPtrFunction callee_; michael@0: HeapPtrObject templateObject_; michael@0: uint32_t pcOffset_; michael@0: michael@0: #ifdef JS_ARM_SIMULATOR michael@0: void *native_; michael@0: #endif michael@0: michael@0: ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub, michael@0: HandleFunction callee, HandleObject templateObject, michael@0: uint32_t pcOffset); michael@0: michael@0: public: michael@0: static inline ICCall_Native *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub, michael@0: HandleFunction callee, HandleObject templateObject, michael@0: uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, michael@0: callee, templateObject, pcOffset); michael@0: } michael@0: michael@0: HeapPtrFunction &callee() { michael@0: return callee_; michael@0: } michael@0: HeapPtrObject &templateObject() { michael@0: return templateObject_; michael@0: } michael@0: michael@0: static size_t offsetOfCallee() { michael@0: return offsetof(ICCall_Native, callee_); michael@0: } michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICCall_Native, pcOffset_); michael@0: } michael@0: michael@0: #ifdef JS_ARM_SIMULATOR michael@0: static size_t offsetOfNative() { michael@0: return offsetof(ICCall_Native, native_); michael@0: } michael@0: #endif michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICCallStubCompiler { michael@0: protected: michael@0: ICStub *firstMonitorStub_; michael@0: bool isConstructing_; michael@0: RootedFunction callee_; michael@0: RootedObject templateObject_; michael@0: uint32_t pcOffset_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(isConstructing_) << 16); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, michael@0: HandleFunction callee, HandleObject templateObject, michael@0: bool isConstructing, uint32_t pcOffset) michael@0: : ICCallStubCompiler(cx, ICStub::Call_Native), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: isConstructing_(isConstructing), michael@0: callee_(cx, callee), michael@0: templateObject_(cx, templateObject), michael@0: pcOffset_(pcOffset) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCall_Native::New(space, getStubCode(), firstMonitorStub_, michael@0: callee_, templateObject_, pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCall_ScriptedApplyArray : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: public: michael@0: // The maximum length of an inlineable funcall array. michael@0: // Keep this small to avoid controllable stack overflows by attackers passing large michael@0: // arrays to fun.apply. michael@0: static const uint32_t MAX_ARGS_ARRAY_LENGTH = 16; michael@0: michael@0: protected: michael@0: uint32_t pcOffset_; michael@0: michael@0: ICCall_ScriptedApplyArray(JitCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: : ICMonitoredStub(ICStub::Call_ScriptedApplyArray, stubCode, firstMonitorStub), michael@0: pcOffset_(pcOffset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICCall_ScriptedApplyArray *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, pcOffset); michael@0: } michael@0: michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICCall_ScriptedApplyArray, pcOffset_); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICCallStubCompiler { michael@0: protected: michael@0: ICStub *firstMonitorStub_; michael@0: uint32_t pcOffset_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: : ICCallStubCompiler(cx, ICStub::Call_ScriptedApplyArray), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: pcOffset_(pcOffset) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCall_ScriptedApplyArray::New(space, getStubCode(), firstMonitorStub_, michael@0: pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICCall_ScriptedApplyArguments : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: uint32_t pcOffset_; michael@0: michael@0: ICCall_ScriptedApplyArguments(JitCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: : ICMonitoredStub(ICStub::Call_ScriptedApplyArguments, stubCode, firstMonitorStub), michael@0: pcOffset_(pcOffset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICCall_ScriptedApplyArguments *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, pcOffset); michael@0: } michael@0: michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICCall_ScriptedApplyArguments, pcOffset_); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICCallStubCompiler { michael@0: protected: michael@0: ICStub *firstMonitorStub_; michael@0: uint32_t pcOffset_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: : ICCallStubCompiler(cx, ICStub::Call_ScriptedApplyArguments), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: pcOffset_(pcOffset) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCall_ScriptedApplyArguments::New(space, getStubCode(), firstMonitorStub_, michael@0: pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Handles calls of the form |fun.call(...)| where fun is a scripted function. michael@0: class ICCall_ScriptedFunCall : public ICMonitoredStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: uint32_t pcOffset_; michael@0: michael@0: ICCall_ScriptedFunCall(JitCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: : ICMonitoredStub(ICStub::Call_ScriptedFunCall, stubCode, firstMonitorStub), michael@0: pcOffset_(pcOffset) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICCall_ScriptedFunCall *New(ICStubSpace *space, JitCode *code, michael@0: ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, firstMonitorStub, pcOffset); michael@0: } michael@0: michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICCall_ScriptedFunCall, pcOffset_); michael@0: } michael@0: michael@0: // Compiler for this stub kind. michael@0: class Compiler : public ICCallStubCompiler { michael@0: protected: michael@0: ICStub *firstMonitorStub_; michael@0: uint32_t pcOffset_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, ICStub *firstMonitorStub, uint32_t pcOffset) michael@0: : ICCallStubCompiler(cx, ICStub::Call_ScriptedFunCall), michael@0: firstMonitorStub_(firstMonitorStub), michael@0: pcOffset_(pcOffset) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICCall_ScriptedFunCall::New(space, getStubCode(), firstMonitorStub_, michael@0: pcOffset_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for performing a TableSwitch, updating the IC's return address to jump michael@0: // to whatever point the switch is branching to. michael@0: class ICTableSwitch : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: // Protected to silence Clang warning. michael@0: void **table_; michael@0: int32_t min_; michael@0: int32_t length_; michael@0: void *defaultTarget_; michael@0: michael@0: ICTableSwitch(JitCode *stubCode, void **table, michael@0: int32_t min, int32_t length, void *defaultTarget) michael@0: : ICStub(TableSwitch, stubCode), table_(table), michael@0: min_(min), length_(length), defaultTarget_(defaultTarget) michael@0: {} michael@0: michael@0: public: michael@0: static inline ICTableSwitch *New(ICStubSpace *space, JitCode *code, void **table, michael@0: int32_t min, int32_t length, void *defaultTarget) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, table, min, length, defaultTarget); michael@0: } michael@0: michael@0: void fixupJumpTable(JSScript *script, BaselineScript *baseline); michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: jsbytecode *pc_; michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, jsbytecode *pc) michael@0: : ICStubCompiler(cx, ICStub::TableSwitch), pc_(pc) michael@0: {} michael@0: michael@0: ICStub *getStub(ICStubSpace *space); michael@0: }; michael@0: }; michael@0: michael@0: // IC for constructing an iterator from an input value. michael@0: class ICIteratorNew_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICIteratorNew_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::IteratorNew_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICIteratorNew_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::IteratorNew_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICIteratorNew_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // IC for testing if there are more values in an iterator. michael@0: class ICIteratorMore_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICIteratorMore_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::IteratorMore_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICIteratorMore_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::IteratorMore_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICIteratorMore_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // IC for testing if there are more values in a native iterator. michael@0: class ICIteratorMore_Native : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICIteratorMore_Native(JitCode *stubCode) michael@0: : ICStub(ICStub::IteratorMore_Native, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICIteratorMore_Native *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::IteratorMore_Native) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICIteratorMore_Native::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // IC for getting the next value in an iterator. michael@0: class ICIteratorNext_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICIteratorNext_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::IteratorNext_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICIteratorNext_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: void setHasNonStringResult() { michael@0: JS_ASSERT(extra_ == 0); michael@0: extra_ = 1; michael@0: } michael@0: bool hasNonStringResult() const { michael@0: return extra_; michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::IteratorNext_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICIteratorNext_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // IC for getting the next value in a native iterator. michael@0: class ICIteratorNext_Native : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICIteratorNext_Native(JitCode *stubCode) michael@0: : ICStub(ICStub::IteratorNext_Native, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICIteratorNext_Native *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::IteratorNext_Native) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICIteratorNext_Native::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // IC for closing an iterator. michael@0: class ICIteratorClose_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICIteratorClose_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::IteratorClose_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICIteratorClose_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::IteratorClose_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICIteratorClose_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // InstanceOf michael@0: // JSOP_INSTANCEOF michael@0: class ICInstanceOf_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICInstanceOf_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::InstanceOf_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICInstanceOf_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::InstanceOf_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICInstanceOf_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // TypeOf michael@0: // JSOP_TYPEOF michael@0: // JSOP_TYPEOFEXPR michael@0: class ICTypeOf_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICTypeOf_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::TypeOf_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static inline ICTypeOf_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::TypeOf_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICTypeOf_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICTypeOf_Typed : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICTypeOf_Typed(JitCode *stubCode, JSType type) michael@0: : ICFallbackStub(ICStub::TypeOf_Typed, stubCode) michael@0: { michael@0: extra_ = uint16_t(type); michael@0: JS_ASSERT(JSType(extra_) == type); michael@0: } michael@0: michael@0: public: michael@0: static inline ICTypeOf_Typed *New(ICStubSpace *space, JitCode *code, JSType type) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, type); michael@0: } michael@0: michael@0: JSType type() const { michael@0: return JSType(extra_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: JSType type_; michael@0: RootedString typeString_; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: virtual int32_t getKey() const { michael@0: return static_cast(kind) | (static_cast(type_) << 16); michael@0: } michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSType type, HandleString string) michael@0: : ICStubCompiler(cx, ICStub::TypeOf_Typed), michael@0: type_(type), michael@0: typeString_(cx, string) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICTypeOf_Typed::New(space, getStubCode(), type_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: class ICRest_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: HeapPtrObject templateObject_; michael@0: michael@0: ICRest_Fallback(JitCode *stubCode, JSObject *templateObject) michael@0: : ICFallbackStub(ICStub::Rest_Fallback, stubCode), templateObject_(templateObject) michael@0: { } michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICRest_Fallback *New(ICStubSpace *space, JitCode *code, michael@0: JSObject *templateObject) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, templateObject); michael@0: } michael@0: michael@0: HeapPtrObject &templateObject() { michael@0: return templateObject_; michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: RootedObject templateObject; michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, JSObject *templateObject) michael@0: : ICStubCompiler(cx, ICStub::Rest_Fallback), michael@0: templateObject(cx, templateObject) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICRest_Fallback::New(space, getStubCode(), templateObject); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Stub for JSOP_RETSUB ("returning" from a |finally| block). michael@0: class ICRetSub_Fallback : public ICFallbackStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: ICRetSub_Fallback(JitCode *stubCode) michael@0: : ICFallbackStub(ICStub::RetSub_Fallback, stubCode) michael@0: { } michael@0: michael@0: public: michael@0: static const uint32_t MAX_OPTIMIZED_STUBS = 8; michael@0: michael@0: static inline ICRetSub_Fallback *New(ICStubSpace *space, JitCode *code) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: protected: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx) michael@0: : ICStubCompiler(cx, ICStub::RetSub_Fallback) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICRetSub_Fallback::New(space, getStubCode()); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: // Optimized JSOP_RETSUB stub. Every stub maps a single pc offset to its michael@0: // native code address. michael@0: class ICRetSub_Resume : public ICStub michael@0: { michael@0: friend class ICStubSpace; michael@0: michael@0: protected: michael@0: uint32_t pcOffset_; michael@0: uint8_t *addr_; michael@0: michael@0: ICRetSub_Resume(JitCode *stubCode, uint32_t pcOffset, uint8_t *addr) michael@0: : ICStub(ICStub::RetSub_Resume, stubCode), michael@0: pcOffset_(pcOffset), michael@0: addr_(addr) michael@0: { } michael@0: michael@0: public: michael@0: static ICRetSub_Resume *New(ICStubSpace *space, JitCode *code, uint32_t pcOffset, michael@0: uint8_t *addr) { michael@0: if (!code) michael@0: return nullptr; michael@0: return space->allocate(code, pcOffset, addr); michael@0: } michael@0: michael@0: static size_t offsetOfPCOffset() { michael@0: return offsetof(ICRetSub_Resume, pcOffset_); michael@0: } michael@0: static size_t offsetOfAddr() { michael@0: return offsetof(ICRetSub_Resume, addr_); michael@0: } michael@0: michael@0: class Compiler : public ICStubCompiler { michael@0: uint32_t pcOffset_; michael@0: uint8_t *addr_; michael@0: michael@0: bool generateStubCode(MacroAssembler &masm); michael@0: michael@0: public: michael@0: Compiler(JSContext *cx, uint32_t pcOffset, uint8_t *addr) michael@0: : ICStubCompiler(cx, ICStub::RetSub_Resume), michael@0: pcOffset_(pcOffset), michael@0: addr_(addr) michael@0: { } michael@0: michael@0: ICStub *getStub(ICStubSpace *space) { michael@0: return ICRetSub_Resume::New(space, getStubCode(), pcOffset_, addr_); michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif // JS_ION michael@0: michael@0: #endif /* jit_BaselineIC_h */