summaryrefslogtreecommitdiffstats
path: root/js/src/jit/SharedIC.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/SharedIC.h')
-rw-r--r--js/src/jit/SharedIC.h3120
1 files changed, 3120 insertions, 0 deletions
diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h
new file mode 100644
index 000000000..42198c890
--- /dev/null
+++ b/js/src/jit/SharedIC.h
@@ -0,0 +1,3120 @@
+/* -*- 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_SharedIC_h
+#define jit_SharedIC_h
+
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsgc.h"
+
+#include "jit/BaselineICList.h"
+#include "jit/BaselineJIT.h"
+#include "jit/MacroAssembler.h"
+#include "jit/SharedICList.h"
+#include "jit/SharedICRegisters.h"
+#include "vm/ReceiverGuard.h"
+#include "vm/TypedArrayCommon.h"
+
+namespace js {
+namespace jit {
+
+class AutoShapeVector;
+
+//
+// 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. warm-up counters), 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 ObjectGroup to update. New input types must be tracked on a group-to-
+// group 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;
+
+#define FORWARD_DECLARE_STUBS(kindName) class IC##kindName;
+ IC_BASELINE_STUB_KIND_LIST(FORWARD_DECLARE_STUBS)
+ IC_SHARED_STUB_KIND_LIST(FORWARD_DECLARE_STUBS)
+#undef FORWARD_DECLARE_STUBS
+
+#ifdef JS_JITSPEW
+void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...)
+ MOZ_FORMAT_PRINTF(3, 4);
+void TypeFallbackICSpew(JSContext* cx, ICTypeMonitor_Fallback* stub, const char* fmt, ...)
+ MOZ_FORMAT_PRINTF(3, 4);
+#else
+#define FallbackICSpew(...)
+#define TypeFallbackICSpew(...)
+#endif
+
+//
+// An entry in the JIT IC descriptor table.
+//
+class ICEntry
+{
+ private:
+ // A pointer to the shared IC stub for this instruction.
+ ICStub* firstStub_;
+
+ // 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_ : 28;
+
+ public:
+ enum Kind {
+ // A for-op IC entry.
+ Kind_Op = 0,
+
+ // A non-op IC entry.
+ Kind_NonOp,
+
+ // A fake IC entry for returning from a callVM for an op.
+ Kind_CallVM,
+
+ // A fake IC entry for returning from a callVM not for an op (e.g., in
+ // the prologue).
+ Kind_NonOpCallVM,
+
+ // A fake IC entry for returning from a callVM to after the
+ // warmup counter.
+ Kind_WarmupCounter,
+
+ // A fake IC entry for returning from a callVM to the interrupt
+ // handler via the over-recursion check on function entry.
+ Kind_StackCheck,
+
+ // As above, but for the early check. See emitStackCheck.
+ Kind_EarlyStackCheck,
+
+ // A fake IC entry for returning from DebugTrapHandler.
+ Kind_DebugTrap,
+
+ // A fake IC entry for returning from a callVM to
+ // Debug{Prologue,Epilogue}.
+ Kind_DebugPrologue,
+ Kind_DebugEpilogue,
+
+ Kind_Invalid
+ };
+
+ private:
+ // What this IC is for.
+ Kind kind_ : 4;
+
+ // Set the kind and asserts that it's sane.
+ void setKind(Kind kind) {
+ MOZ_ASSERT(kind < Kind_Invalid);
+ kind_ = kind;
+ MOZ_ASSERT(this->kind() == kind);
+ }
+
+ public:
+ ICEntry(uint32_t pcOffset, Kind kind)
+ : firstStub_(nullptr), returnOffset_(), pcOffset_(pcOffset)
+ {
+ // The offset must fit in at least 28 bits, since we shave off 4 for
+ // the Kind enum.
+ MOZ_ASSERT(pcOffset_ == pcOffset);
+ JS_STATIC_ASSERT(BaselineScript::MAX_JSSCRIPT_LENGTH <= (1u << 28) - 1);
+ MOZ_ASSERT(pcOffset <= BaselineScript::MAX_JSSCRIPT_LENGTH);
+ setKind(kind);
+ }
+
+ CodeOffset returnOffset() const {
+ return CodeOffset(returnOffset_);
+ }
+
+ void setReturnOffset(CodeOffset offset) {
+ MOZ_ASSERT(offset.offset() <= (size_t) UINT32_MAX);
+ returnOffset_ = (uint32_t) offset.offset();
+ }
+
+ uint32_t pcOffset() const {
+ return pcOffset_;
+ }
+
+ jsbytecode* pc(JSScript* script) const {
+ return script->offsetToPC(pcOffset_);
+ }
+
+ Kind kind() const {
+ // MSVC compiles enums as signed.
+ return Kind(kind_ & 0xf);
+ }
+ bool isForOp() const {
+ return kind() == Kind_Op;
+ }
+
+ void setFakeKind(Kind kind) {
+ MOZ_ASSERT(kind != Kind_Op && kind != Kind_NonOp);
+ setKind(kind);
+ }
+
+ bool hasStub() const {
+ return firstStub_ != nullptr;
+ }
+ ICStub* firstStub() const {
+ MOZ_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_;
+ }
+
+ protected:
+ void traceEntry(JSTracer* trc);
+};
+
+class BaselineICEntry : public ICEntry
+{
+ public:
+ BaselineICEntry(uint32_t pcOffset, Kind kind)
+ : ICEntry(pcOffset, kind)
+ { }
+
+ void trace(JSTracer* trc);
+};
+
+class IonICEntry : public ICEntry
+{
+ JSScript* script_;
+
+ public:
+ IonICEntry(uint32_t pcOffset, Kind kind, JSScript* script)
+ : ICEntry(pcOffset, kind),
+ script_(script)
+ { }
+
+ JSScript* script() {
+ return script_;
+ }
+
+ void trace(JSTracer* trc);
+};
+
+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 nullptr-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:
+ explicit ICStubConstIterator(ICStub* currentStub) : currentStub_(currentStub) {}
+
+ static ICStubConstIterator StartingAt(ICStub* stub) {
+ return ICStubConstIterator(stub);
+ }
+ static ICStubConstIterator End(ICStub* stub) {
+ return ICStubConstIterator(nullptr);
+ }
+
+ 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 {
+ MOZ_ASSERT(currentStub_);
+ return currentStub_;
+ }
+
+ ICStub* operator ->() const {
+ MOZ_ASSERT(currentStub_);
+ return currentStub_;
+ }
+
+ bool atEnd() const {
+ return currentStub_ == nullptr;
+ }
+};
+
+// 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_;
+
+ explicit ICStubIterator(ICFallbackStub* fallbackStub, bool end=false);
+ public:
+
+ bool operator ==(const ICStubIterator& other) const {
+ // == should only ever be called on stubs from the same chain.
+ MOZ_ASSERT(icEntry_ == other.icEntry_);
+ MOZ_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(JSContext* cx);
+};
+
+//
+// Base class for all IC stubs.
+//
+class ICStub
+{
+ friend class ICFallbackStub;
+
+ public:
+ enum Kind {
+ INVALID = 0,
+#define DEF_ENUM_KIND(kindName) kindName,
+ IC_BASELINE_STUB_KIND_LIST(DEF_ENUM_KIND)
+ IC_SHARED_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_BASELINE_STUB_KIND_LIST(DEF_KIND_STR)
+ IC_SHARED_STUB_KIND_LIST(DEF_KIND_STR)
+#undef DEF_KIND_STR
+ default:
+ MOZ_CRASH("Invalid kind.");
+ }
+ }
+
+ enum Trait {
+ Regular = 0x0,
+ Fallback = 0x1,
+ Monitored = 0x2,
+ MonitoredFallback = 0x3,
+ Updated = 0x4
+ };
+
+ void markCode(JSTracer* trc, const char* name);
+ void updateCode(JitCode* stubCode);
+ void trace(JSTracer* trc);
+
+ template <typename T, typename... Args>
+ static T* New(JSContext* cx, ICStubSpace* space, JitCode* code, Args&&... args) {
+ if (!code)
+ return nullptr;
+ T* result = space->allocate<T>(code, mozilla::Forward<Args>(args)...);
+ if (!result)
+ ReportOutOfMemory(cx);
+ return result;
+ }
+
+ protected:
+ // 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_;
+
+ // A 16-bit field usable by subtypes of ICStub for subtype-specific small-info
+ uint16_t extra_;
+
+ // The kind of the stub.
+ // High bit is 'isFallback' flag.
+ // Second high bit is 'isMonitored' flag.
+ Trait trait_ : 3;
+ Kind kind_ : 13;
+
+ inline ICStub(Kind kind, JitCode* stubCode)
+ : stubCode_(stubCode->raw()),
+ next_(nullptr),
+ extra_(0),
+ trait_(Regular),
+ kind_(kind)
+ {
+ MOZ_ASSERT(stubCode != nullptr);
+ }
+
+ inline ICStub(Kind kind, Trait trait, JitCode* stubCode)
+ : stubCode_(stubCode->raw()),
+ next_(nullptr),
+ extra_(0),
+ trait_(trait),
+ kind_(kind)
+ {
+ MOZ_ASSERT(stubCode != nullptr);
+ }
+
+ 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 {
+ MOZ_ASSERT(isFallback());
+ return reinterpret_cast<const ICFallbackStub*>(this);
+ }
+
+ inline ICFallbackStub* toFallbackStub() {
+ MOZ_ASSERT(isFallback());
+ return reinterpret_cast<ICFallbackStub*>(this);
+ }
+
+ inline const ICMonitoredStub* toMonitoredStub() const {
+ MOZ_ASSERT(isMonitored());
+ return reinterpret_cast<const ICMonitoredStub*>(this);
+ }
+
+ inline ICMonitoredStub* toMonitoredStub() {
+ MOZ_ASSERT(isMonitored());
+ return reinterpret_cast<ICMonitoredStub*>(this);
+ }
+
+ inline const ICMonitoredFallbackStub* toMonitoredFallbackStub() const {
+ MOZ_ASSERT(isMonitoredFallback());
+ return reinterpret_cast<const ICMonitoredFallbackStub*>(this);
+ }
+
+ inline ICMonitoredFallbackStub* toMonitoredFallbackStub() {
+ MOZ_ASSERT(isMonitoredFallback());
+ return reinterpret_cast<ICMonitoredFallbackStub*>(this);
+ }
+
+ inline const ICUpdatedStub* toUpdatedStub() const {
+ MOZ_ASSERT(isUpdated());
+ return reinterpret_cast<const ICUpdatedStub*>(this);
+ }
+
+ inline ICUpdatedStub* toUpdatedStub() {
+ MOZ_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 { \
+ MOZ_ASSERT(is##kindName()); \
+ return reinterpret_cast<const IC##kindName*>(this); \
+ } \
+ inline IC##kindName* to##kindName() { \
+ MOZ_ASSERT(is##kindName()); \
+ return reinterpret_cast<IC##kindName*>(this); \
+ }
+ IC_BASELINE_STUB_KIND_LIST(KIND_METHODS)
+ IC_SHARED_STUB_KIND_LIST(KIND_METHODS)
+#undef KIND_METHODS
+
+ inline ICStub* next() const {
+ return next_;
+ }
+
+ inline bool hasNext() const {
+ return next_ != nullptr;
+ }
+
+ inline void setNext(ICStub* stub) {
+ // Note: next_ only needs to be changed under the compilation lock for
+ // non-type-monitor/update ICs.
+ next_ = stub;
+ }
+
+ inline ICStub** addressOfNext() {
+ return &next_;
+ }
+
+ inline JitCode* jitCode() {
+ return JitCode::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_;
+ MOZ_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) {
+ MOZ_ASSERT(IsValidKind(kind));
+ switch (kind) {
+ case Call_Fallback:
+ case Call_Scripted:
+ case Call_AnyScripted:
+ case Call_Native:
+ case Call_ClassHook:
+ case Call_ScriptedApplyArray:
+ case Call_ScriptedApplyArguments:
+ case Call_ScriptedFunCall:
+ case Call_StringSplit:
+ case WarmUpCounter_Fallback:
+ case GetElem_NativeSlotName:
+ case GetElem_NativeSlotSymbol:
+ case GetElem_NativePrototypeSlotName:
+ case GetElem_NativePrototypeSlotSymbol:
+ case GetElem_NativePrototypeCallNativeName:
+ case GetElem_NativePrototypeCallNativeSymbol:
+ case GetElem_NativePrototypeCallScriptedName:
+ case GetElem_NativePrototypeCallScriptedSymbol:
+ case GetElem_UnboxedPropertyName:
+ case GetProp_CallScripted:
+ case GetProp_CallNative:
+ case GetProp_CallNativeGlobal:
+ case GetProp_CallDOMProxyNative:
+ case GetProp_CallDOMProxyWithGenerationNative:
+ case GetProp_DOMProxyShadowed:
+ case GetProp_Generic:
+ case SetProp_CallScripted:
+ case SetProp_CallNative:
+ case RetSub_Fallback:
+ // These two fallback stubs don't actually make non-tail calls,
+ // but the fallback code for the bailout path needs to pop the stub frame
+ // pushed during the bailout.
+ case GetProp_Fallback:
+ case SetProp_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 {
+ MOZ_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_ : 31;
+ uint32_t invalid_ : 1;
+
+ // 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 added, it'll point to the current
+ // last stub's "next_" field.
+ ICStub** lastStubPtrAddr_;
+
+ ICFallbackStub(Kind kind, JitCode* stubCode)
+ : ICStub(kind, ICStub::Fallback, stubCode),
+ icEntry_(nullptr),
+ numOptimizedStubs_(0),
+ invalid_(false),
+ lastStubPtrAddr_(nullptr) {}
+
+ ICFallbackStub(Kind kind, Trait trait, JitCode* stubCode)
+ : ICStub(kind, trait, stubCode),
+ icEntry_(nullptr),
+ numOptimizedStubs_(0),
+ invalid_(false),
+ lastStubPtrAddr_(nullptr)
+ {
+ MOZ_ASSERT(trait == ICStub::Fallback ||
+ trait == ICStub::MonitoredFallback);
+ }
+
+ public:
+ inline ICEntry* icEntry() const {
+ return icEntry_;
+ }
+
+ inline size_t numOptimizedStubs() const {
+ return (size_t) numOptimizedStubs_;
+ }
+
+ void setInvalid() {
+ invalid_ = 1;
+ }
+
+ bool invalid() const {
+ return invalid_;
+ }
+
+ // 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 JitScript is created. This method
+ // allows these fields to be fixed up at that point.
+ void fixupICEntry(ICEntry* icEntry) {
+ MOZ_ASSERT(icEntry_ == nullptr);
+ MOZ_ASSERT(lastStubPtrAddr_ == nullptr);
+ icEntry_ = icEntry;
+ lastStubPtrAddr_ = icEntry_->addressOfFirstStub();
+ }
+
+ // Add a new stub to the IC chain terminated by this fallback stub.
+ void addNewStub(ICStub* stub) {
+ MOZ_ASSERT(!invalid());
+ MOZ_ASSERT(*lastStubPtrAddr_ == this);
+ MOZ_ASSERT(stub->next() == nullptr);
+ 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, JitCode* 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.
+ MOZ_ASSERT(firstMonitorStub_ && firstMonitorStub_->isTypeMonitor_Fallback());
+ firstMonitorStub_ = monitorStub;
+ }
+ inline void resetFirstMonitorStub(ICStub* monitorFallback) {
+ MOZ_ASSERT(monitorFallback->isTypeMonitor_Fallback());
+ firstMonitorStub_ = monitorFallback;
+ }
+ inline ICStub* firstMonitorStub() const {
+ return firstMonitorStub_;
+ }
+
+ static inline size_t offsetOfFirstMonitorStub() {
+ return offsetof(ICMonitoredStub, firstMonitorStub_);
+ }
+};
+
+class ICCacheIR_Monitored : public ICMonitoredStub
+{
+ CacheIRStubInfo* stubInfo_;
+
+ public:
+ ICCacheIR_Monitored(JitCode* stubCode, ICStub* firstMonitorStub, CacheIRStubInfo* stubInfo)
+ : ICMonitoredStub(ICStub::CacheIR_Monitored, stubCode, firstMonitorStub),
+ stubInfo_(stubInfo)
+ {}
+
+ void notePreliminaryObject() {
+ extra_ = 1;
+ }
+ bool hasPreliminaryObject() const {
+ return extra_;
+ }
+
+ const CacheIRStubInfo* stubInfo() const {
+ return stubInfo_;
+ }
+};
+
+// 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, JitCode* stubCode)
+ : ICStub(kind, ICStub::Updated, stubCode),
+ firstUpdateStub_(nullptr),
+ numOptimizedStubs_(0)
+ {}
+
+ public:
+ MOZ_MUST_USE bool initUpdatingChain(JSContext* cx, ICStubSpace* space);
+
+ MOZ_MUST_USE 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_;
+ MOZ_ASSERT(iter->next() != nullptr);
+ while (!iter->next()->isTypeUpdate_Fallback())
+ iter = iter->next();
+ MOZ_ASSERT(iter->next()->next() == nullptr);
+ 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;
+
+ public:
+ enum class Engine {
+ Baseline = 0,
+ IonMonkey
+ };
+
+ protected:
+ JSContext* cx;
+ ICStub::Kind kind;
+ Engine engine_;
+ bool inStubFrame_;
+
+#ifdef DEBUG
+ bool entersStubFrame_;
+ uint32_t framePushedAtEnterStubFrame_;
+#endif
+
+ // By default the stubcode key is just the kind.
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1);
+ }
+
+ virtual MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) = 0;
+ virtual void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> genCode) {}
+
+ JitCode* getStubCode();
+
+ ICStubCompiler(JSContext* cx, ICStub::Kind kind, Engine engine)
+ : suppressGC(cx), cx(cx), kind(kind), engine_(engine), inStubFrame_(false)
+#ifdef DEBUG
+ , entersStubFrame_(false), framePushedAtEnterStubFrame_(0)
+#endif
+ {}
+
+ // Push a payload specialized per compiler needed to execute stubs.
+ void PushStubPayload(MacroAssembler& masm, Register scratch);
+ void pushStubPayload(MacroAssembler& masm, Register scratch);
+
+ // Emits a tail call to a VMFunction wrapper.
+ MOZ_MUST_USE bool tailCallVM(const VMFunction& fun, MacroAssembler& masm);
+
+ // Emits a normal (non-tail) call to a VMFunction wrapper.
+ MOZ_MUST_USE 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.
+ MOZ_MUST_USE 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);
+
+ public:
+ static inline AllocatableGeneralRegisterSet availableGeneralRegs(size_t numInputs) {
+ AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
+#if defined(JS_CODEGEN_ARM)
+ MOZ_ASSERT(!regs.has(BaselineStackReg));
+ MOZ_ASSERT(!regs.has(ICTailCallReg));
+ regs.take(BaselineSecondScratchReg);
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+ MOZ_ASSERT(!regs.has(BaselineStackReg));
+ MOZ_ASSERT(!regs.has(ICTailCallReg));
+ MOZ_ASSERT(!regs.has(BaselineSecondScratchReg));
+#elif defined(JS_CODEGEN_ARM64)
+ MOZ_ASSERT(!regs.has(PseudoStackPointer));
+ MOZ_ASSERT(!regs.has(RealStackPointer));
+ MOZ_ASSERT(!regs.has(ICTailCallReg));
+#else
+ MOZ_ASSERT(!regs.has(BaselineStackReg));
+#endif
+ regs.take(BaselineFrameReg);
+ regs.take(ICStubReg);
+#ifdef JS_CODEGEN_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:
+ MOZ_CRASH("Invalid numInputs");
+ }
+
+ return regs;
+ }
+
+ protected:
+ void emitPostWriteBarrierSlot(MacroAssembler& masm, Register obj, ValueOperand val,
+ Register scratch, LiveGeneralRegisterSet saveRegs);
+
+ template <typename T, typename... Args>
+ T* newStub(Args&&... args) {
+ return ICStub::New<T>(cx, mozilla::Forward<Args>(args)...);
+ }
+
+ public:
+ virtual ICStub* getStub(ICStubSpace* space) = 0;
+
+ static ICStubSpace* StubSpaceForKind(ICStub::Kind kind, JSScript* outerScript, Engine engine) {
+ if (ICStub::CanMakeCalls(kind)) {
+ if (engine == ICStubCompiler::Engine::Baseline)
+ return outerScript->baselineScript()->fallbackStubSpace();
+ return outerScript->ionScript()->fallbackStubSpace();
+ }
+ return outerScript->zone()->jitZone()->optimizedStubSpace();
+ }
+
+ ICStubSpace* getStubSpace(JSScript* outerScript) {
+ return StubSpaceForKind(kind, outerScript, engine_);
+ }
+};
+
+class SharedStubInfo
+{
+ BaselineFrame* maybeFrame_;
+ RootedScript outerScript_;
+ RootedScript innerScript_;
+ ICEntry* icEntry_;
+
+ public:
+ SharedStubInfo(JSContext* cx, void* payload, ICEntry* entry);
+
+ ICStubCompiler::Engine engine() const {
+ return maybeFrame_ ? ICStubCompiler::Engine::Baseline : ICStubCompiler::Engine::IonMonkey;
+ }
+
+ HandleScript script() const {
+ MOZ_ASSERT(innerScript_);
+ return innerScript_;
+ }
+
+ HandleScript innerScript() const {
+ MOZ_ASSERT(innerScript_);
+ return innerScript_;
+ }
+
+ HandleScript outerScript(JSContext* cx);
+
+ jsbytecode* pc() const {
+ return icEntry()->pc(innerScript());
+ }
+
+ uint32_t pcOffset() const {
+ return script()->pcToOffset(pc());
+ }
+
+ BaselineFrame* frame() const {
+ MOZ_ASSERT(maybeFrame_);
+ return maybeFrame_;
+ }
+
+ BaselineFrame* maybeFrame() const {
+ return maybeFrame_;
+ }
+
+ ICEntry* icEntry() const {
+ return icEntry_;
+ }
+};
+
+// Monitored fallback stubs - as the name implies.
+class ICMonitoredFallbackStub : public ICFallbackStub
+{
+ protected:
+ // Pointer to the fallback monitor stub.
+ ICTypeMonitor_Fallback* fallbackMonitorStub_;
+
+ ICMonitoredFallbackStub(Kind kind, JitCode* stubCode)
+ : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode),
+ fallbackMonitorStub_(nullptr) {}
+
+ public:
+ MOZ_MUST_USE bool initMonitoringChain(JSContext* cx, ICStubSpace* space,
+ ICStubCompiler::Engine engine);
+ MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, SharedStubInfo* info, HandleValue val);
+
+ inline ICTypeMonitor_Fallback* fallbackMonitorStub() const {
+ return fallbackMonitorStub_;
+ }
+
+ static inline size_t offsetOfFallbackMonitorStub() {
+ return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_);
+ }
+};
+
+
+// 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>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(op) << 17);
+ }
+
+ ICMultiStubCompiler(JSContext* cx, ICStub::Kind kind, JSOp op, Engine engine)
+ : ICStubCompiler(cx, kind, engine), op(op) {}
+};
+
+// 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, JitCode* stubCode, uint16_t flags)
+ : ICStub(kind, stubCode)
+ {
+ MOZ_ASSERT(kind == TypeMonitor_PrimitiveSet || kind == TypeUpdate_PrimitiveSet);
+ MOZ_ASSERT(flags && !(flags & ~ValidFlags()));
+ extra_ = flags;
+ }
+
+ TypeCheckPrimitiveSetStub* updateTypesAndCode(uint16_t flags, JitCode* code) {
+ MOZ_ASSERT(flags && !(flags & ~ValidFlags()));
+ if (!code)
+ return nullptr;
+ extra_ = flags;
+ updateCode(code);
+ return this;
+ }
+
+ public:
+ uint16_t typeFlags() const {
+ return extra_;
+ }
+
+ bool containsType(JSValueType type) const {
+ MOZ_ASSERT(type <= JSVAL_TYPE_OBJECT);
+ MOZ_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>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(flags_) << 17);
+ }
+
+ public:
+ Compiler(JSContext* cx, Kind kind, Engine engine_, TypeCheckPrimitiveSetStub* existingStub,
+ JSValueType type)
+ : ICStubCompiler(cx, kind, engine_),
+ existingStub_(existingStub),
+ flags_((existingStub ? existingStub->typeFlags() : 0) | TypeToFlag(type))
+ {
+ MOZ_ASSERT_IF(existingStub_, flags_ != existingStub_->typeFlags());
+ }
+
+ TypeCheckPrimitiveSetStub* updateStub() {
+ MOZ_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_ : 7;
+
+ uint32_t invalid_ : 1;
+
+ // 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(JitCode* stubCode, ICMonitoredFallbackStub* mainFallbackStub,
+ uint32_t argumentIndex)
+ : ICStub(ICStub::TypeMonitor_Fallback, stubCode),
+ mainFallbackStub_(mainFallbackStub),
+ firstMonitorStub_(thisFromCtor()),
+ lastMonitorStubPtrAddr_(nullptr),
+ numOptimizedMonitorStubs_(0),
+ invalid_(false),
+ hasFallbackStub_(mainFallbackStub != nullptr),
+ argumentIndex_(argumentIndex)
+ { }
+
+ ICTypeMonitor_Fallback* thisFromCtor() {
+ return this;
+ }
+
+ void addOptimizedMonitorStub(ICStub* stub) {
+ MOZ_ASSERT(!invalid());
+ stub->setNext(this);
+
+ MOZ_ASSERT((lastMonitorStubPtrAddr_ != nullptr) ==
+ (numOptimizedMonitorStubs_ || !hasFallbackStub_));
+
+ if (lastMonitorStubPtrAddr_)
+ *lastMonitorStubPtrAddr_ = stub;
+
+ if (numOptimizedMonitorStubs_ == 0) {
+ MOZ_ASSERT(firstMonitorStub_ == this);
+ firstMonitorStub_ = stub;
+ } else {
+ MOZ_ASSERT(firstMonitorStub_ != nullptr);
+ }
+
+ lastMonitorStubPtrAddr_ = stub->addressOfNext();
+ numOptimizedMonitorStubs_++;
+ }
+
+ public:
+ 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 {
+ MOZ_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_;
+ }
+
+ void setInvalid() {
+ invalid_ = 1;
+ }
+
+ bool invalid() const {
+ return invalid_;
+ }
+
+ 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) {
+ MOZ_ASSERT(!hasFallbackStub_);
+ MOZ_ASSERT(icEntry_ == nullptr);
+ MOZ_ASSERT(lastMonitorStubPtrAddr_ == nullptr);
+ icEntry_ = icEntry;
+ lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub();
+ }
+
+ // Create a new monitor stub for the type of the given value, and
+ // add it to this chain.
+ MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, SharedStubInfo* info, HandleValue val);
+
+ void resetMonitorStubChain(Zone* zone);
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ ICMonitoredFallbackStub* mainFallbackStub_;
+ uint32_t argumentIndex_;
+
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, Engine engine, ICMonitoredFallbackStub* mainFallbackStub)
+ : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback, engine),
+ mainFallbackStub_(mainFallbackStub),
+ argumentIndex_(BYTECODE_INDEX)
+ { }
+
+ Compiler(JSContext* cx, Engine engine, uint32_t argumentIndex)
+ : ICStubCompiler(cx, ICStub::TypeMonitor_Fallback, engine),
+ mainFallbackStub_(nullptr),
+ argumentIndex_(argumentIndex)
+ { }
+
+ ICTypeMonitor_Fallback* getStub(ICStubSpace* space) {
+ return newStub<ICTypeMonitor_Fallback>(space, getStubCode(), mainFallbackStub_,
+ argumentIndex_);
+ }
+ };
+};
+
+class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub
+{
+ friend class ICStubSpace;
+
+ ICTypeMonitor_PrimitiveSet(JitCode* stubCode, uint16_t flags)
+ : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags)
+ {}
+
+ public:
+ class Compiler : public TypeCheckPrimitiveSetStub::Compiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, Engine engine, ICTypeMonitor_PrimitiveSet* existingStub,
+ JSValueType type)
+ : TypeCheckPrimitiveSetStub::Compiler(cx, TypeMonitor_PrimitiveSet, engine, existingStub,
+ type)
+ {}
+
+ ICTypeMonitor_PrimitiveSet* updateStub() {
+ TypeCheckPrimitiveSetStub* stub =
+ this->TypeCheckPrimitiveSetStub::Compiler::updateStub();
+ if (!stub)
+ return nullptr;
+ return stub->toMonitorStub();
+ }
+
+ ICTypeMonitor_PrimitiveSet* getStub(ICStubSpace* space) {
+ MOZ_ASSERT(!existingStub_);
+ return newStub<ICTypeMonitor_PrimitiveSet>(space, getStubCode(), flags_);
+ }
+ };
+};
+
+class ICTypeMonitor_SingleObject : public ICStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObject obj_;
+
+ ICTypeMonitor_SingleObject(JitCode* stubCode, JSObject* obj);
+
+ public:
+ GCPtrObject& object() {
+ return obj_;
+ }
+
+ static size_t offsetOfObject() {
+ return offsetof(ICTypeMonitor_SingleObject, obj_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ HandleObject obj_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, HandleObject obj)
+ : ICStubCompiler(cx, TypeMonitor_SingleObject, Engine::Baseline),
+ obj_(obj)
+ { }
+
+ ICTypeMonitor_SingleObject* getStub(ICStubSpace* space) {
+ return newStub<ICTypeMonitor_SingleObject>(space, getStubCode(), obj_);
+ }
+ };
+};
+
+class ICTypeMonitor_ObjectGroup : public ICStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObjectGroup group_;
+
+ ICTypeMonitor_ObjectGroup(JitCode* stubCode, ObjectGroup* group);
+
+ public:
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+
+ static size_t offsetOfGroup() {
+ return offsetof(ICTypeMonitor_ObjectGroup, group_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ HandleObjectGroup group_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, HandleObjectGroup group)
+ : ICStubCompiler(cx, TypeMonitor_ObjectGroup, Engine::Baseline),
+ group_(group)
+ { }
+
+ ICTypeMonitor_ObjectGroup* getStub(ICStubSpace* space) {
+ return newStub<ICTypeMonitor_ObjectGroup>(space, getStubCode(), group_);
+ }
+ };
+};
+
+
+// BinaryArith
+// JSOP_ADD, JSOP_SUB, JSOP_MUL, JOP_DIV, JSOP_MOD
+// JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR
+// JSOP_LSH, JSOP_RSH, JSOP_URSH
+
+class ICBinaryArith_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICBinaryArith_Fallback(JitCode* stubCode)
+ : ICFallbackStub(BinaryArith_Fallback, stubCode)
+ {
+ extra_ = 0;
+ }
+
+ static const uint16_t SAW_DOUBLE_RESULT_BIT = 0x1;
+ static const uint16_t UNOPTIMIZABLE_OPERANDS_BIT = 0x2;
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ bool sawDoubleResult() const {
+ return extra_ & SAW_DOUBLE_RESULT_BIT;
+ }
+ void setSawDoubleResult() {
+ extra_ |= SAW_DOUBLE_RESULT_BIT;
+ }
+ bool hadUnoptimizableOperands() const {
+ return extra_ & UNOPTIMIZABLE_OPERANDS_BIT;
+ }
+ void noteUnoptimizableOperands() {
+ extra_ |= UNOPTIMIZABLE_OPERANDS_BIT;
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx, Engine engine)
+ : ICStubCompiler(cx, ICStub::BinaryArith_Fallback, engine) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICBinaryArith_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+class ICBinaryArith_Int32 : public ICStub
+{
+ friend class ICStubSpace;
+
+ ICBinaryArith_Int32(JitCode* stubCode, bool allowDouble)
+ : ICStub(BinaryArith_Int32, stubCode)
+ {
+ extra_ = allowDouble;
+ }
+
+ public:
+ bool allowDouble() const {
+ return extra_;
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ JSOp op_;
+ bool allowDouble_;
+
+ MOZ_MUST_USE 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>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(op_) << 17) |
+ (static_cast<int32_t>(allowDouble_) << 25);
+ }
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine, bool allowDouble)
+ : ICStubCompiler(cx, ICStub::BinaryArith_Int32, engine),
+ op_(op), allowDouble_(allowDouble) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICBinaryArith_Int32>(space, getStubCode(), allowDouble_);
+ }
+ };
+};
+
+class ICBinaryArith_StringConcat : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICBinaryArith_StringConcat(JitCode* stubCode)
+ : ICStub(BinaryArith_StringConcat, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx, Engine engine)
+ : ICStubCompiler(cx, ICStub::BinaryArith_StringConcat, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICBinaryArith_StringConcat>(space, getStubCode());
+ }
+ };
+};
+
+class ICBinaryArith_StringObjectConcat : public ICStub
+{
+ friend class ICStubSpace;
+
+ ICBinaryArith_StringObjectConcat(JitCode* stubCode, bool lhsIsString)
+ : ICStub(BinaryArith_StringObjectConcat, stubCode)
+ {
+ extra_ = lhsIsString;
+ }
+
+ public:
+ bool lhsIsString() const {
+ return extra_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ bool lhsIsString_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(lhsIsString_) << 17);
+ }
+
+ public:
+ Compiler(JSContext* cx, Engine engine, bool lhsIsString)
+ : ICStubCompiler(cx, ICStub::BinaryArith_StringObjectConcat, engine),
+ lhsIsString_(lhsIsString)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICBinaryArith_StringObjectConcat>(space, getStubCode(),
+ lhsIsString_);
+ }
+ };
+};
+
+class ICBinaryArith_Double : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICBinaryArith_Double(JitCode* stubCode)
+ : ICStub(BinaryArith_Double, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine)
+ : ICMultiStubCompiler(cx, ICStub::BinaryArith_Double, op, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICBinaryArith_Double>(space, getStubCode());
+ }
+ };
+};
+
+class ICBinaryArith_BooleanWithInt32 : public ICStub
+{
+ friend class ICStubSpace;
+
+ ICBinaryArith_BooleanWithInt32(JitCode* stubCode, bool lhsIsBool, bool rhsIsBool)
+ : ICStub(BinaryArith_BooleanWithInt32, stubCode)
+ {
+ MOZ_ASSERT(lhsIsBool || rhsIsBool);
+ extra_ = 0;
+ if (lhsIsBool)
+ extra_ |= 1;
+ if (rhsIsBool)
+ extra_ |= 2;
+ }
+
+ public:
+ bool lhsIsBoolean() const {
+ return extra_ & 1;
+ }
+
+ bool rhsIsBoolean() const {
+ return extra_ & 2;
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ JSOp op_;
+ bool lhsIsBool_;
+ bool rhsIsBool_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(op_) << 17) |
+ (static_cast<int32_t>(lhsIsBool_) << 25) |
+ (static_cast<int32_t>(rhsIsBool_) << 26);
+ }
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsBool, bool rhsIsBool)
+ : ICStubCompiler(cx, ICStub::BinaryArith_BooleanWithInt32, engine),
+ op_(op), lhsIsBool_(lhsIsBool), rhsIsBool_(rhsIsBool)
+ {
+ MOZ_ASSERT(op_ == JSOP_ADD || op_ == JSOP_SUB || op_ == JSOP_BITOR ||
+ op_ == JSOP_BITAND || op_ == JSOP_BITXOR);
+ MOZ_ASSERT(lhsIsBool_ || rhsIsBool_);
+ }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICBinaryArith_BooleanWithInt32>(space, getStubCode(),
+ lhsIsBool_, rhsIsBool_);
+ }
+ };
+};
+
+class ICBinaryArith_DoubleWithInt32 : public ICStub
+{
+ friend class ICStubSpace;
+
+ ICBinaryArith_DoubleWithInt32(JitCode* stubCode, bool lhsIsDouble)
+ : ICStub(BinaryArith_DoubleWithInt32, stubCode)
+ {
+ extra_ = lhsIsDouble;
+ }
+
+ public:
+ bool lhsIsDouble() const {
+ return extra_;
+ }
+
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ bool lhsIsDouble_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(op) << 17) |
+ (static_cast<int32_t>(lhsIsDouble_) << 25);
+ }
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsDouble)
+ : ICMultiStubCompiler(cx, ICStub::BinaryArith_DoubleWithInt32, op, engine),
+ lhsIsDouble_(lhsIsDouble)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICBinaryArith_DoubleWithInt32>(space, getStubCode(),
+ lhsIsDouble_);
+ }
+ };
+};
+
+// UnaryArith
+// JSOP_BITNOT
+// JSOP_NEG
+
+class ICUnaryArith_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICUnaryArith_Fallback(JitCode* stubCode)
+ : ICFallbackStub(UnaryArith_Fallback, stubCode)
+ {
+ extra_ = 0;
+ }
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ bool sawDoubleResult() {
+ return extra_;
+ }
+ void setSawDoubleResult() {
+ extra_ = 1;
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx, Engine engine)
+ : ICStubCompiler(cx, ICStub::UnaryArith_Fallback, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICUnaryArith_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+class ICUnaryArith_Int32 : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICUnaryArith_Int32(JitCode* stubCode)
+ : ICStub(UnaryArith_Int32, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine)
+ : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICUnaryArith_Int32>(space, getStubCode());
+ }
+ };
+};
+
+class ICUnaryArith_Double : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICUnaryArith_Double(JitCode* stubCode)
+ : ICStub(UnaryArith_Double, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine)
+ : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICUnaryArith_Double>(space, getStubCode());
+ }
+ };
+};
+
+// Compare
+// JSOP_LT
+// JSOP_LE
+// JSOP_GT
+// JSOP_GE
+// JSOP_EQ
+// JSOP_NE
+// JSOP_STRICTEQ
+// JSOP_STRICTNE
+
+class ICCompare_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICCompare_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::Compare_Fallback, stubCode) {}
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
+ void noteUnoptimizableAccess() {
+ extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
+ }
+ bool hadUnoptimizableAccess() const {
+ return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx, Engine engine)
+ : ICStubCompiler(cx, ICStub::Compare_Fallback, engine) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+class ICCompare_Int32 : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICCompare_Int32(JitCode* stubCode)
+ : ICStub(ICStub::Compare_Int32, stubCode) {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine)
+ : ICMultiStubCompiler(cx, ICStub::Compare_Int32, op, engine) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_Int32>(space, getStubCode());
+ }
+ };
+};
+
+class ICCompare_Double : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICCompare_Double(JitCode* stubCode)
+ : ICStub(ICStub::Compare_Double, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine)
+ : ICMultiStubCompiler(cx, ICStub::Compare_Double, op, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_Double>(space, getStubCode());
+ }
+ };
+};
+
+class ICCompare_NumberWithUndefined : public ICStub
+{
+ friend class ICStubSpace;
+
+ ICCompare_NumberWithUndefined(JitCode* stubCode, bool lhsIsUndefined)
+ : ICStub(ICStub::Compare_NumberWithUndefined, stubCode)
+ {
+ extra_ = lhsIsUndefined;
+ }
+
+ public:
+ bool lhsIsUndefined() {
+ return extra_;
+ }
+
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ bool lhsIsUndefined;
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsUndefined)
+ : ICMultiStubCompiler(cx, ICStub::Compare_NumberWithUndefined, op, engine),
+ lhsIsUndefined(lhsIsUndefined)
+ {}
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(op) << 17) |
+ (static_cast<int32_t>(lhsIsUndefined) << 25);
+ }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_NumberWithUndefined>(space, getStubCode(),
+ lhsIsUndefined);
+ }
+ };
+};
+
+class ICCompare_String : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICCompare_String(JitCode* stubCode)
+ : ICStub(ICStub::Compare_String, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine)
+ : ICMultiStubCompiler(cx, ICStub::Compare_String, op, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_String>(space, getStubCode());
+ }
+ };
+};
+
+class ICCompare_Boolean : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICCompare_Boolean(JitCode* stubCode)
+ : ICStub(ICStub::Compare_Boolean, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine)
+ : ICMultiStubCompiler(cx, ICStub::Compare_Boolean, op, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_Boolean>(space, getStubCode());
+ }
+ };
+};
+
+class ICCompare_Object : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICCompare_Object(JitCode* stubCode)
+ : ICStub(ICStub::Compare_Object, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine)
+ : ICMultiStubCompiler(cx, ICStub::Compare_Object, op, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_Object>(space, getStubCode());
+ }
+ };
+};
+
+class ICCompare_ObjectWithUndefined : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICCompare_ObjectWithUndefined(JitCode* stubCode)
+ : ICStub(ICStub::Compare_ObjectWithUndefined, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICMultiStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ bool lhsIsUndefined;
+ bool compareWithNull;
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsUndefined, bool compareWithNull)
+ : ICMultiStubCompiler(cx, ICStub::Compare_ObjectWithUndefined, op, engine),
+ lhsIsUndefined(lhsIsUndefined),
+ compareWithNull(compareWithNull)
+ {}
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(op) << 17) |
+ (static_cast<int32_t>(lhsIsUndefined) << 25) |
+ (static_cast<int32_t>(compareWithNull) << 26);
+ }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_ObjectWithUndefined>(space, getStubCode());
+ }
+ };
+};
+
+class ICCompare_Int32WithBoolean : public ICStub
+{
+ friend class ICStubSpace;
+
+ ICCompare_Int32WithBoolean(JitCode* stubCode, bool lhsIsInt32)
+ : ICStub(ICStub::Compare_Int32WithBoolean, stubCode)
+ {
+ extra_ = lhsIsInt32;
+ }
+
+ public:
+ bool lhsIsInt32() const {
+ return extra_;
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ JSOp op_;
+ bool lhsIsInt32_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(op_) << 17) |
+ (static_cast<int32_t>(lhsIsInt32_) << 25);
+ }
+
+ public:
+ Compiler(JSContext* cx, JSOp op, Engine engine, bool lhsIsInt32)
+ : ICStubCompiler(cx, ICStub::Compare_Int32WithBoolean, engine),
+ op_(op),
+ lhsIsInt32_(lhsIsInt32)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCompare_Int32WithBoolean>(space, getStubCode(), lhsIsInt32_);
+ }
+ };
+};
+
+// Enum for stubs handling a combination of typed arrays and typed objects.
+enum TypedThingLayout {
+ Layout_TypedArray,
+ Layout_OutlineTypedObject,
+ Layout_InlineTypedObject
+};
+
+static inline TypedThingLayout
+GetTypedThingLayout(const Class* clasp)
+{
+ if (IsTypedArrayClass(clasp))
+ return Layout_TypedArray;
+ if (IsOutlineTypedObjectClass(clasp))
+ return Layout_OutlineTypedObject;
+ if (IsInlineTypedObjectClass(clasp))
+ return Layout_InlineTypedObject;
+ MOZ_CRASH("Bad object class");
+}
+
+bool
+IsPreliminaryObject(JSObject* obj);
+
+void
+StripPreliminaryObjectStubs(JSContext* cx, ICFallbackStub* stub);
+
+MOZ_MUST_USE bool
+EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId name,
+ MutableHandleObject holder, MutableHandleShape shape,
+ bool* checkDOMProxy=nullptr,
+ DOMProxyShadowsResult* shadowsResult=nullptr,
+ bool* domProxyHasGeneration=nullptr);
+
+JSObject*
+GetDOMProxyProto(JSObject* obj);
+
+bool
+IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy=false);
+
+bool
+IsCacheableGetPropReadSlot(JSObject* obj, JSObject* holder, Shape* shape, bool isDOMProxy=false);
+
+void
+GetFixedOrDynamicSlotOffset(Shape* shape, bool* isFixed, uint32_t* offset);
+
+MOZ_MUST_USE bool
+IsCacheableGetPropCall(JSContext* cx, JSObject* obj, JSObject* holder, Shape* shape,
+ bool* isScripted, bool* isTemporarilyUnoptimizable, bool isDOMProxy=false);
+
+MOZ_MUST_USE bool
+UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub,
+ ICStub::Kind kind,
+ HandleNativeObject holder,
+ HandleObject receiver,
+ HandleFunction getter);
+MOZ_MUST_USE bool
+CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
+ JSObject** lastProto = nullptr, size_t* protoChainDepthOut = nullptr);
+
+void
+GuardReceiverObject(MacroAssembler& masm, ReceiverGuard guard,
+ Register object, Register scratch,
+ size_t receiverGuardOffset, Label* failure);
+
+MOZ_MUST_USE bool
+GetProtoShapes(JSObject* obj, size_t protoChainDepth, MutableHandle<ShapeVector> shapes);
+
+void
+CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, Register object,
+ const Address& checkExpandoShapeAddr,
+ Address* expandoAndGenerationAddr,
+ Address* generationAddr,
+ Register scratch,
+ AllocatableGeneralRegisterSet& domProxyRegSet,
+ Label* checkFailed);
+
+void
+CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure);
+
+MOZ_MUST_USE bool
+DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
+ MutableHandleValue result);
+
+void
+LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result);
+
+class ICGetProp_Fallback : public ICMonitoredFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICGetProp_Fallback(JitCode* stubCode)
+ : ICMonitoredFallbackStub(ICStub::GetProp_Fallback, stubCode)
+ { }
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 16;
+ 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 {
+ public:
+ static const int32_t BASELINE_KEY =
+ (static_cast<int32_t>(Engine::Baseline)) |
+ (static_cast<int32_t>(ICStub::GetProp_Fallback) << 1);
+
+ protected:
+ uint32_t returnOffset_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+ void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> code);
+
+ public:
+ explicit Compiler(JSContext* cx, Engine engine)
+ : ICStubCompiler(cx, ICStub::GetProp_Fallback, engine)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ ICGetProp_Fallback* stub = newStub<ICGetProp_Fallback>(space, getStubCode());
+ if (!stub || !stub->initMonitoringChain(cx, space, engine_))
+ return nullptr;
+ return stub;
+ }
+ };
+};
+
+// Stub for sites, which are too polymorphic (i.e. MAX_OPTIMIZED_STUBS was reached)
+class ICGetProp_Generic : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ explicit ICGetProp_Generic(JitCode* stubCode, ICStub* firstMonitorStub)
+ : ICMonitoredStub(ICStub::GetProp_Generic, stubCode, firstMonitorStub) {}
+
+ public:
+ static ICGetProp_Generic* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICGetProp_Generic& other);
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+ ICStub* firstMonitorStub_;
+ public:
+ explicit Compiler(JSContext* cx, Engine engine, ICStub* firstMonitorStub)
+ : ICStubCompiler(cx, ICStub::GetProp_Generic, engine),
+ firstMonitorStub_(firstMonitorStub)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetProp_Generic>(space, getStubCode(), firstMonitorStub_);
+ }
+ };
+};
+
+// Stub for accessing a string's length.
+class ICGetProp_StringLength : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICGetProp_StringLength(JitCode* stubCode)
+ : ICStub(GetProp_StringLength, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICStubCompiler {
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx, Engine engine)
+ : ICStubCompiler(cx, ICStub::GetProp_StringLength, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetProp_StringLength>(space, getStubCode());
+ }
+ };
+};
+
+// Base class for native GetProp stubs.
+class ICGetPropNativeStub : public ICMonitoredStub
+{
+ // Object shape/group.
+ HeapReceiverGuard receiverGuard_;
+
+ // Fixed or dynamic slot offset.
+ uint32_t offset_;
+
+ protected:
+ ICGetPropNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, uint32_t offset);
+
+ public:
+ HeapReceiverGuard& receiverGuard() {
+ return receiverGuard_;
+ }
+ uint32_t offset() const {
+ return offset_;
+ }
+
+ void notePreliminaryObject() {
+ extra_ = 1;
+ }
+ bool hasPreliminaryObject() const {
+ return extra_;
+ }
+
+ static size_t offsetOfReceiverGuard() {
+ return offsetof(ICGetPropNativeStub, receiverGuard_);
+ }
+ static size_t offsetOfOffset() {
+ return offsetof(ICGetPropNativeStub, offset_);
+ }
+};
+
+class ICGetPropNativePrototypeStub : public ICGetPropNativeStub
+{
+ // Holder and its shape.
+ GCPtrObject holder_;
+ GCPtrShape holderShape_;
+
+ protected:
+ ICGetPropNativePrototypeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, uint32_t offset, JSObject* holder,
+ Shape* holderShape);
+
+ public:
+ GCPtrObject& holder() {
+ return holder_;
+ }
+ GCPtrShape& holderShape() {
+ return holderShape_;
+ }
+ static size_t offsetOfHolder() {
+ return offsetof(ICGetPropNativePrototypeStub, holder_);
+ }
+ static size_t offsetOfHolderShape() {
+ return offsetof(ICGetPropNativePrototypeStub, holderShape_);
+ }
+};
+
+// Stub for accessing a non-lexical global name. Semantically, it is really a
+// getprop: the name is either on the GlobalObject or its prototype chain. We
+// teleport to the object that has the name, but we also need to guard on the
+// shape of the global object.
+//
+// The receiver object is the global lexical scope.
+class ICGetName_Global : public ICGetPropNativePrototypeStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ GCPtrShape globalShape_;
+
+ ICGetName_Global(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
+ uint32_t slot, JSObject* holder, Shape* holderShape, Shape* globalShape);
+
+ public:
+ static ICGetName_Global* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICGetName_Global& other);
+
+ GCPtrShape& globalShape() {
+ return globalShape_;
+ }
+ static size_t offsetOfGlobalShape() {
+ return offsetof(ICGetName_Global, globalShape_);
+ }
+};
+
+// Compiler for native GetProp stubs.
+class ICGetPropNativeCompiler : public ICStubCompiler
+{
+ ICStub* firstMonitorStub_;
+ HandleObject obj_;
+ HandleObject holder_;
+ HandlePropertyName propName_;
+ bool isFixedSlot_;
+ uint32_t offset_;
+ bool inputDefinitelyObject_;
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ protected:
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(isFixedSlot_) << 17) |
+ (static_cast<int32_t>(inputDefinitelyObject_) << 18) |
+ (HeapReceiverGuard::keyBits(obj_) << 19);
+ }
+
+ public:
+ ICGetPropNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStubCompiler::Engine engine,
+ ICStub* firstMonitorStub, HandleObject obj, HandleObject holder,
+ HandlePropertyName propName, bool isFixedSlot, uint32_t offset,
+ bool inputDefinitelyObject = false)
+ : ICStubCompiler(cx, kind, engine),
+ firstMonitorStub_(firstMonitorStub),
+ obj_(obj),
+ holder_(holder),
+ propName_(propName),
+ isFixedSlot_(isFixedSlot),
+ offset_(offset),
+ inputDefinitelyObject_(inputDefinitelyObject)
+ {}
+
+ ICGetPropNativeStub* getStub(ICStubSpace* space);
+};
+
+static uint32_t
+SimpleTypeDescrKey(SimpleTypeDescr* descr)
+{
+ if (descr->is<ScalarTypeDescr>())
+ return uint32_t(descr->as<ScalarTypeDescr>().type()) << 1;
+ return (uint32_t(descr->as<ReferenceTypeDescr>().type()) << 1) | 1;
+}
+
+inline bool
+SimpleTypeDescrKeyIsScalar(uint32_t key)
+{
+ return !(key & 1);
+}
+
+inline ScalarTypeDescr::Type
+ScalarTypeFromSimpleTypeDescrKey(uint32_t key)
+{
+ MOZ_ASSERT(SimpleTypeDescrKeyIsScalar(key));
+ return ScalarTypeDescr::Type(key >> 1);
+}
+
+inline ReferenceTypeDescr::Type
+ReferenceTypeFromSimpleTypeDescrKey(uint32_t key)
+{
+ MOZ_ASSERT(!SimpleTypeDescrKeyIsScalar(key));
+ return ReferenceTypeDescr::Type(key >> 1);
+}
+
+class ICGetPropCallGetter : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ // Shape/group of receiver object. Used for both own and proto getters.
+ // In the GetPropCallDOMProxyNative case, the receiver guard enforces
+ // the proxy handler, because Shape implies Class.
+ HeapReceiverGuard receiverGuard_;
+
+ // Holder and holder shape. For own getters, guarding on receiverGuard_ is
+ // sufficient, although Ion may use holder_ and holderShape_ even for own
+ // getters. In this case holderShape_ == receiverGuard_.shape_ (isOwnGetter
+ // below relies on this).
+ GCPtrObject holder_;
+
+ GCPtrShape holderShape_;
+
+ // Function to call.
+ GCPtrFunction getter_;
+
+ // PC offset of call
+ uint32_t pcOffset_;
+
+ ICGetPropCallGetter(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard receiverGuard, JSObject* holder,
+ Shape* holderShape, JSFunction* getter, uint32_t pcOffset);
+
+ public:
+ GCPtrObject& holder() {
+ return holder_;
+ }
+ GCPtrShape& holderShape() {
+ return holderShape_;
+ }
+ GCPtrFunction& getter() {
+ return getter_;
+ }
+ HeapReceiverGuard& receiverGuard() {
+ return receiverGuard_;
+ }
+
+ bool isOwnGetter() const {
+ MOZ_ASSERT(holder_->isNative());
+ MOZ_ASSERT(holderShape_);
+ return receiverGuard_.shape() == holderShape_;
+ }
+
+ 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_);
+ }
+ static size_t offsetOfReceiverGuard() {
+ return offsetof(ICGetPropCallGetter, receiverGuard_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ ICStub* firstMonitorStub_;
+ RootedObject receiver_;
+ RootedObject holder_;
+ RootedFunction getter_;
+ uint32_t pcOffset_;
+ const Class* outerClass_;
+
+ virtual int32_t getKey() const {
+ // ICGetPropCallNativeCompiler::getKey adds more bits to our
+ // return value, so be careful when making changes here.
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (HeapReceiverGuard::keyBits(receiver_) << 17) |
+ (static_cast<int32_t>(!!outerClass_) << 19) |
+ (static_cast<int32_t>(receiver_ != holder_) << 20);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub::Kind kind, Engine engine, ICStub* firstMonitorStub,
+ HandleObject receiver, HandleObject holder, HandleFunction getter,
+ uint32_t pcOffset, const Class* outerClass)
+ : ICStubCompiler(cx, kind, engine),
+ firstMonitorStub_(firstMonitorStub),
+ receiver_(cx, receiver),
+ holder_(cx, holder),
+ getter_(cx, getter),
+ pcOffset_(pcOffset),
+ outerClass_(outerClass)
+ {
+ MOZ_ASSERT(kind == ICStub::GetProp_CallScripted ||
+ kind == ICStub::GetProp_CallNative ||
+ kind == ICStub::GetProp_CallNativeGlobal);
+ }
+ };
+};
+
+// Stub for calling a scripted getter on a native object when the getter is kept on the
+// proto-chain.
+class ICGetProp_CallScripted : public ICGetPropCallGetter
+{
+ friend class ICStubSpace;
+
+ protected:
+ ICGetProp_CallScripted(JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard receiverGuard,
+ JSObject* holder, Shape* holderShape,
+ JSFunction* getter, uint32_t pcOffset)
+ : ICGetPropCallGetter(GetProp_CallScripted, stubCode, firstMonitorStub,
+ receiverGuard, holder, holderShape, getter, pcOffset)
+ {}
+
+ public:
+ static ICGetProp_CallScripted* Clone(JSContext* cx, ICStubSpace* space,
+ ICStub* firstMonitorStub, ICGetProp_CallScripted& other);
+
+ class Compiler : public ICGetPropCallGetter::Compiler {
+ protected:
+ MOZ_MUST_USE 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, Engine::Baseline,
+ firstMonitorStub, obj, holder,
+ getter, pcOffset, /* outerClass = */ nullptr)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ ReceiverGuard guard(receiver_);
+ Shape* holderShape = holder_->as<NativeObject>().lastProperty();
+ return newStub<ICGetProp_CallScripted>(space, getStubCode(), firstMonitorStub_,
+ guard, 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(JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard receiverGuard,
+ JSObject* holder, Shape* holderShape,
+ JSFunction* getter, uint32_t pcOffset)
+ : ICGetPropCallGetter(GetProp_CallNative, stubCode, firstMonitorStub,
+ receiverGuard, holder, holderShape, getter, pcOffset)
+ {}
+
+ public:
+ static ICGetProp_CallNative* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICGetProp_CallNative& other);
+
+};
+
+// Stub for calling a native getter on the GlobalObject.
+class ICGetProp_CallNativeGlobal : public ICGetPropCallGetter
+{
+ friend class ICStubSpace;
+
+ protected:
+ GCPtrShape globalShape_;
+
+ ICGetProp_CallNativeGlobal(JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard receiverGuard,
+ JSObject* holder, Shape* holderShape, Shape* globalShape,
+ JSFunction* getter, uint32_t pcOffset)
+ : ICGetPropCallGetter(GetProp_CallNativeGlobal, stubCode, firstMonitorStub,
+ receiverGuard, holder, holderShape, getter, pcOffset),
+ globalShape_(globalShape)
+ { }
+
+ public:
+ static ICGetProp_CallNativeGlobal* Clone(JSContext* cx, ICStubSpace* space,
+ ICStub* firstMonitorStub,
+ ICGetProp_CallNativeGlobal& other);
+
+ GCPtrShape& globalShape() {
+ return globalShape_;
+ }
+ static size_t offsetOfGlobalShape() {
+ return offsetof(ICGetProp_CallNativeGlobal, globalShape_);
+ }
+};
+
+class ICGetPropCallNativeCompiler : public ICGetPropCallGetter::Compiler
+{
+ bool inputDefinitelyObject_;
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ int32_t baseKey = ICGetPropCallGetter::Compiler::getKey();
+ MOZ_ASSERT((baseKey >> 21) == 0);
+ return baseKey | (static_cast<int32_t>(inputDefinitelyObject_) << 21);
+ }
+
+ public:
+ ICGetPropCallNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStubCompiler::Engine engine,
+ ICStub* firstMonitorStub, HandleObject receiver,
+ HandleObject holder, HandleFunction getter, uint32_t pcOffset,
+ const Class* outerClass, bool inputDefinitelyObject = false)
+ : ICGetPropCallGetter::Compiler(cx, kind, engine, firstMonitorStub, receiver, holder,
+ getter, pcOffset, outerClass),
+ inputDefinitelyObject_(inputDefinitelyObject)
+ {}
+
+ ICStub* getStub(ICStubSpace* space);
+};
+
+class ICGetPropCallDOMProxyNativeStub : public ICGetPropCallGetter
+{
+ friend class ICStubSpace;
+ protected:
+ // Object shape of expected expando object. (nullptr if no expando object should be there)
+ GCPtrShape expandoShape_;
+
+ ICGetPropCallDOMProxyNativeStub(ICStub::Kind kind, JitCode* stubCode,
+ ICStub* firstMonitorStub, Shape* shape,
+ Shape* expandoShape,
+ JSObject* holder, Shape* holderShape,
+ JSFunction* getter, uint32_t pcOffset);
+
+ public:
+ GCPtrShape& expandoShape() {
+ return expandoShape_;
+ }
+ static size_t offsetOfExpandoShape() {
+ return offsetof(ICGetPropCallDOMProxyNativeStub, expandoShape_);
+ }
+};
+
+class ICGetProp_CallDOMProxyNative : public ICGetPropCallDOMProxyNativeStub
+{
+ friend class ICStubSpace;
+ ICGetProp_CallDOMProxyNative(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape,
+ Shape* expandoShape,
+ JSObject* holder, Shape* holderShape,
+ JSFunction* getter, uint32_t pcOffset)
+ : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyNative, stubCode,
+ firstMonitorStub, shape, expandoShape,
+ holder, holderShape, getter, pcOffset)
+ {}
+
+ public:
+ static ICGetProp_CallDOMProxyNative* Clone(JSContext* cx,
+ ICStubSpace* space,
+ ICStub* firstMonitorStub,
+ ICGetProp_CallDOMProxyNative& other);
+};
+
+class ICGetProp_CallDOMProxyWithGenerationNative : public ICGetPropCallDOMProxyNativeStub
+{
+ protected:
+ ExpandoAndGeneration* expandoAndGeneration_;
+ uint64_t generation_;
+
+ public:
+ ICGetProp_CallDOMProxyWithGenerationNative(JitCode* stubCode, ICStub* firstMonitorStub,
+ Shape* shape,
+ ExpandoAndGeneration* expandoAndGeneration,
+ uint64_t generation, Shape* expandoShape,
+ JSObject* holder, Shape* holderShape,
+ JSFunction* getter, uint32_t pcOffset)
+ : ICGetPropCallDOMProxyNativeStub(ICStub::GetProp_CallDOMProxyWithGenerationNative,
+ stubCode, firstMonitorStub, shape,
+ expandoShape, holder, holderShape, getter, pcOffset),
+ expandoAndGeneration_(expandoAndGeneration),
+ generation_(generation)
+ {
+ }
+
+ static ICGetProp_CallDOMProxyWithGenerationNative*
+ Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICGetProp_CallDOMProxyWithGenerationNative& other);
+
+ void* expandoAndGeneration() const {
+ return expandoAndGeneration_;
+ }
+ uint64_t generation() const {
+ return generation_;
+ }
+
+ void setGeneration(uint64_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_;
+ Rooted<ProxyObject*> proxy_;
+ RootedObject holder_;
+ RootedFunction getter_;
+ uint32_t pcOffset_;
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm, Address* internalStructAddr,
+ Address* generationAddr);
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ ICGetPropCallDOMProxyNativeCompiler(JSContext* cx, ICStub::Kind kind,
+ ICStubCompiler::Engine engine,
+ ICStub* firstMonitorStub, Handle<ProxyObject*> proxy,
+ HandleObject holder, HandleFunction getter,
+ uint32_t pcOffset);
+
+ ICStub* getStub(ICStubSpace* space);
+};
+
+class ICGetProp_DOMProxyShadowed : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+ protected:
+ GCPtrShape shape_;
+ const BaseProxyHandler* proxyHandler_;
+ GCPtrPropertyName name_;
+ uint32_t pcOffset_;
+
+ ICGetProp_DOMProxyShadowed(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape,
+ const BaseProxyHandler* proxyHandler, PropertyName* name,
+ uint32_t pcOffset);
+
+ public:
+ static ICGetProp_DOMProxyShadowed* Clone(JSContext* cx, ICStubSpace* space,
+ ICStub* firstMonitorStub,
+ ICGetProp_DOMProxyShadowed& other);
+
+ GCPtrShape& shape() {
+ return shape_;
+ }
+ GCPtrPropertyName& 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_;
+ Rooted<ProxyObject*> proxy_;
+ RootedPropertyName name_;
+ uint32_t pcOffset_;
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, Engine engine, ICStub* firstMonitorStub, Handle<ProxyObject*> proxy,
+ HandlePropertyName name, uint32_t pcOffset)
+ : ICStubCompiler(cx, ICStub::GetProp_CallNative, engine),
+ firstMonitorStub_(firstMonitorStub),
+ proxy_(cx, proxy),
+ name_(cx, name),
+ pcOffset_(pcOffset)
+ {}
+
+ ICStub* getStub(ICStubSpace* space);
+ };
+};
+
+class ICGetProp_ArgumentsLength : public ICStub
+{
+ friend class ICStubSpace;
+ public:
+ enum Which { Magic };
+
+ protected:
+ explicit ICGetProp_ArgumentsLength(JitCode* stubCode)
+ : ICStub(ICStub::GetProp_ArgumentsLength, stubCode)
+ { }
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ Which which_;
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(which_) << 17);
+ }
+
+ public:
+ Compiler(JSContext* cx, Engine engine, Which which)
+ : ICStubCompiler(cx, ICStub::GetProp_ArgumentsLength, engine),
+ which_(which)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetProp_ArgumentsLength>(space, getStubCode());
+ }
+ };
+};
+
+class ICGetProp_ArgumentsCallee : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ ICGetProp_ArgumentsCallee(JitCode* stubCode, ICStub* firstMonitorStub);
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ ICStub* firstMonitorStub_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, Engine engine, ICStub* firstMonitorStub)
+ : ICStubCompiler(cx, ICStub::GetProp_ArgumentsCallee, engine),
+ firstMonitorStub_(firstMonitorStub)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetProp_ArgumentsCallee>(space, getStubCode(), firstMonitorStub_);
+ }
+ };
+};
+
+// JSOP_NEWARRAY
+// JSOP_NEWINIT
+
+class ICNewArray_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObject templateObject_;
+
+ // The group used for objects created here is always available, even if the
+ // template object itself is not.
+ GCPtrObjectGroup templateGroup_;
+
+ ICNewArray_Fallback(JitCode* stubCode, ObjectGroup* templateGroup)
+ : ICFallbackStub(ICStub::NewArray_Fallback, stubCode),
+ templateObject_(nullptr), templateGroup_(templateGroup)
+ {}
+
+ public:
+ class Compiler : public ICStubCompiler {
+ RootedObjectGroup templateGroup;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, ObjectGroup* templateGroup, Engine engine)
+ : ICStubCompiler(cx, ICStub::NewArray_Fallback, engine),
+ templateGroup(cx, templateGroup)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICNewArray_Fallback>(space, getStubCode(), templateGroup);
+ }
+ };
+
+ GCPtrObject& templateObject() {
+ return templateObject_;
+ }
+
+ void setTemplateObject(JSObject* obj) {
+ MOZ_ASSERT(obj->group() == templateGroup());
+ templateObject_ = obj;
+ }
+
+ GCPtrObjectGroup& templateGroup() {
+ return templateGroup_;
+ }
+
+ void setTemplateGroup(ObjectGroup* group) {
+ templateObject_ = nullptr;
+ templateGroup_ = group;
+ }
+};
+
+// JSOP_NEWOBJECT
+
+class ICNewObject_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObject templateObject_;
+
+ explicit ICNewObject_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(nullptr)
+ {}
+
+ public:
+ class Compiler : public ICStubCompiler {
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx, Engine engine)
+ : ICStubCompiler(cx, ICStub::NewObject_Fallback, engine)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICNewObject_Fallback>(space, getStubCode());
+ }
+ };
+
+ GCPtrObject& templateObject() {
+ return templateObject_;
+ }
+
+ void setTemplateObject(JSObject* obj) {
+ templateObject_ = obj;
+ }
+};
+
+class ICNewObject_WithTemplate : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICNewObject_WithTemplate(JitCode* stubCode)
+ : ICStub(ICStub::NewObject_WithTemplate, stubCode)
+ {}
+};
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_SharedIC_h */