summaryrefslogtreecommitdiffstats
path: root/js/src/jit/BaselineIC.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/BaselineIC.h')
-rw-r--r--js/src/jit/BaselineIC.h3384
1 files changed, 3384 insertions, 0 deletions
diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h
new file mode 100644
index 000000000..a57556d99
--- /dev/null
+++ b/js/src/jit/BaselineIC.h
@@ -0,0 +1,3384 @@
+/* -*- 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
+
+#include "mozilla/Assertions.h"
+
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsgc.h"
+#include "jsopcode.h"
+
+#include "builtin/TypedObject.h"
+#include "gc/Barrier.h"
+#include "jit/BaselineICList.h"
+#include "jit/BaselineJIT.h"
+#include "jit/SharedIC.h"
+#include "jit/SharedICRegisters.h"
+#include "js/GCVector.h"
+#include "vm/ArrayObject.h"
+#include "vm/UnboxedObject.h"
+
+namespace js {
+namespace jit {
+
+// WarmUpCounter_Fallback
+
+// A WarmUpCounter IC chain has only the fallback stub.
+class ICWarmUpCounter_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICWarmUpCounter_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::WarmUpCounter_Fallback, stubCode)
+ { }
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::WarmUpCounter_Fallback, Engine::Baseline)
+ { }
+
+ ICWarmUpCounter_Fallback* getStub(ICStubSpace* space) {
+ return newStub<ICWarmUpCounter_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+
+// 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;
+
+ explicit ICTypeUpdate_Fallback(JitCode* stubCode)
+ : ICStub(ICStub::TypeUpdate_Fallback, stubCode)
+ {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::TypeUpdate_Fallback, Engine::Baseline)
+ { }
+
+ ICTypeUpdate_Fallback* getStub(ICStubSpace* space) {
+ return newStub<ICTypeUpdate_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+class ICTypeUpdate_PrimitiveSet : public TypeCheckPrimitiveSetStub
+{
+ friend class ICStubSpace;
+
+ ICTypeUpdate_PrimitiveSet(JitCode* stubCode, uint16_t flags)
+ : TypeCheckPrimitiveSetStub(TypeUpdate_PrimitiveSet, stubCode, flags)
+ {}
+
+ public:
+ class Compiler : public TypeCheckPrimitiveSetStub::Compiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, ICTypeUpdate_PrimitiveSet* existingStub, JSValueType type)
+ : TypeCheckPrimitiveSetStub::Compiler(cx, TypeUpdate_PrimitiveSet,
+ Engine::Baseline, existingStub, type)
+ {}
+
+ ICTypeUpdate_PrimitiveSet* updateStub() {
+ TypeCheckPrimitiveSetStub* stub =
+ this->TypeCheckPrimitiveSetStub::Compiler::updateStub();
+ if (!stub)
+ return nullptr;
+ return stub->toUpdateStub();
+ }
+
+ ICTypeUpdate_PrimitiveSet* getStub(ICStubSpace* space) {
+ MOZ_ASSERT(!existingStub_);
+ return newStub<ICTypeUpdate_PrimitiveSet>(space, getStubCode(), flags_);
+ }
+ };
+};
+
+// Type update stub to handle a singleton object.
+class ICTypeUpdate_SingleObject : public ICStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObject obj_;
+
+ ICTypeUpdate_SingleObject(JitCode* stubCode, JSObject* obj);
+
+ public:
+ GCPtrObject& object() {
+ return obj_;
+ }
+
+ static size_t offsetOfObject() {
+ return offsetof(ICTypeUpdate_SingleObject, obj_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ HandleObject obj_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, HandleObject obj)
+ : ICStubCompiler(cx, TypeUpdate_SingleObject, Engine::Baseline),
+ obj_(obj)
+ { }
+
+ ICTypeUpdate_SingleObject* getStub(ICStubSpace* space) {
+ return newStub<ICTypeUpdate_SingleObject>(space, getStubCode(), obj_);
+ }
+ };
+};
+
+// Type update stub to handle a single ObjectGroup.
+class ICTypeUpdate_ObjectGroup : public ICStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObjectGroup group_;
+
+ ICTypeUpdate_ObjectGroup(JitCode* stubCode, ObjectGroup* group);
+
+ public:
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+
+ static size_t offsetOfGroup() {
+ return offsetof(ICTypeUpdate_ObjectGroup, group_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ HandleObjectGroup group_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, HandleObjectGroup group)
+ : ICStubCompiler(cx, TypeUpdate_ObjectGroup, Engine::Baseline),
+ group_(group)
+ { }
+
+ ICTypeUpdate_ObjectGroup* getStub(ICStubSpace* space) {
+ return newStub<ICTypeUpdate_ObjectGroup>(space, getStubCode(), group_);
+ }
+ };
+};
+
+// ToBool
+// JSOP_IFNE
+
+class ICToBool_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICToBool_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::ToBool_Fallback, stubCode) {}
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::ToBool_Fallback, Engine::Baseline) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICToBool_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+class ICToBool_Int32 : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICToBool_Int32(JitCode* stubCode)
+ : ICStub(ICStub::ToBool_Int32, stubCode) {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::ToBool_Int32, Engine::Baseline) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICToBool_Int32>(space, getStubCode());
+ }
+ };
+};
+
+class ICToBool_String : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICToBool_String(JitCode* stubCode)
+ : ICStub(ICStub::ToBool_String, stubCode) {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::ToBool_String, Engine::Baseline) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICToBool_String>(space, getStubCode());
+ }
+ };
+};
+
+class ICToBool_NullUndefined : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICToBool_NullUndefined(JitCode* stubCode)
+ : ICStub(ICStub::ToBool_NullUndefined, stubCode) {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::ToBool_NullUndefined, Engine::Baseline) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICToBool_NullUndefined>(space, getStubCode());
+ }
+ };
+};
+
+class ICToBool_Double : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICToBool_Double(JitCode* stubCode)
+ : ICStub(ICStub::ToBool_Double, stubCode) {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::ToBool_Double, Engine::Baseline) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICToBool_Double>(space, getStubCode());
+ }
+ };
+};
+
+class ICToBool_Object : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICToBool_Object(JitCode* stubCode)
+ : ICStub(ICStub::ToBool_Object, stubCode) {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::ToBool_Object, Engine::Baseline) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICToBool_Object>(space, getStubCode());
+ }
+ };
+};
+
+// ToNumber
+// JSOP_POS
+
+class ICToNumber_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICToNumber_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::ToNumber_Fallback, stubCode) {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::ToNumber_Fallback, Engine::Baseline) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICToNumber_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+// GetElem
+// JSOP_GETELEM
+
+class ICGetElem_Fallback : public ICMonitoredFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICGetElem_Fallback(JitCode* stubCode)
+ : ICMonitoredFallbackStub(ICStub::GetElem_Fallback, stubCode)
+ { }
+
+ static const uint16_t EXTRA_NON_NATIVE = 0x1;
+ static const uint16_t EXTRA_NEGATIVE_INDEX = 0x2;
+ static const uint16_t EXTRA_UNOPTIMIZABLE_ACCESS = 0x4;
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 16;
+
+ 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;
+ }
+ void noteUnoptimizableAccess() {
+ extra_ |= EXTRA_UNOPTIMIZABLE_ACCESS;
+ }
+ bool hadUnoptimizableAccess() const {
+ return extra_ & EXTRA_UNOPTIMIZABLE_ACCESS;
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::GetElem_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ ICGetElem_Fallback* stub = newStub<ICGetElem_Fallback>(space, getStubCode());
+ if (!stub)
+ return nullptr;
+ if (!stub->initMonitoringChain(cx, space, engine_))
+ return nullptr;
+ return stub;
+ }
+ };
+};
+
+class ICGetElemNativeStub : public ICMonitoredStub
+{
+ public:
+ enum AccessType { FixedSlot = 0, DynamicSlot, UnboxedProperty, NativeGetter, ScriptedGetter, NumAccessTypes };
+
+ protected:
+ HeapReceiverGuard receiverGuard_;
+
+ static const unsigned NEEDS_ATOMIZE_SHIFT = 0;
+ static const uint16_t NEEDS_ATOMIZE_MASK = 0x1;
+
+ static const unsigned ACCESSTYPE_SHIFT = 1;
+ static const uint16_t ACCESSTYPE_MASK = 0x7;
+
+ static const unsigned ISSYMBOL_SHIFT = 4;
+ static const uint16_t ISSYMBOL_MASK = 0x1;
+
+ static_assert(ACCESSTYPE_MASK >= NumAccessTypes, "ACCESSTYPE_MASK must cover all possible AccessType values");
+
+ ICGetElemNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, AccessType acctype, bool needsAtomize, bool isSymbol);
+
+ ~ICGetElemNativeStub();
+
+ public:
+ HeapReceiverGuard& receiverGuard() {
+ return receiverGuard_;
+ }
+ static size_t offsetOfReceiverGuard() {
+ return offsetof(ICGetElemNativeStub, receiverGuard_);
+ }
+
+ AccessType accessType() const {
+ return static_cast<AccessType>((extra_ >> ACCESSTYPE_SHIFT) & ACCESSTYPE_MASK);
+ }
+
+ bool needsAtomize() const {
+ return (extra_ >> NEEDS_ATOMIZE_SHIFT) & NEEDS_ATOMIZE_MASK;
+ }
+
+ bool isSymbol() const {
+ return (extra_ >> ISSYMBOL_SHIFT) & ISSYMBOL_MASK;
+ }
+};
+
+template <class T>
+class ICGetElemNativeStubImpl : public ICGetElemNativeStub
+{
+ protected:
+ GCPtr<T> key_;
+
+ ICGetElemNativeStubImpl(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, const T* key, AccessType acctype, bool needsAtomize)
+ : ICGetElemNativeStub(kind, stubCode, firstMonitorStub, guard, acctype, needsAtomize,
+ mozilla::IsSame<T, JS::Symbol*>::value),
+ key_(*key)
+ {}
+
+ public:
+ GCPtr<T>& key() {
+ return key_;
+ }
+ static size_t offsetOfKey() {
+ return offsetof(ICGetElemNativeStubImpl, key_);
+ }
+};
+
+typedef ICGetElemNativeStub::AccessType AccType;
+
+template <class T>
+class ICGetElemNativeSlotStub : public ICGetElemNativeStubImpl<T>
+{
+ protected:
+ uint32_t offset_;
+
+ ICGetElemNativeSlotStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
+ uint32_t offset)
+ : ICGetElemNativeStubImpl<T>(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize),
+ offset_(offset)
+ {
+ MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName ||
+ kind == ICStub::GetElem_NativeSlotSymbol ||
+ kind == ICStub::GetElem_NativePrototypeSlotName ||
+ kind == ICStub::GetElem_NativePrototypeSlotSymbol ||
+ kind == ICStub::GetElem_UnboxedPropertyName);
+ MOZ_ASSERT(acctype == ICGetElemNativeStub::FixedSlot ||
+ acctype == ICGetElemNativeStub::DynamicSlot ||
+ acctype == ICGetElemNativeStub::UnboxedProperty);
+ }
+
+ public:
+ uint32_t offset() const {
+ return offset_;
+ }
+
+ static size_t offsetOfOffset() {
+ return offsetof(ICGetElemNativeSlotStub, offset_);
+ }
+};
+
+template <class T>
+class ICGetElemNativeGetterStub : public ICGetElemNativeStubImpl<T>
+{
+ protected:
+ GCPtrFunction getter_;
+ uint32_t pcOffset_;
+
+ ICGetElemNativeGetterStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
+ JSFunction* getter, uint32_t pcOffset);
+
+ public:
+ GCPtrFunction& getter() {
+ return getter_;
+ }
+ static size_t offsetOfGetter() {
+ return offsetof(ICGetElemNativeGetterStub, getter_);
+ }
+
+ static size_t offsetOfPCOffset() {
+ return offsetof(ICGetElemNativeGetterStub, pcOffset_);
+ }
+};
+
+template <class T>
+ICStub::Kind
+getGetElemStubKind(ICStub::Kind kind)
+{
+ MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName ||
+ kind == ICStub::GetElem_NativePrototypeSlotName ||
+ kind == ICStub::GetElem_NativePrototypeCallNativeName ||
+ kind == ICStub::GetElem_NativePrototypeCallScriptedName);
+ return static_cast<ICStub::Kind>(kind + mozilla::IsSame<T, JS::Symbol*>::value);
+}
+
+template <class T>
+class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub<T>
+{
+ friend class ICStubSpace;
+ ICGetElem_NativeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
+ const T* key, AccType acctype, bool needsAtomize, uint32_t offset)
+ : ICGetElemNativeSlotStub<T>(getGetElemStubKind<T>(ICStub::GetElem_NativeSlotName),
+ stubCode, firstMonitorStub, guard,
+ key, acctype, needsAtomize, offset)
+ {}
+};
+
+class ICGetElem_NativeSlotName :
+ public ICGetElem_NativeSlot<PropertyName*>
+{};
+class ICGetElem_NativeSlotSymbol :
+ public ICGetElem_NativeSlot<JS::Symbol*>
+{};
+
+template <class T>
+class ICGetElem_UnboxedProperty : public ICGetElemNativeSlotStub<T>
+{
+ friend class ICStubSpace;
+ ICGetElem_UnboxedProperty(JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, const T* key, AccType acctype,
+ bool needsAtomize, uint32_t offset)
+ : ICGetElemNativeSlotStub<T>(ICStub::GetElem_UnboxedPropertyName, stubCode, firstMonitorStub,
+ guard, key, acctype, needsAtomize, offset)
+ {}
+};
+
+class ICGetElem_UnboxedPropertyName :
+ public ICGetElem_UnboxedProperty<PropertyName*>
+{};
+
+template <class T>
+class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub<T>
+{
+ friend class ICStubSpace;
+ GCPtrObject holder_;
+ GCPtrShape holderShape_;
+
+ ICGetElem_NativePrototypeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
+ const T* key, AccType acctype, bool needsAtomize, uint32_t offset,
+ JSObject* holder, Shape* holderShape);
+
+ public:
+ GCPtrObject& holder() {
+ return holder_;
+ }
+ static size_t offsetOfHolder() {
+ return offsetof(ICGetElem_NativePrototypeSlot, holder_);
+ }
+
+ GCPtrShape& holderShape() {
+ return holderShape_;
+ }
+ static size_t offsetOfHolderShape() {
+ return offsetof(ICGetElem_NativePrototypeSlot, holderShape_);
+ }
+};
+
+class ICGetElem_NativePrototypeSlotName :
+ public ICGetElem_NativePrototypeSlot<PropertyName*>
+{};
+class ICGetElem_NativePrototypeSlotSymbol :
+ public ICGetElem_NativePrototypeSlot<JS::Symbol*>
+{};
+
+template <class T>
+class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub<T>
+{
+ friend class ICStubSpace;
+ GCPtrObject holder_;
+ GCPtrShape holderShape_;
+
+ protected:
+ ICGetElemNativePrototypeCallStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, const T* key, AccType acctype,
+ bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
+ JSObject* holder, Shape* holderShape);
+
+ public:
+ GCPtrObject& holder() {
+ return holder_;
+ }
+ static size_t offsetOfHolder() {
+ return offsetof(ICGetElemNativePrototypeCallStub, holder_);
+ }
+
+ GCPtrShape& holderShape() {
+ return holderShape_;
+ }
+ static size_t offsetOfHolderShape() {
+ return offsetof(ICGetElemNativePrototypeCallStub, holderShape_);
+ }
+};
+
+template <class T>
+class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub<T>
+{
+ friend class ICStubSpace;
+
+ ICGetElem_NativePrototypeCallNative(JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, const T* key, AccType acctype,
+ bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
+ JSObject* holder, Shape* holderShape)
+ : ICGetElemNativePrototypeCallStub<T>(getGetElemStubKind<T>(
+ ICStub::GetElem_NativePrototypeCallNativeName),
+ stubCode, firstMonitorStub, guard, key,
+ acctype, needsAtomize, getter, pcOffset, holder,
+ holderShape)
+ {}
+
+ public:
+ static ICGetElem_NativePrototypeCallNative<T>* Clone(JSContext* cx, ICStubSpace* space,
+ ICStub* firstMonitorStub,
+ ICGetElem_NativePrototypeCallNative<T>& other);
+};
+
+class ICGetElem_NativePrototypeCallNativeName :
+ public ICGetElem_NativePrototypeCallNative<PropertyName*>
+{};
+class ICGetElem_NativePrototypeCallNativeSymbol :
+ public ICGetElem_NativePrototypeCallNative<JS::Symbol*>
+{};
+
+template <class T>
+class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub<T>
+{
+ friend class ICStubSpace;
+
+ ICGetElem_NativePrototypeCallScripted(JitCode* stubCode, ICStub* firstMonitorStub,
+ ReceiverGuard guard, const T* key, AccType acctype,
+ bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
+ JSObject* holder, Shape* holderShape)
+ : ICGetElemNativePrototypeCallStub<T>(getGetElemStubKind<T>(
+ ICStub::GetElem_NativePrototypeCallScriptedName),
+ stubCode, firstMonitorStub, guard, key, acctype,
+ needsAtomize, getter, pcOffset, holder, holderShape)
+ {}
+
+ public:
+ static ICGetElem_NativePrototypeCallScripted<T>*
+ Clone(JSContext* cx, ICStubSpace* space,
+ ICStub* firstMonitorStub,
+ ICGetElem_NativePrototypeCallScripted<T>& other);
+};
+
+class ICGetElem_NativePrototypeCallScriptedName :
+ public ICGetElem_NativePrototypeCallScripted<PropertyName*>
+{};
+class ICGetElem_NativePrototypeCallScriptedSymbol :
+ public ICGetElem_NativePrototypeCallScripted<JS::Symbol*>
+{};
+
+// Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs.
+template <class T>
+class ICGetElemNativeCompiler : public ICStubCompiler
+{
+ ICStub* firstMonitorStub_;
+ HandleObject obj_;
+ HandleObject holder_;
+ Handle<T> key_;
+ AccType acctype_;
+ bool needsAtomize_;
+ uint32_t offset_;
+ JSValueType unboxedType_;
+ HandleFunction getter_;
+ uint32_t pcOffset_;
+
+ MOZ_MUST_USE bool emitCheckKey(MacroAssembler& masm, Label& failure);
+ MOZ_MUST_USE bool emitCallNative(MacroAssembler& masm, Register objReg);
+ MOZ_MUST_USE bool emitCallScripted(MacroAssembler& masm, Register objReg);
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ protected:
+ virtual int32_t getKey() const {
+ MOZ_ASSERT(static_cast<int32_t>(acctype_) <= 7);
+ MOZ_ASSERT(static_cast<int32_t>(unboxedType_) <= 15);
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(needsAtomize_) << 17) |
+ (static_cast<int32_t>(acctype_) << 18) |
+ (static_cast<int32_t>(unboxedType_) << 21) |
+ (static_cast<int32_t>(mozilla::IsSame<JS::Symbol*, T>::value) << 25) |
+ (HeapReceiverGuard::keyBits(obj_) << 26);
+ }
+
+ public:
+ ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub,
+ HandleObject obj, HandleObject holder, Handle<T> key, AccType acctype,
+ bool needsAtomize, uint32_t offset,
+ JSValueType unboxedType = JSVAL_TYPE_MAGIC)
+ : ICStubCompiler(cx, kind, Engine::Baseline),
+ firstMonitorStub_(firstMonitorStub),
+ obj_(obj),
+ holder_(holder),
+ key_(key),
+ acctype_(acctype),
+ needsAtomize_(needsAtomize),
+ offset_(offset),
+ unboxedType_(unboxedType),
+ getter_(nullptr),
+ pcOffset_(0)
+ {}
+
+ ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub,
+ HandleObject obj, HandleObject holder, Handle<T> key, AccType acctype,
+ bool needsAtomize, HandleFunction getter, uint32_t pcOffset)
+ : ICStubCompiler(cx, kind, Engine::Baseline),
+ firstMonitorStub_(firstMonitorStub),
+ obj_(obj),
+ holder_(holder),
+ key_(key),
+ acctype_(acctype),
+ needsAtomize_(needsAtomize),
+ offset_(0),
+ unboxedType_(JSVAL_TYPE_MAGIC),
+ getter_(getter),
+ pcOffset_(pcOffset)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ RootedReceiverGuard guard(cx, ReceiverGuard(obj_));
+ if (kind == ICStub::GetElem_NativeSlotName || kind == ICStub::GetElem_NativeSlotSymbol) {
+ MOZ_ASSERT(obj_ == holder_);
+ return newStub<ICGetElem_NativeSlot<T>>(
+ space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
+ needsAtomize_, offset_);
+ }
+
+ if (kind == ICStub::GetElem_UnboxedPropertyName) {
+ MOZ_ASSERT(obj_ == holder_);
+ return newStub<ICGetElem_UnboxedProperty<T>>(
+ space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
+ needsAtomize_, offset_);
+ }
+
+ MOZ_ASSERT(obj_ != holder_);
+ RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
+ if (kind == ICStub::GetElem_NativePrototypeSlotName ||
+ kind == ICStub::GetElem_NativePrototypeSlotSymbol)
+ {
+ return newStub<ICGetElem_NativePrototypeSlot<T>>(
+ space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
+ needsAtomize_, offset_, holder_, holderShape);
+ }
+
+ if (kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
+ kind == ICStub::GetElem_NativePrototypeCallNativeName) {
+ return newStub<ICGetElem_NativePrototypeCallNative<T>>(
+ space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
+ needsAtomize_, getter_, pcOffset_, holder_, holderShape);
+ }
+
+ MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
+ kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol);
+ if (kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
+ kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol) {
+ return newStub<ICGetElem_NativePrototypeCallScripted<T>>(
+ space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
+ needsAtomize_, getter_, pcOffset_, holder_, holderShape);
+ }
+
+ MOZ_CRASH("Invalid kind.");
+ }
+};
+
+class ICGetElem_String : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICGetElem_String(JitCode* stubCode)
+ : ICStub(ICStub::GetElem_String, stubCode) {}
+
+ public:
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::GetElem_String, Engine::Baseline) {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetElem_String>(space, getStubCode());
+ }
+ };
+};
+
+class ICGetElem_Dense : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ GCPtrShape shape_;
+
+ ICGetElem_Dense(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape);
+
+ public:
+ static ICGetElem_Dense* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICGetElem_Dense& other);
+
+ static size_t offsetOfShape() {
+ return offsetof(ICGetElem_Dense, shape_);
+ }
+
+ GCPtrShape& shape() {
+ return shape_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ ICStub* firstMonitorStub_;
+ RootedShape shape_;
+
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub, Shape* shape)
+ : ICStubCompiler(cx, ICStub::GetElem_Dense, Engine::Baseline),
+ firstMonitorStub_(firstMonitorStub),
+ shape_(cx, shape)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetElem_Dense>(space, getStubCode(), firstMonitorStub_, shape_);
+ }
+ };
+};
+
+class ICGetElem_UnboxedArray : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObjectGroup group_;
+
+ ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub, ObjectGroup* group);
+
+ public:
+ static ICGetElem_UnboxedArray* Clone(JSContext* cx, ICStubSpace* space,
+ ICStub* firstMonitorStub, ICGetElem_UnboxedArray& other);
+
+ static size_t offsetOfGroup() {
+ return offsetof(ICGetElem_UnboxedArray, group_);
+ }
+
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ ICStub* firstMonitorStub_;
+ RootedObjectGroup group_;
+ JSValueType elementType_;
+
+ protected:
+ 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>(elementType_) << 17);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub, ObjectGroup* group)
+ : ICStubCompiler(cx, ICStub::GetElem_UnboxedArray, Engine::Baseline),
+ firstMonitorStub_(firstMonitorStub),
+ group_(cx, group),
+ elementType_(group->unboxedLayoutDontCheckGeneration().elementType())
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetElem_UnboxedArray>(space, getStubCode(), firstMonitorStub_, group_);
+ }
+ };
+};
+
+// Accesses scalar elements of a typed array or typed object.
+class ICGetElem_TypedArray : public ICStub
+{
+ friend class ICStubSpace;
+
+ protected: // Protected to silence Clang warning.
+ GCPtrShape shape_;
+
+ ICGetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type);
+
+ public:
+ static size_t offsetOfShape() {
+ return offsetof(ICGetElem_TypedArray, shape_);
+ }
+
+ GCPtrShape& shape() {
+ return shape_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ RootedShape shape_;
+ Scalar::Type type_;
+ TypedThingLayout layout_;
+
+ protected:
+ 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>(type_) << 17) |
+ (static_cast<int32_t>(layout_) << 25);
+ }
+
+ public:
+ Compiler(JSContext* cx, Shape* shape, Scalar::Type type)
+ : ICStubCompiler(cx, ICStub::GetElem_TypedArray, Engine::Baseline),
+ shape_(cx, shape),
+ type_(type),
+ layout_(GetTypedThingLayout(shape->getObjectClass()))
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetElem_TypedArray>(space, getStubCode(), shape_, type_);
+ }
+ };
+};
+
+class ICGetElem_Arguments : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+ public:
+ enum Which { Mapped, Unmapped, Magic };
+
+ private:
+ ICGetElem_Arguments(JitCode* stubCode, ICStub* firstMonitorStub, Which which)
+ : ICMonitoredStub(ICStub::GetElem_Arguments, stubCode, firstMonitorStub)
+ {
+ extra_ = static_cast<uint16_t>(which);
+ }
+
+ public:
+ static ICGetElem_Arguments* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICGetElem_Arguments& other);
+
+ Which which() const {
+ return static_cast<Which>(extra_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ ICStub* firstMonitorStub_;
+ Which which_;
+
+ protected:
+ 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, ICStub* firstMonitorStub, Which which)
+ : ICStubCompiler(cx, ICStub::GetElem_Arguments, Engine::Baseline),
+ firstMonitorStub_(firstMonitorStub),
+ which_(which)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetElem_Arguments>(space, getStubCode(), firstMonitorStub_, which_);
+ }
+ };
+};
+
+// SetElem
+// JSOP_SETELEM
+// JSOP_INITELEM
+
+class ICSetElem_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICSetElem_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::SetElem_Fallback, stubCode)
+ { }
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ void noteArrayWriteHole() {
+ extra_ = 1;
+ }
+ bool hasArrayWriteHole() const {
+ return extra_;
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::SetElem_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICSetElem_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+class ICSetElem_DenseOrUnboxedArray : public ICUpdatedStub
+{
+ friend class ICStubSpace;
+
+ GCPtrShape shape_; // null for unboxed arrays
+ GCPtrObjectGroup group_;
+
+ ICSetElem_DenseOrUnboxedArray(JitCode* stubCode, Shape* shape, ObjectGroup* group);
+
+ public:
+ static size_t offsetOfShape() {
+ return offsetof(ICSetElem_DenseOrUnboxedArray, shape_);
+ }
+ static size_t offsetOfGroup() {
+ return offsetof(ICSetElem_DenseOrUnboxedArray, group_);
+ }
+
+ GCPtrShape& shape() {
+ return shape_;
+ }
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ RootedShape shape_;
+ RootedObjectGroup group_;
+ JSValueType unboxedType_;
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(unboxedType_) << 17);
+ }
+
+ Compiler(JSContext* cx, Shape* shape, HandleObjectGroup group)
+ : ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArray, Engine::Baseline),
+ shape_(cx, shape),
+ group_(cx, group),
+ unboxedType_(shape
+ ? JSVAL_TYPE_MAGIC
+ : group->unboxedLayoutDontCheckGeneration().elementType())
+ {}
+
+ ICUpdatedStub* getStub(ICStubSpace* space) {
+ ICSetElem_DenseOrUnboxedArray* stub =
+ newStub<ICSetElem_DenseOrUnboxedArray>(space, getStubCode(), shape_, group_);
+ if (!stub || !stub->initUpdatingChain(cx, space))
+ return nullptr;
+ return stub;
+ }
+
+ bool needsUpdateStubs() {
+ return unboxedType_ == JSVAL_TYPE_MAGIC || unboxedType_ == JSVAL_TYPE_OBJECT;
+ }
+ };
+};
+
+template <size_t ProtoChainDepth> class ICSetElem_DenseOrUnboxedArrayAddImpl;
+
+class ICSetElem_DenseOrUnboxedArrayAdd : public ICUpdatedStub
+{
+ friend class ICStubSpace;
+
+ public:
+ static const size_t MAX_PROTO_CHAIN_DEPTH = 4;
+
+ protected:
+ GCPtrObjectGroup group_;
+
+ ICSetElem_DenseOrUnboxedArrayAdd(JitCode* stubCode, ObjectGroup* group, size_t protoChainDepth);
+
+ public:
+ static size_t offsetOfGroup() {
+ return offsetof(ICSetElem_DenseOrUnboxedArrayAdd, group_);
+ }
+
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+ size_t protoChainDepth() const {
+ MOZ_ASSERT(extra_ <= MAX_PROTO_CHAIN_DEPTH);
+ return extra_;
+ }
+
+ template <size_t ProtoChainDepth>
+ ICSetElem_DenseOrUnboxedArrayAddImpl<ProtoChainDepth>* toImplUnchecked() {
+ return static_cast<ICSetElem_DenseOrUnboxedArrayAddImpl<ProtoChainDepth>*>(this);
+ }
+
+ template <size_t ProtoChainDepth>
+ ICSetElem_DenseOrUnboxedArrayAddImpl<ProtoChainDepth>* toImpl() {
+ MOZ_ASSERT(ProtoChainDepth == protoChainDepth());
+ return toImplUnchecked<ProtoChainDepth>();
+ }
+};
+
+template <size_t ProtoChainDepth>
+class ICSetElem_DenseOrUnboxedArrayAddImpl : public ICSetElem_DenseOrUnboxedArrayAdd
+{
+ friend class ICStubSpace;
+
+ // Note: for unboxed arrays, the first shape is null.
+ static const size_t NumShapes = ProtoChainDepth + 1;
+ mozilla::Array<GCPtrShape, NumShapes> shapes_;
+
+ ICSetElem_DenseOrUnboxedArrayAddImpl(JitCode* stubCode, ObjectGroup* group,
+ Handle<ShapeVector> shapes)
+ : ICSetElem_DenseOrUnboxedArrayAdd(stubCode, group, ProtoChainDepth)
+ {
+ MOZ_ASSERT(shapes.length() == NumShapes);
+ for (size_t i = 0; i < NumShapes; i++)
+ shapes_[i].init(shapes[i]);
+ }
+
+ public:
+ void traceShapes(JSTracer* trc) {
+ for (size_t i = 0; i < NumShapes; i++)
+ TraceNullableEdge(trc, &shapes_[i], "baseline-setelem-denseadd-stub-shape");
+ }
+ Shape* shape(size_t i) const {
+ MOZ_ASSERT(i < NumShapes);
+ return shapes_[i];
+ }
+ static size_t offsetOfShape(size_t idx) {
+ return offsetof(ICSetElem_DenseOrUnboxedArrayAddImpl, shapes_) + idx * sizeof(GCPtrShape);
+ }
+};
+
+class ICSetElemDenseOrUnboxedArrayAddCompiler : public ICStubCompiler {
+ RootedObject obj_;
+ size_t protoChainDepth_;
+ JSValueType unboxedType_;
+
+ 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>(protoChainDepth_) << 17) |
+ (static_cast<int32_t>(unboxedType_) << 20);
+ }
+
+ public:
+ ICSetElemDenseOrUnboxedArrayAddCompiler(JSContext* cx, HandleObject obj, size_t protoChainDepth)
+ : ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArrayAdd, Engine::Baseline),
+ obj_(cx, obj),
+ protoChainDepth_(protoChainDepth),
+ unboxedType_(obj->is<UnboxedArrayObject>()
+ ? obj->as<UnboxedArrayObject>().elementType()
+ : JSVAL_TYPE_MAGIC)
+ {}
+
+ template <size_t ProtoChainDepth>
+ ICUpdatedStub* getStubSpecific(ICStubSpace* space, Handle<ShapeVector> shapes);
+
+ ICUpdatedStub* getStub(ICStubSpace* space);
+
+ bool needsUpdateStubs() {
+ return unboxedType_ == JSVAL_TYPE_MAGIC || unboxedType_ == JSVAL_TYPE_OBJECT;
+ }
+};
+
+// Accesses scalar elements of a typed array or typed object.
+class ICSetElem_TypedArray : public ICStub
+{
+ friend class ICStubSpace;
+
+ protected: // Protected to silence Clang warning.
+ GCPtrShape shape_;
+
+ ICSetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type,
+ bool expectOutOfBounds);
+
+ public:
+ Scalar::Type type() const {
+ return (Scalar::Type) (extra_ & 0xff);
+ }
+
+ bool expectOutOfBounds() const {
+ return (extra_ >> 8) & 1;
+ }
+
+ static size_t offsetOfShape() {
+ return offsetof(ICSetElem_TypedArray, shape_);
+ }
+
+ GCPtrShape& shape() {
+ return shape_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ RootedShape shape_;
+ Scalar::Type type_;
+ TypedThingLayout layout_;
+ bool expectOutOfBounds_;
+
+ protected:
+ 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>(type_) << 17) |
+ (static_cast<int32_t>(layout_) << 25) |
+ (static_cast<int32_t>(expectOutOfBounds_) << 29);
+ }
+
+ public:
+ Compiler(JSContext* cx, Shape* shape, Scalar::Type type, bool expectOutOfBounds)
+ : ICStubCompiler(cx, ICStub::SetElem_TypedArray, Engine::Baseline),
+ shape_(cx, shape),
+ type_(type),
+ layout_(GetTypedThingLayout(shape->getObjectClass())),
+ expectOutOfBounds_(expectOutOfBounds)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICSetElem_TypedArray>(space, getStubCode(), shape_, type_,
+ expectOutOfBounds_);
+ }
+ };
+};
+
+// In
+// JSOP_IN
+class ICIn_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICIn_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::In_Fallback, stubCode)
+ { }
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::In_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICIn_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+// Base class for In_Native and In_NativePrototype stubs.
+class ICInNativeStub : public ICStub
+{
+ GCPtrShape shape_;
+ GCPtrPropertyName name_;
+
+ protected:
+ ICInNativeStub(ICStub::Kind kind, JitCode* stubCode, HandleShape shape,
+ HandlePropertyName name);
+
+ public:
+ GCPtrShape& shape() {
+ return shape_;
+ }
+ static size_t offsetOfShape() {
+ return offsetof(ICInNativeStub, shape_);
+ }
+
+ GCPtrPropertyName& name() {
+ return name_;
+ }
+ static size_t offsetOfName() {
+ return offsetof(ICInNativeStub, name_);
+ }
+};
+
+// Stub for confirming an own property on a native object.
+class ICIn_Native : public ICInNativeStub
+{
+ friend class ICStubSpace;
+
+ ICIn_Native(JitCode* stubCode, HandleShape shape, HandlePropertyName name)
+ : ICInNativeStub(In_Native, stubCode, shape, name)
+ {}
+};
+
+// Stub for confirming 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 ICIn_NativePrototype : public ICInNativeStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObject holder_;
+ GCPtrShape holderShape_;
+
+ ICIn_NativePrototype(JitCode* stubCode, HandleShape shape, HandlePropertyName name,
+ HandleObject holder, HandleShape holderShape);
+
+ public:
+ GCPtrObject& holder() {
+ return holder_;
+ }
+ GCPtrShape& holderShape() {
+ return holderShape_;
+ }
+ static size_t offsetOfHolder() {
+ return offsetof(ICIn_NativePrototype, holder_);
+ }
+ static size_t offsetOfHolderShape() {
+ return offsetof(ICIn_NativePrototype, holderShape_);
+ }
+};
+
+// Compiler for In_Native and In_NativePrototype stubs.
+class ICInNativeCompiler : public ICStubCompiler
+{
+ RootedObject obj_;
+ RootedObject holder_;
+ RootedPropertyName name_;
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ ICInNativeCompiler(JSContext* cx, ICStub::Kind kind, HandleObject obj, HandleObject holder,
+ HandlePropertyName name)
+ : ICStubCompiler(cx, kind, Engine::Baseline),
+ obj_(cx, obj),
+ holder_(cx, holder),
+ name_(cx, name)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ RootedShape shape(cx, obj_->as<NativeObject>().lastProperty());
+ if (kind == ICStub::In_Native) {
+ MOZ_ASSERT(obj_ == holder_);
+ return newStub<ICIn_Native>(space, getStubCode(), shape, name_);
+ }
+
+ MOZ_ASSERT(obj_ != holder_);
+ MOZ_ASSERT(kind == ICStub::In_NativePrototype);
+ RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
+ return newStub<ICIn_NativePrototype>(space, getStubCode(), shape, name_, holder_,
+ holderShape);
+ }
+};
+
+template <size_t ProtoChainDepth> class ICIn_NativeDoesNotExistImpl;
+
+class ICIn_NativeDoesNotExist : public ICStub
+{
+ friend class ICStubSpace;
+
+ GCPtrPropertyName name_;
+
+ public:
+ static const size_t MAX_PROTO_CHAIN_DEPTH = 8;
+
+ protected:
+ ICIn_NativeDoesNotExist(JitCode* stubCode, size_t protoChainDepth,
+ HandlePropertyName name);
+
+ public:
+ size_t protoChainDepth() const {
+ MOZ_ASSERT(extra_ <= MAX_PROTO_CHAIN_DEPTH);
+ return extra_;
+ }
+ GCPtrPropertyName& name() {
+ return name_;
+ }
+
+ template <size_t ProtoChainDepth>
+ ICIn_NativeDoesNotExistImpl<ProtoChainDepth>* toImpl() {
+ MOZ_ASSERT(ProtoChainDepth == protoChainDepth());
+ return static_cast<ICIn_NativeDoesNotExistImpl<ProtoChainDepth>*>(this);
+ }
+
+ static size_t offsetOfShape(size_t idx);
+ static size_t offsetOfName() {
+ return offsetof(ICIn_NativeDoesNotExist, name_);
+ }
+};
+
+template <size_t ProtoChainDepth>
+class ICIn_NativeDoesNotExistImpl : public ICIn_NativeDoesNotExist
+{
+ friend class ICStubSpace;
+
+ public:
+ static const size_t MAX_PROTO_CHAIN_DEPTH = 8;
+ static const size_t NumShapes = ProtoChainDepth + 1;
+
+ private:
+ mozilla::Array<GCPtrShape, NumShapes> shapes_;
+
+ ICIn_NativeDoesNotExistImpl(JitCode* stubCode, Handle<ShapeVector> shapes,
+ HandlePropertyName name);
+
+ public:
+ void traceShapes(JSTracer* trc) {
+ for (size_t i = 0; i < NumShapes; i++)
+ TraceEdge(trc, &shapes_[i], "baseline-innativedoesnotexist-stub-shape");
+ }
+
+ static size_t offsetOfShape(size_t idx) {
+ return offsetof(ICIn_NativeDoesNotExistImpl, shapes_) + (idx * sizeof(GCPtrShape));
+ }
+};
+
+class ICInNativeDoesNotExistCompiler : public ICStubCompiler
+{
+ RootedObject obj_;
+ RootedPropertyName name_;
+ size_t protoChainDepth_;
+
+ protected:
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(protoChainDepth_) << 17);
+ }
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ ICInNativeDoesNotExistCompiler(JSContext* cx, HandleObject obj, HandlePropertyName name,
+ size_t protoChainDepth);
+
+ template <size_t ProtoChainDepth>
+ ICStub* getStubSpecific(ICStubSpace* space, Handle<ShapeVector> shapes) {
+ return newStub<ICIn_NativeDoesNotExistImpl<ProtoChainDepth>>(space, getStubCode(), shapes,
+ name_);}
+
+ ICStub* getStub(ICStubSpace* space);
+};
+
+class ICIn_Dense : public ICStub
+{
+ friend class ICStubSpace;
+
+ GCPtrShape shape_;
+
+ ICIn_Dense(JitCode* stubCode, HandleShape shape);
+
+ public:
+ GCPtrShape& shape() {
+ return shape_;
+ }
+ static size_t offsetOfShape() {
+ return offsetof(ICIn_Dense, shape_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ RootedShape shape_;
+
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, Shape* shape)
+ : ICStubCompiler(cx, ICStub::In_Dense, Engine::Baseline),
+ shape_(cx, shape)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICIn_Dense>(space, getStubCode(), shape_);
+ }
+ };
+};
+
+// GetName
+// JSOP_GETNAME
+// JSOP_GETGNAME
+class ICGetName_Fallback : public ICMonitoredFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICGetName_Fallback(JitCode* stubCode)
+ : ICMonitoredFallbackStub(ICStub::GetName_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);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::GetName_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ ICGetName_Fallback* stub = newStub<ICGetName_Fallback>(space, getStubCode());
+ if (!stub || !stub->initMonitoringChain(cx, space, engine_))
+ return nullptr;
+ return stub;
+ }
+ };
+};
+
+// Optimized lexical GETGNAME stub.
+class ICGetName_GlobalLexical : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected: // Protected to silence Clang warning.
+ uint32_t slot_;
+
+ ICGetName_GlobalLexical(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t slot);
+
+ public:
+ static size_t offsetOfSlot() {
+ return offsetof(ICGetName_GlobalLexical, slot_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ ICStub* firstMonitorStub_;
+ uint32_t slot_;
+
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub, uint32_t slot)
+ : ICStubCompiler(cx, ICStub::GetName_GlobalLexical, Engine::Baseline),
+ firstMonitorStub_(firstMonitorStub),
+ slot_(slot)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetName_GlobalLexical>(space, getStubCode(), firstMonitorStub_, slot_);
+ }
+ };
+};
+
+// Optimized GETNAME/CALLNAME stub, making a variable number of hops to get an
+// 'own' property off some env 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 env chain.
+template <size_t NumHops>
+class ICGetName_Env : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ static const size_t MAX_HOPS = 6;
+
+ mozilla::Array<GCPtrShape, NumHops + 1> shapes_;
+ uint32_t offset_;
+
+ ICGetName_Env(JitCode* stubCode, ICStub* firstMonitorStub,
+ Handle<ShapeVector> shapes, uint32_t offset);
+
+ static Kind GetStubKind() {
+ return (Kind) (GetName_Env0 + NumHops);
+ }
+
+ public:
+ void traceEnvironments(JSTracer* trc) {
+ for (size_t i = 0; i < NumHops + 1; i++)
+ TraceEdge(trc, &shapes_[i], "baseline-env-stub-shape");
+ }
+
+ static size_t offsetOfShape(size_t index) {
+ MOZ_ASSERT(index <= NumHops);
+ return offsetof(ICGetName_Env, shapes_) + (index * sizeof(GCPtrShape));
+ }
+ static size_t offsetOfOffset() {
+ return offsetof(ICGetName_Env, offset_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ ICStub* firstMonitorStub_;
+ Rooted<ShapeVector> shapes_;
+ bool isFixedSlot_;
+ uint32_t offset_;
+
+ protected:
+ 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);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub,
+ ShapeVector&& shapes, bool isFixedSlot, uint32_t offset)
+ : ICStubCompiler(cx, GetStubKind(), Engine::Baseline),
+ firstMonitorStub_(firstMonitorStub),
+ shapes_(cx, mozilla::Move(shapes)),
+ isFixedSlot_(isFixedSlot),
+ offset_(offset)
+ {
+ }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetName_Env>(space, getStubCode(), firstMonitorStub_, shapes_,
+ offset_);
+ }
+ };
+};
+
+// BindName
+// JSOP_BINDNAME
+class ICBindName_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICBindName_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::BindName_Fallback, stubCode)
+ { }
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::BindName_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICBindName_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+// GetIntrinsic
+// JSOP_GETINTRINSIC
+class ICGetIntrinsic_Fallback : public ICMonitoredFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICGetIntrinsic_Fallback(JitCode* stubCode)
+ : ICMonitoredFallbackStub(ICStub::GetIntrinsic_Fallback, stubCode)
+ { }
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::GetIntrinsic_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ ICGetIntrinsic_Fallback* stub =
+ newStub<ICGetIntrinsic_Fallback>(space, getStubCode());
+ if (!stub || !stub->initMonitoringChain(cx, space, engine_))
+ return nullptr;
+ return stub;
+ }
+ };
+};
+
+// Stub that loads the constant result of a GETINTRINSIC operation.
+class ICGetIntrinsic_Constant : public ICStub
+{
+ friend class ICStubSpace;
+
+ GCPtrValue value_;
+
+ ICGetIntrinsic_Constant(JitCode* stubCode, const Value& value);
+ ~ICGetIntrinsic_Constant();
+
+ public:
+ GCPtrValue& value() {
+ return value_;
+ }
+ static size_t offsetOfValue() {
+ return offsetof(ICGetIntrinsic_Constant, value_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ HandleValue value_;
+
+ public:
+ Compiler(JSContext* cx, HandleValue value)
+ : ICStubCompiler(cx, ICStub::GetIntrinsic_Constant, Engine::Baseline),
+ value_(value)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICGetIntrinsic_Constant>(space, getStubCode(), value_);
+ }
+ };
+};
+
+// SetProp
+// JSOP_SETPROP
+// JSOP_SETNAME
+// JSOP_SETGNAME
+// JSOP_INITPROP
+
+class ICSetProp_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICSetProp_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::SetProp_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);
+ }
+
+ class Compiler : public ICStubCompiler {
+ public:
+ static const int32_t BASELINE_KEY =
+ (static_cast<int32_t>(Engine::Baseline)) |
+ (static_cast<int32_t>(ICStub::SetProp_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)
+ : ICStubCompiler(cx, ICStub::SetProp_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICSetProp_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+// Optimized SETPROP/SETGNAME/SETNAME stub.
+class ICSetProp_Native : public ICUpdatedStub
+{
+ friend class ICStubSpace;
+
+ protected: // Protected to silence Clang warning.
+ GCPtrObjectGroup group_;
+ GCPtrShape shape_;
+ uint32_t offset_;
+
+ ICSetProp_Native(JitCode* stubCode, ObjectGroup* group, Shape* shape, uint32_t offset);
+
+ public:
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+ GCPtrShape& shape() {
+ return shape_;
+ }
+ void notePreliminaryObject() {
+ extra_ = 1;
+ }
+ bool hasPreliminaryObject() const {
+ return extra_;
+ }
+ static size_t offsetOfGroup() {
+ return offsetof(ICSetProp_Native, group_);
+ }
+ 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>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(isFixedSlot_) << 17) |
+ (static_cast<int32_t>(obj_->is<UnboxedPlainObject>()) << 18);
+ }
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, HandleObject obj, bool isFixedSlot, uint32_t offset)
+ : ICStubCompiler(cx, ICStub::SetProp_Native, Engine::Baseline),
+ obj_(cx, obj),
+ isFixedSlot_(isFixedSlot),
+ offset_(offset)
+ {}
+
+ ICSetProp_Native* 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.
+ GCPtrObjectGroup group_;
+ GCPtrShape newShape_;
+ GCPtrObjectGroup newGroup_;
+ uint32_t offset_;
+
+ ICSetProp_NativeAdd(JitCode* stubCode, ObjectGroup* group, size_t protoChainDepth,
+ Shape* newShape, ObjectGroup* newGroup, uint32_t offset);
+
+ public:
+ size_t protoChainDepth() const {
+ return extra_;
+ }
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+ GCPtrShape& newShape() {
+ return newShape_;
+ }
+ GCPtrObjectGroup& newGroup() {
+ return newGroup_;
+ }
+
+ template <size_t ProtoChainDepth>
+ ICSetProp_NativeAddImpl<ProtoChainDepth>* toImpl() {
+ MOZ_ASSERT(ProtoChainDepth == protoChainDepth());
+ return static_cast<ICSetProp_NativeAddImpl<ProtoChainDepth>*>(this);
+ }
+
+ static size_t offsetOfGroup() {
+ return offsetof(ICSetProp_NativeAdd, group_);
+ }
+ static size_t offsetOfNewShape() {
+ return offsetof(ICSetProp_NativeAdd, newShape_);
+ }
+ static size_t offsetOfNewGroup() {
+ return offsetof(ICSetProp_NativeAdd, newGroup_);
+ }
+ 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;
+ mozilla::Array<GCPtrShape, NumShapes> shapes_;
+
+ ICSetProp_NativeAddImpl(JitCode* stubCode, ObjectGroup* group,
+ Handle<ShapeVector> shapes,
+ Shape* newShape, ObjectGroup* newGroup, uint32_t offset);
+
+ public:
+ void traceShapes(JSTracer* trc) {
+ for (size_t i = 0; i < NumShapes; i++)
+ TraceEdge(trc, &shapes_[i], "baseline-setpropnativeadd-stub-shape");
+ }
+
+ static size_t offsetOfShape(size_t idx) {
+ return offsetof(ICSetProp_NativeAddImpl, shapes_) + (idx * sizeof(GCPtrShape));
+ }
+};
+
+class ICSetPropNativeAddCompiler : public ICStubCompiler
+{
+ RootedObject obj_;
+ RootedShape oldShape_;
+ RootedObjectGroup oldGroup_;
+ size_t protoChainDepth_;
+ bool isFixedSlot_;
+ uint32_t offset_;
+
+ 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>(obj_->is<UnboxedPlainObject>()) << 18) |
+ (static_cast<int32_t>(protoChainDepth_) << 19);
+ }
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ ICSetPropNativeAddCompiler(JSContext* cx, HandleObject obj,
+ HandleShape oldShape, HandleObjectGroup oldGroup,
+ size_t protoChainDepth, bool isFixedSlot, uint32_t offset);
+
+ template <size_t ProtoChainDepth>
+ ICUpdatedStub* getStubSpecific(ICStubSpace* space, Handle<ShapeVector> shapes)
+ {
+ RootedObjectGroup newGroup(cx, obj_->getGroup(cx));
+ if (!newGroup)
+ return nullptr;
+
+ // Only specify newGroup when the object's group changes due to the
+ // object becoming fully initialized per the acquired properties
+ // analysis.
+ if (newGroup == oldGroup_)
+ newGroup = nullptr;
+
+ RootedShape newShape(cx);
+ if (obj_->isNative())
+ newShape = obj_->as<NativeObject>().lastProperty();
+ else
+ newShape = obj_->as<UnboxedPlainObject>().maybeExpando()->lastProperty();
+
+ return newStub<ICSetProp_NativeAddImpl<ProtoChainDepth>>(
+ space, getStubCode(), oldGroup_, shapes, newShape, newGroup, offset_);
+ }
+
+ ICUpdatedStub* getStub(ICStubSpace* space);
+};
+
+class ICSetProp_Unboxed : public ICUpdatedStub
+{
+ friend class ICStubSpace;
+
+ GCPtrObjectGroup group_;
+ uint32_t fieldOffset_;
+
+ ICSetProp_Unboxed(JitCode* stubCode, ObjectGroup* group, uint32_t fieldOffset)
+ : ICUpdatedStub(ICStub::SetProp_Unboxed, stubCode),
+ group_(group),
+ fieldOffset_(fieldOffset)
+ {
+ (void) fieldOffset_; // Silence clang warning
+ }
+
+ public:
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+
+ static size_t offsetOfGroup() {
+ return offsetof(ICSetProp_Unboxed, group_);
+ }
+ static size_t offsetOfFieldOffset() {
+ return offsetof(ICSetProp_Unboxed, fieldOffset_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ RootedObjectGroup group_;
+ uint32_t fieldOffset_;
+ JSValueType fieldType_;
+
+ 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>(fieldType_) << 17);
+ }
+
+ public:
+ Compiler(JSContext* cx, ObjectGroup* group, uint32_t fieldOffset,
+ JSValueType fieldType)
+ : ICStubCompiler(cx, ICStub::SetProp_Unboxed, Engine::Baseline),
+ group_(cx, group),
+ fieldOffset_(fieldOffset),
+ fieldType_(fieldType)
+ {}
+
+ ICUpdatedStub* getStub(ICStubSpace* space) {
+ ICUpdatedStub* stub = newStub<ICSetProp_Unboxed>(space, getStubCode(), group_,
+ fieldOffset_);
+ if (!stub || !stub->initUpdatingChain(cx, space))
+ return nullptr;
+ return stub;
+ }
+
+ bool needsUpdateStubs() {
+ return fieldType_ == JSVAL_TYPE_OBJECT;
+ }
+ };
+};
+
+class ICSetProp_TypedObject : public ICUpdatedStub
+{
+ friend class ICStubSpace;
+
+ GCPtrShape shape_;
+ GCPtrObjectGroup group_;
+ uint32_t fieldOffset_;
+ bool isObjectReference_;
+
+ ICSetProp_TypedObject(JitCode* stubCode, Shape* shape, ObjectGroup* group,
+ uint32_t fieldOffset, bool isObjectReference)
+ : ICUpdatedStub(ICStub::SetProp_TypedObject, stubCode),
+ shape_(shape),
+ group_(group),
+ fieldOffset_(fieldOffset),
+ isObjectReference_(isObjectReference)
+ {
+ (void) fieldOffset_; // Silence clang warning
+ }
+
+ public:
+ GCPtrShape& shape() {
+ return shape_;
+ }
+ GCPtrObjectGroup& group() {
+ return group_;
+ }
+ bool isObjectReference() {
+ return isObjectReference_;
+ }
+
+ static size_t offsetOfShape() {
+ return offsetof(ICSetProp_TypedObject, shape_);
+ }
+ static size_t offsetOfGroup() {
+ return offsetof(ICSetProp_TypedObject, group_);
+ }
+ static size_t offsetOfFieldOffset() {
+ return offsetof(ICSetProp_TypedObject, fieldOffset_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ RootedShape shape_;
+ RootedObjectGroup group_;
+ uint32_t fieldOffset_;
+ TypedThingLayout layout_;
+ Rooted<SimpleTypeDescr*> fieldDescr_;
+
+ 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>(SimpleTypeDescrKey(fieldDescr_)) << 17) |
+ (static_cast<int32_t>(layout_) << 25);
+ }
+
+ public:
+ Compiler(JSContext* cx, Shape* shape, ObjectGroup* group, uint32_t fieldOffset,
+ SimpleTypeDescr* fieldDescr)
+ : ICStubCompiler(cx, ICStub::SetProp_TypedObject, Engine::Baseline),
+ shape_(cx, shape),
+ group_(cx, group),
+ fieldOffset_(fieldOffset),
+ layout_(GetTypedThingLayout(shape->getObjectClass())),
+ fieldDescr_(cx, fieldDescr)
+ {}
+
+ ICUpdatedStub* getStub(ICStubSpace* space) {
+ bool isObjectReference =
+ fieldDescr_->is<ReferenceTypeDescr>() &&
+ fieldDescr_->as<ReferenceTypeDescr>().type() == ReferenceTypeDescr::TYPE_OBJECT;
+ ICUpdatedStub* stub = newStub<ICSetProp_TypedObject>(space, getStubCode(), shape_,
+ group_, fieldOffset_,
+ isObjectReference);
+ if (!stub || !stub->initUpdatingChain(cx, space))
+ return nullptr;
+ return stub;
+ }
+
+ bool needsUpdateStubs() {
+ return fieldDescr_->is<ReferenceTypeDescr>() &&
+ fieldDescr_->as<ReferenceTypeDescr>().type() != ReferenceTypeDescr::TYPE_STRING;
+ }
+ };
+};
+
+// Base stub for calling a setters on a native or unboxed object.
+class ICSetPropCallSetter : public ICStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ // Shape/group of receiver object. Used for both own and proto setters.
+ HeapReceiverGuard receiverGuard_;
+
+ // Holder and holder shape. For own setters, guarding on receiverGuard_ is
+ // sufficient, although Ion may use holder_ and holderShape_ even for own
+ // setters. In this case holderShape_ == receiverGuard_.shape_ (isOwnSetter
+ // below relies on this).
+ GCPtrObject holder_;
+ GCPtrShape holderShape_;
+
+ // Function to call.
+ GCPtrFunction setter_;
+
+ // PC of call, for profiler
+ uint32_t pcOffset_;
+
+ ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard receiverGuard,
+ JSObject* holder, Shape* holderShape, JSFunction* setter,
+ uint32_t pcOffset);
+
+ public:
+ HeapReceiverGuard& receiverGuard() {
+ return receiverGuard_;
+ }
+ GCPtrObject& holder() {
+ return holder_;
+ }
+ GCPtrShape& holderShape() {
+ return holderShape_;
+ }
+ GCPtrFunction& setter() {
+ return setter_;
+ }
+
+ bool isOwnSetter() const {
+ MOZ_ASSERT(holder_->isNative());
+ MOZ_ASSERT(holderShape_);
+ return receiverGuard_.shape() == holderShape_;
+ }
+
+ static size_t offsetOfReceiverGuard() {
+ return offsetof(ICSetPropCallSetter, receiverGuard_);
+ }
+ 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 receiver_;
+ RootedObject holder_;
+ RootedFunction setter_;
+ uint32_t pcOffset_;
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (HeapReceiverGuard::keyBits(receiver_) << 17) |
+ (static_cast<int32_t>(receiver_ != holder_) << 20);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub::Kind kind, HandleObject receiver, HandleObject holder,
+ HandleFunction setter, uint32_t pcOffset)
+ : ICStubCompiler(cx, kind, Engine::Baseline),
+ receiver_(cx, receiver),
+ holder_(cx, holder),
+ setter_(cx, setter),
+ pcOffset_(pcOffset)
+ {
+ MOZ_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(JitCode* stubCode, ReceiverGuard guard, JSObject* holder,
+ Shape* holderShape, JSFunction* setter, uint32_t pcOffset)
+ : ICSetPropCallSetter(SetProp_CallScripted, stubCode, guard, holder, holderShape,
+ setter, pcOffset)
+ {}
+
+ public:
+ static ICSetProp_CallScripted* Clone(JSContext* cx, ICStubSpace* space, ICStub*,
+ ICSetProp_CallScripted& other);
+
+ class Compiler : public ICSetPropCallSetter::Compiler {
+ protected:
+ MOZ_MUST_USE 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) {
+ ReceiverGuard guard(receiver_);
+ Shape* holderShape = holder_->as<NativeObject>().lastProperty();
+ return newStub<ICSetProp_CallScripted>(space, getStubCode(), guard, 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(JitCode* stubCode, ReceiverGuard guard, JSObject* holder,
+ Shape* holderShape, JSFunction* setter, uint32_t pcOffset)
+ : ICSetPropCallSetter(SetProp_CallNative, stubCode, guard, holder, holderShape,
+ setter, pcOffset)
+ {}
+
+ public:
+ static ICSetProp_CallNative* Clone(JSContext* cx,
+ ICStubSpace* space, ICStub*,
+ ICSetProp_CallNative& other);
+
+ class Compiler : public ICSetPropCallSetter::Compiler {
+ protected:
+ MOZ_MUST_USE 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) {
+ ReceiverGuard guard(receiver_);
+ Shape* holderShape = holder_->as<NativeObject>().lastProperty();
+ return newStub<ICSetProp_CallNative>(space, getStubCode(), guard, holder_, holderShape,
+ setter_, pcOffset_);
+ }
+ };
+};
+
+// Call
+// JSOP_CALL
+// JSOP_FUNAPPLY
+// JSOP_FUNCALL
+// JSOP_NEW
+// JSOP_SPREADCALL
+// JSOP_SPREADNEW
+// JSOP_SPREADEVAL
+
+class ICCallStubCompiler : public ICStubCompiler
+{
+ protected:
+ ICCallStubCompiler(JSContext* cx, ICStub::Kind kind)
+ : ICStubCompiler(cx, kind, Engine::Baseline)
+ { }
+
+ enum FunApplyThing {
+ FunApply_MagicArgs,
+ FunApply_Array
+ };
+
+ void pushCallArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs,
+ Register argcReg, bool isJitCall, bool isConstructing = false);
+ void pushSpreadCallArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs,
+ Register argcReg, bool isJitCall, bool isConstructing);
+ void guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure,
+ bool isConstructing);
+ Register guardFunApply(MacroAssembler& masm, AllocatableGeneralRegisterSet regs,
+ Register argcReg, bool checkNative, FunApplyThing applyThing,
+ Label* failure);
+ void pushCallerArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs);
+ void pushArrayArguments(MacroAssembler& masm, Address arrayVal,
+ AllocatableGeneralRegisterSet regs);
+};
+
+class ICCall_Fallback : public ICMonitoredFallbackStub
+{
+ friend class ICStubSpace;
+ public:
+ static const unsigned UNOPTIMIZABLE_CALL_FLAG = 0x1;
+
+ 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:
+
+ explicit ICCall_Fallback(JitCode* stubCode)
+ : ICMonitoredFallbackStub(ICStub::Call_Fallback, stubCode)
+ { }
+
+ public:
+ void noteUnoptimizableCall() {
+ extra_ |= UNOPTIMIZABLE_CALL_FLAG;
+ }
+ bool hadUnoptimizableCall() const {
+ return extra_ & UNOPTIMIZABLE_CALL_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 {
+ public:
+ static const int32_t BASELINE_CALL_KEY =
+ (static_cast<int32_t>(Engine::Baseline)) |
+ (static_cast<int32_t>(ICStub::Call_Fallback) << 1) |
+ (0 << 17) | // spread
+ (0 << 18); // constructing
+ static const int32_t BASELINE_CONSTRUCT_KEY =
+ (static_cast<int32_t>(Engine::Baseline)) |
+ (static_cast<int32_t>(ICStub::Call_Fallback) << 1) |
+ (0 << 17) | // spread
+ (1 << 18); // constructing
+
+ protected:
+ bool isConstructing_;
+ bool isSpread_;
+ uint32_t returnOffset_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+ void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> code);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1) |
+ (static_cast<int32_t>(isSpread_) << 17) |
+ (static_cast<int32_t>(isConstructing_) << 18);
+ }
+
+ public:
+ Compiler(JSContext* cx, bool isConstructing, bool isSpread)
+ : ICCallStubCompiler(cx, ICStub::Call_Fallback),
+ isConstructing_(isConstructing),
+ isSpread_(isSpread)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ ICCall_Fallback* stub = newStub<ICCall_Fallback>(space, getStubCode());
+ if (!stub || !stub->initMonitoringChain(cx, space, engine_))
+ return nullptr;
+ return stub;
+ }
+ };
+};
+
+class ICCall_Scripted : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+ public:
+ // The maximum number of inlineable spread call arguments. Keep this small
+ // to avoid controllable stack overflows by attackers passing large arrays
+ // to spread call. This value is shared with ICCall_Native.
+ static const uint32_t MAX_ARGS_SPREAD_LENGTH = 16;
+
+ protected:
+ GCPtrFunction callee_;
+ GCPtrObject templateObject_;
+ uint32_t pcOffset_;
+
+ ICCall_Scripted(JitCode* stubCode, ICStub* firstMonitorStub,
+ JSFunction* callee, JSObject* templateObject,
+ uint32_t pcOffset);
+
+ public:
+ static ICCall_Scripted* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICCall_Scripted& other);
+
+ GCPtrFunction& callee() {
+ return callee_;
+ }
+ GCPtrObject& templateObject() {
+ return templateObject_;
+ }
+
+ static size_t offsetOfCallee() {
+ return offsetof(ICCall_Scripted, callee_);
+ }
+ static size_t offsetOfPCOffset() {
+ return offsetof(ICCall_Scripted, pcOffset_);
+ }
+};
+
+class ICCall_AnyScripted : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ uint32_t pcOffset_;
+
+ ICCall_AnyScripted(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t pcOffset)
+ : ICMonitoredStub(ICStub::Call_AnyScripted, stubCode, firstMonitorStub),
+ pcOffset_(pcOffset)
+ { }
+
+ public:
+ static ICCall_AnyScripted* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICCall_AnyScripted& other);
+
+ 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_;
+ bool isSpread_;
+ RootedFunction callee_;
+ RootedObject templateObject_;
+ uint32_t pcOffset_;
+ 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>(isConstructing_) << 17) |
+ (static_cast<int32_t>(isSpread_) << 18);
+ }
+
+ public:
+ ICCallScriptedCompiler(JSContext* cx, ICStub* firstMonitorStub,
+ JSFunction* callee, JSObject* templateObject,
+ bool isConstructing, bool isSpread, uint32_t pcOffset)
+ : ICCallStubCompiler(cx, ICStub::Call_Scripted),
+ firstMonitorStub_(firstMonitorStub),
+ isConstructing_(isConstructing),
+ isSpread_(isSpread),
+ callee_(cx, callee),
+ templateObject_(cx, templateObject),
+ pcOffset_(pcOffset)
+ { }
+
+ ICCallScriptedCompiler(JSContext* cx, ICStub* firstMonitorStub, bool isConstructing,
+ bool isSpread, uint32_t pcOffset)
+ : ICCallStubCompiler(cx, ICStub::Call_AnyScripted),
+ firstMonitorStub_(firstMonitorStub),
+ isConstructing_(isConstructing),
+ isSpread_(isSpread),
+ callee_(cx, nullptr),
+ templateObject_(cx, nullptr),
+ pcOffset_(pcOffset)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ if (callee_) {
+ return newStub<ICCall_Scripted>(space, getStubCode(), firstMonitorStub_, callee_,
+ templateObject_, pcOffset_);
+ }
+ return newStub<ICCall_AnyScripted>(space, getStubCode(), firstMonitorStub_, pcOffset_);
+ }
+};
+
+class ICCall_Native : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ GCPtrFunction callee_;
+ GCPtrObject templateObject_;
+ uint32_t pcOffset_;
+
+#ifdef JS_SIMULATOR
+ void *native_;
+#endif
+
+ ICCall_Native(JitCode* stubCode, ICStub* firstMonitorStub,
+ JSFunction* callee, JSObject* templateObject,
+ uint32_t pcOffset);
+
+ public:
+ static ICCall_Native* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICCall_Native& other);
+
+ GCPtrFunction& callee() {
+ return callee_;
+ }
+ GCPtrObject& templateObject() {
+ return templateObject_;
+ }
+
+ static size_t offsetOfCallee() {
+ return offsetof(ICCall_Native, callee_);
+ }
+ static size_t offsetOfPCOffset() {
+ return offsetof(ICCall_Native, pcOffset_);
+ }
+
+#ifdef JS_SIMULATOR
+ static size_t offsetOfNative() {
+ return offsetof(ICCall_Native, native_);
+ }
+#endif
+
+ // Compiler for this stub kind.
+ class Compiler : public ICCallStubCompiler {
+ protected:
+ ICStub* firstMonitorStub_;
+ bool isConstructing_;
+ bool isSpread_;
+ RootedFunction callee_;
+ RootedObject templateObject_;
+ uint32_t pcOffset_;
+ 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>(isConstructing_) << 17) |
+ (static_cast<int32_t>(isSpread_) << 18);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub,
+ HandleFunction callee, HandleObject templateObject,
+ bool isConstructing, bool isSpread, uint32_t pcOffset)
+ : ICCallStubCompiler(cx, ICStub::Call_Native),
+ firstMonitorStub_(firstMonitorStub),
+ isConstructing_(isConstructing),
+ isSpread_(isSpread),
+ callee_(cx, callee),
+ templateObject_(cx, templateObject),
+ pcOffset_(pcOffset)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCall_Native>(space, getStubCode(), firstMonitorStub_, callee_,
+ templateObject_, pcOffset_);
+ }
+ };
+};
+
+class ICCall_ClassHook : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ const Class* clasp_;
+ void* native_;
+ GCPtrObject templateObject_;
+ uint32_t pcOffset_;
+
+ ICCall_ClassHook(JitCode* stubCode, ICStub* firstMonitorStub,
+ const Class* clasp, Native native, JSObject* templateObject,
+ uint32_t pcOffset);
+
+ public:
+ static ICCall_ClassHook* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
+ ICCall_ClassHook& other);
+
+ const Class* clasp() {
+ return clasp_;
+ }
+ void* native() {
+ return native_;
+ }
+ GCPtrObject& templateObject() {
+ return templateObject_;
+ }
+
+ static size_t offsetOfClass() {
+ return offsetof(ICCall_ClassHook, clasp_);
+ }
+ static size_t offsetOfNative() {
+ return offsetof(ICCall_ClassHook, native_);
+ }
+ static size_t offsetOfPCOffset() {
+ return offsetof(ICCall_ClassHook, pcOffset_);
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICCallStubCompiler {
+ protected:
+ ICStub* firstMonitorStub_;
+ bool isConstructing_;
+ const Class* clasp_;
+ Native native_;
+ RootedObject templateObject_;
+ uint32_t pcOffset_;
+ 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>(isConstructing_) << 17);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub,
+ const Class* clasp, Native native,
+ HandleObject templateObject, uint32_t pcOffset,
+ bool isConstructing)
+ : ICCallStubCompiler(cx, ICStub::Call_ClassHook),
+ firstMonitorStub_(firstMonitorStub),
+ isConstructing_(isConstructing),
+ clasp_(clasp),
+ native_(native),
+ templateObject_(cx, templateObject),
+ pcOffset_(pcOffset)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCall_ClassHook>(space, getStubCode(), firstMonitorStub_, clasp_,
+ native_, templateObject_, pcOffset_);
+ }
+ };
+};
+
+class ICCall_ScriptedApplyArray : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+ public:
+ // The maximum length of an inlineable funcall array.
+ // Keep this small to avoid controllable stack overflows by attackers passing large
+ // arrays to fun.apply.
+ static const uint32_t MAX_ARGS_ARRAY_LENGTH = 16;
+
+ protected:
+ uint32_t pcOffset_;
+
+ ICCall_ScriptedApplyArray(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t pcOffset)
+ : ICMonitoredStub(ICStub::Call_ScriptedApplyArray, stubCode, firstMonitorStub),
+ pcOffset_(pcOffset)
+ {}
+
+ public:
+ static ICCall_ScriptedApplyArray* Clone(JSContext* cx,
+ ICStubSpace* space,
+ ICStub* firstMonitorStub,
+ ICCall_ScriptedApplyArray& other);
+
+ static size_t offsetOfPCOffset() {
+ return offsetof(ICCall_ScriptedApplyArray, pcOffset_);
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICCallStubCompiler {
+ protected:
+ ICStub* firstMonitorStub_;
+ uint32_t pcOffset_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub, uint32_t pcOffset)
+ : ICCallStubCompiler(cx, ICStub::Call_ScriptedApplyArray),
+ firstMonitorStub_(firstMonitorStub),
+ pcOffset_(pcOffset)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCall_ScriptedApplyArray>(space, getStubCode(), firstMonitorStub_,
+ pcOffset_);
+ }
+ };
+};
+
+class ICCall_ScriptedApplyArguments : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ uint32_t pcOffset_;
+
+ ICCall_ScriptedApplyArguments(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t pcOffset)
+ : ICMonitoredStub(ICStub::Call_ScriptedApplyArguments, stubCode, firstMonitorStub),
+ pcOffset_(pcOffset)
+ {}
+
+ public:
+ static ICCall_ScriptedApplyArguments* Clone(JSContext* cx,
+ ICStubSpace* space,
+ ICStub* firstMonitorStub,
+ ICCall_ScriptedApplyArguments& other);
+
+ static size_t offsetOfPCOffset() {
+ return offsetof(ICCall_ScriptedApplyArguments, pcOffset_);
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICCallStubCompiler {
+ protected:
+ ICStub* firstMonitorStub_;
+ uint32_t pcOffset_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub, uint32_t pcOffset)
+ : ICCallStubCompiler(cx, ICStub::Call_ScriptedApplyArguments),
+ firstMonitorStub_(firstMonitorStub),
+ pcOffset_(pcOffset)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCall_ScriptedApplyArguments>(space, getStubCode(), firstMonitorStub_,
+ pcOffset_);
+ }
+ };
+};
+
+// Handles calls of the form |fun.call(...)| where fun is a scripted function.
+class ICCall_ScriptedFunCall : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ uint32_t pcOffset_;
+
+ ICCall_ScriptedFunCall(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t pcOffset)
+ : ICMonitoredStub(ICStub::Call_ScriptedFunCall, stubCode, firstMonitorStub),
+ pcOffset_(pcOffset)
+ {}
+
+ public:
+ static ICCall_ScriptedFunCall* Clone(JSContext* cx, ICStubSpace* space,
+ ICStub* firstMonitorStub, ICCall_ScriptedFunCall& other);
+
+ static size_t offsetOfPCOffset() {
+ return offsetof(ICCall_ScriptedFunCall, pcOffset_);
+ }
+
+ // Compiler for this stub kind.
+ class Compiler : public ICCallStubCompiler {
+ protected:
+ ICStub* firstMonitorStub_;
+ uint32_t pcOffset_;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub, uint32_t pcOffset)
+ : ICCallStubCompiler(cx, ICStub::Call_ScriptedFunCall),
+ firstMonitorStub_(firstMonitorStub),
+ pcOffset_(pcOffset)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCall_ScriptedFunCall>(space, getStubCode(), firstMonitorStub_,
+ pcOffset_);
+ }
+ };
+};
+
+class ICCall_StringSplit : public ICMonitoredStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ uint32_t pcOffset_;
+ GCPtrString expectedStr_;
+ GCPtrString expectedSep_;
+ GCPtrObject templateObject_;
+
+ ICCall_StringSplit(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t pcOffset, JSString* str,
+ JSString* sep, JSObject* templateObject)
+ : ICMonitoredStub(ICStub::Call_StringSplit, stubCode, firstMonitorStub),
+ pcOffset_(pcOffset), expectedStr_(str), expectedSep_(sep),
+ templateObject_(templateObject)
+ { }
+
+ public:
+ static size_t offsetOfExpectedStr() {
+ return offsetof(ICCall_StringSplit, expectedStr_);
+ }
+
+ static size_t offsetOfExpectedSep() {
+ return offsetof(ICCall_StringSplit, expectedSep_);
+ }
+
+ static size_t offsetOfTemplateObject() {
+ return offsetof(ICCall_StringSplit, templateObject_);
+ }
+
+ GCPtrString& expectedStr() {
+ return expectedStr_;
+ }
+
+ GCPtrString& expectedSep() {
+ return expectedSep_;
+ }
+
+ GCPtrObject& templateObject() {
+ return templateObject_;
+ }
+
+ class Compiler : public ICCallStubCompiler {
+ protected:
+ ICStub* firstMonitorStub_;
+ uint32_t pcOffset_;
+ RootedString expectedStr_;
+ RootedString expectedSep_;
+ RootedObject templateObject_;
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ virtual int32_t getKey() const {
+ return static_cast<int32_t>(engine_) |
+ (static_cast<int32_t>(kind) << 1);
+ }
+
+ public:
+ Compiler(JSContext* cx, ICStub* firstMonitorStub, uint32_t pcOffset, HandleString str,
+ HandleString sep, HandleValue templateObject)
+ : ICCallStubCompiler(cx, ICStub::Call_StringSplit),
+ firstMonitorStub_(firstMonitorStub),
+ pcOffset_(pcOffset),
+ expectedStr_(cx, str),
+ expectedSep_(cx, sep),
+ templateObject_(cx, &templateObject.toObject())
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCall_StringSplit>(space, getStubCode(), firstMonitorStub_, pcOffset_,
+ expectedStr_, expectedSep_, templateObject_);
+ }
+ };
+};
+
+class ICCall_IsSuspendedStarGenerator : public ICStub
+{
+ friend class ICStubSpace;
+
+ protected:
+ explicit ICCall_IsSuspendedStarGenerator(JitCode* stubCode)
+ : ICStub(ICStub::Call_IsSuspendedStarGenerator, stubCode)
+ {}
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::Call_IsSuspendedStarGenerator, Engine::Baseline)
+ {}
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICCall_IsSuspendedStarGenerator>(space, getStubCode());
+ }
+ };
+};
+
+// 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(JitCode* stubCode, void** table,
+ int32_t min, int32_t length, void* defaultTarget)
+ : ICStub(TableSwitch, stubCode), table_(table),
+ min_(min), length_(length), defaultTarget_(defaultTarget)
+ {}
+
+ public:
+ void fixupJumpTable(JSScript* script, BaselineScript* baseline);
+
+ class Compiler : public ICStubCompiler {
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ jsbytecode* pc_;
+
+ public:
+ Compiler(JSContext* cx, jsbytecode* pc)
+ : ICStubCompiler(cx, ICStub::TableSwitch, Engine::Baseline), pc_(pc)
+ {}
+
+ ICStub* getStub(ICStubSpace* space);
+ };
+};
+
+// IC for constructing an iterator from an input value.
+class ICIteratorNew_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICIteratorNew_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::IteratorNew_Fallback, stubCode)
+ { }
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::IteratorNew_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICIteratorNew_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+// IC for testing if there are more values in an iterator.
+class ICIteratorMore_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICIteratorMore_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::IteratorMore_Fallback, stubCode)
+ { }
+
+ public:
+ void setHasNonStringResult() {
+ extra_ = 1;
+ }
+ bool hasNonStringResult() const {
+ MOZ_ASSERT(extra_ <= 1);
+ return extra_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::IteratorMore_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICIteratorMore_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+// IC for testing if there are more values in a native iterator.
+class ICIteratorMore_Native : public ICStub
+{
+ friend class ICStubSpace;
+
+ explicit ICIteratorMore_Native(JitCode* stubCode)
+ : ICStub(ICStub::IteratorMore_Native, stubCode)
+ { }
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::IteratorMore_Native, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICIteratorMore_Native>(space, getStubCode());
+ }
+ };
+};
+
+// IC for closing an iterator.
+class ICIteratorClose_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICIteratorClose_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::IteratorClose_Fallback, stubCode)
+ { }
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::IteratorClose_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICIteratorClose_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+// InstanceOf
+// JSOP_INSTANCEOF
+class ICInstanceOf_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICInstanceOf_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::InstanceOf_Fallback, stubCode)
+ { }
+
+ static const uint16_t UNOPTIMIZABLE_ACCESS_BIT = 0x1;
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 4;
+
+ void noteUnoptimizableAccess() {
+ extra_ |= UNOPTIMIZABLE_ACCESS_BIT;
+ }
+ bool hadUnoptimizableAccess() const {
+ return extra_ & UNOPTIMIZABLE_ACCESS_BIT;
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::InstanceOf_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICInstanceOf_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+class ICInstanceOf_Function : public ICStub
+{
+ friend class ICStubSpace;
+
+ GCPtrShape shape_;
+ GCPtrObject prototypeObj_;
+ uint32_t slot_;
+
+ ICInstanceOf_Function(JitCode* stubCode, Shape* shape, JSObject* prototypeObj, uint32_t slot);
+
+ public:
+ GCPtrShape& shape() {
+ return shape_;
+ }
+ GCPtrObject& prototypeObject() {
+ return prototypeObj_;
+ }
+ uint32_t slot() const {
+ return slot_;
+ }
+ static size_t offsetOfShape() {
+ return offsetof(ICInstanceOf_Function, shape_);
+ }
+ static size_t offsetOfPrototypeObject() {
+ return offsetof(ICInstanceOf_Function, prototypeObj_);
+ }
+ static size_t offsetOfSlot() {
+ return offsetof(ICInstanceOf_Function, slot_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ RootedShape shape_;
+ RootedObject prototypeObj_;
+ uint32_t slot_;
+
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, Shape* shape, JSObject* prototypeObj, uint32_t slot)
+ : ICStubCompiler(cx, ICStub::InstanceOf_Function, Engine::Baseline),
+ shape_(cx, shape),
+ prototypeObj_(cx, prototypeObj),
+ slot_(slot)
+ {}
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICInstanceOf_Function>(space, getStubCode(), shape_, prototypeObj_,
+ slot_);
+ }
+ };
+};
+
+// TypeOf
+// JSOP_TYPEOF
+// JSOP_TYPEOFEXPR
+class ICTypeOf_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICTypeOf_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::TypeOf_Fallback, stubCode)
+ { }
+
+ public:
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::TypeOf_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICTypeOf_Fallback>(space, getStubCode());
+ }
+ };
+};
+
+class ICTypeOf_Typed : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ ICTypeOf_Typed(JitCode* stubCode, JSType type)
+ : ICFallbackStub(ICStub::TypeOf_Typed, stubCode)
+ {
+ extra_ = uint16_t(type);
+ MOZ_ASSERT(JSType(extra_) == type);
+ }
+
+ public:
+ JSType type() const {
+ return JSType(extra_);
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ JSType type_;
+ RootedString typeString_;
+ 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>(type_) << 17);
+ }
+
+ public:
+ Compiler(JSContext* cx, JSType type, HandleString string)
+ : ICStubCompiler(cx, ICStub::TypeOf_Typed, Engine::Baseline),
+ type_(type),
+ typeString_(cx, string)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICTypeOf_Typed>(space, getStubCode(), type_);
+ }
+ };
+};
+
+class ICRest_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ GCPtrArrayObject templateObject_;
+
+ ICRest_Fallback(JitCode* stubCode, ArrayObject* templateObject)
+ : ICFallbackStub(ICStub::Rest_Fallback, stubCode), templateObject_(templateObject)
+ { }
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ GCPtrArrayObject& templateObject() {
+ return templateObject_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ RootedArrayObject templateObject;
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, ArrayObject* templateObject)
+ : ICStubCompiler(cx, ICStub::Rest_Fallback, Engine::Baseline),
+ templateObject(cx, templateObject)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICRest_Fallback>(space, getStubCode(), templateObject);
+ }
+ };
+};
+
+// Stub for JSOP_RETSUB ("returning" from a |finally| block).
+class ICRetSub_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ explicit ICRetSub_Fallback(JitCode* stubCode)
+ : ICFallbackStub(ICStub::RetSub_Fallback, stubCode)
+ { }
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ explicit Compiler(JSContext* cx)
+ : ICStubCompiler(cx, ICStub::RetSub_Fallback, Engine::Baseline)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICRetSub_Fallback>(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(JitCode* stubCode, uint32_t pcOffset, uint8_t* addr)
+ : ICStub(ICStub::RetSub_Resume, stubCode),
+ pcOffset_(pcOffset),
+ addr_(addr)
+ { }
+
+ public:
+ 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_;
+
+ MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
+
+ public:
+ Compiler(JSContext* cx, uint32_t pcOffset, uint8_t* addr)
+ : ICStubCompiler(cx, ICStub::RetSub_Resume, Engine::Baseline),
+ pcOffset_(pcOffset),
+ addr_(addr)
+ { }
+
+ ICStub* getStub(ICStubSpace* space) {
+ return newStub<ICRetSub_Resume>(space, getStubCode(), pcOffset_, addr_);
+ }
+ };
+};
+
+inline bool
+IsCacheableDOMProxy(JSObject* obj)
+{
+ if (!obj->is<ProxyObject>())
+ return false;
+
+ const BaseProxyHandler* handler = obj->as<ProxyObject>().handler();
+ return handler->family() == GetDOMProxyHandlerFamily();
+}
+
+struct IonOsrTempData;
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_BaselineIC_h */