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