| /* -*- 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 "jit/BaselineICList.h" |
| #include "jit/BaselineJIT.h" |
| #include "jit/SharedIC.h" |
| #include "jit/SharedICRegisters.h" |
| #include "js/TraceableVector.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: |
| 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: |
| 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: |
| 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; |
| |
| HeapPtrObject obj_; |
| |
| ICTypeUpdate_SingleObject(JitCode* stubCode, JSObject* obj); |
| |
| public: |
| HeapPtrObject& object() { |
| return obj_; |
| } |
| |
| static size_t offsetOfObject() { |
| return offsetof(ICTypeUpdate_SingleObject, obj_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| HandleObject obj_; |
| bool generateStubCode(MacroAssembler& masm); |
| |
| public: |
| Compiler(JSContext* cx, HandleObject obj) |
| : ICStubCompiler(cx, TypeUpdate_SingleObject, 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; |
| |
| HeapPtrObjectGroup group_; |
| |
| ICTypeUpdate_ObjectGroup(JitCode* stubCode, ObjectGroup* group); |
| |
| public: |
| HeapPtrObjectGroup& group() { |
| return group_; |
| } |
| |
| static size_t offsetOfGroup() { |
| return offsetof(ICTypeUpdate_ObjectGroup, group_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| protected: |
| HandleObjectGroup group_; |
| 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_); |
| } |
| }; |
| }; |
| |
| class ICNewArray_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| HeapPtrObject templateObject_; |
| |
| // The group used for objects created here is always available, even if the |
| // template object itself is not. |
| HeapPtrObjectGroup templateGroup_; |
| |
| ICNewArray_Fallback(JitCode* stubCode, ObjectGroup* templateGroup) |
| : ICFallbackStub(ICStub::NewArray_Fallback, stubCode), |
| templateObject_(nullptr), templateGroup_(templateGroup) |
| {} |
| |
| public: |
| class Compiler : public ICStubCompiler { |
| RootedObjectGroup templateGroup; |
| bool generateStubCode(MacroAssembler& masm); |
| |
| public: |
| Compiler(JSContext* cx, ObjectGroup* templateGroup) |
| : ICStubCompiler(cx, ICStub::NewArray_Fallback, Engine::Baseline), |
| templateGroup(cx, templateGroup) |
| {} |
| |
| ICStub* getStub(ICStubSpace* space) { |
| return newStub<ICNewArray_Fallback>(space, getStubCode(), templateGroup); |
| } |
| }; |
| |
| HeapPtrObject& templateObject() { |
| return templateObject_; |
| } |
| |
| void setTemplateObject(JSObject* obj) { |
| MOZ_ASSERT(obj->group() == templateGroup()); |
| templateObject_ = obj; |
| } |
| |
| HeapPtrObjectGroup& templateGroup() { |
| return templateGroup_; |
| } |
| |
| void setTemplateGroup(ObjectGroup* group) { |
| templateObject_ = nullptr; |
| templateGroup_ = group; |
| } |
| }; |
| |
| class ICNewObject_Fallback : public ICFallbackStub |
| { |
| friend class ICStubSpace; |
| |
| HeapPtrObject templateObject_; |
| |
| explicit ICNewObject_Fallback(JitCode* stubCode) |
| : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(nullptr) |
| {} |
| |
| public: |
| class Compiler : public ICStubCompiler { |
| bool generateStubCode(MacroAssembler& masm); |
| |
| public: |
| explicit Compiler(JSContext* cx) |
| : ICStubCompiler(cx, ICStub::NewObject_Fallback, Engine::Baseline) |
| {} |
| |
| ICStub* getStub(ICStubSpace* space) { |
| return newStub<ICNewObject_Fallback>(space, getStubCode()); |
| } |
| }; |
| |
| HeapPtrObject& 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) |
| {} |
| }; |
| |
| // 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: |
| 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: |
| 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: |
| 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: |
| 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: |
| 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: |
| 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: |
| 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: |
| 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 }; |
| |
| 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 = 0x3; |
| |
| static const unsigned ISSYMBOL_SHIFT = 3; |
| static const uint16_t ISSYMBOL_MASK = 0x1; |
| |
| 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: |
| HeapPtr<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: |
| HeapPtr<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: |
| HeapPtrFunction 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: |
| HeapPtrFunction& 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; |
| HeapPtrObject holder_; |
| HeapPtrShape holderShape_; |
| |
| ICGetElem_NativePrototypeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, |
| const T* key, AccType acctype, bool needsAtomize, uint32_t offset, |
| JSObject* holder, Shape* holderShape); |
| |
| public: |
| HeapPtrObject& holder() { |
| return holder_; |
| } |
| static size_t offsetOfHolder() { |
| return offsetof(ICGetElem_NativePrototypeSlot, holder_); |
| } |
| |
| HeapPtrShape& 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; |
| HeapPtrObject holder_; |
| HeapPtrShape 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: |
| HeapPtrObject& holder() { |
| return holder_; |
| } |
| static size_t offsetOfHolder() { |
| return offsetof(ICGetElemNativePrototypeCallStub, holder_); |
| } |
| |
| HeapPtrShape& 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_; |
| |
| bool emitCheckKey(MacroAssembler& masm, Label& failure); |
| bool emitCallNative(MacroAssembler& masm, Register objReg); |
| bool emitCallScripted(MacroAssembler& masm, Register objReg); |
| 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_) <= 8); |
| 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: |
| 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; |
| |
| HeapPtrShape 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_); |
| } |
| |
| HeapPtrShape& shape() { |
| return shape_; |
| } |
| |
| class Compiler : public ICStubCompiler { |
| ICStub* firstMonitorStub_; |
| RootedShape shape_; |
| |
| protected: |
| 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; |
| |
| HeapPtrObjectGroup 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_); |
| } |
| |
| HeapPtrObjectGroup& group() { |
| return group_; |
| } |
| |
| class Compiler : public ICStubCompiler { |
| ICStub* firstMonitorStub_; |
| RootedObjectGroup group_; |
| JSValueType elementType_; |
| |
| protected: |
| 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. |
| HeapPtrShape shape_; |
| |
| ICGetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type); |
| |
| public: |
| static size_t offsetOfShape() { |
| return offsetof(ICGetElem_TypedArray, shape_); |
| } |
| |
| HeapPtrShape& shape() { |
| return shape_; |
| } |
| |
| class Compiler : public ICStubCompiler { |
| RootedShape shape_; |
| Scalar::Type type_; |
| TypedThingLayout layout_; |
| |
| protected: |
| 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: |
| 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: |
| 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; |
| |
| HeapPtrShape shape_; // null for unboxed arrays |
| HeapPtrObjectGroup 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_); |
| } |
| |
| HeapPtrShape& shape() { |
| return shape_; |
| } |
| HeapPtrObjectGroup& group() { |
| return group_; |
| } |
| |
| class Compiler : public ICStubCompiler { |
| RootedShape shape_; |
| RootedObjectGroup group_; |
| JSValueType unboxedType_; |
| |
| 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: |
| HeapPtrObjectGroup group_; |
| |
| ICSetElem_DenseOrUnboxedArrayAdd(JitCode* stubCode, ObjectGroup* group, size_t protoChainDepth); |
| |
| public: |
| static size_t offsetOfGroup() { |
| return offsetof(ICSetElem_DenseOrUnboxedArrayAdd, group_); |
| } |
| |
| HeapPtrObjectGroup& 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<HeapPtrShape, 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++) { |
| if (shapes_[i]) |
| TraceEdge(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(HeapPtrShape); |
| } |
| }; |
| |
| class ICSetElemDenseOrUnboxedArrayAddCompiler : public ICStubCompiler { |
| RootedObject obj_; |
| size_t protoChainDepth_; |
| JSValueType unboxedType_; |
| |
| 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. |
| HeapPtrShape 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_); |
| } |
| |
| HeapPtrShape& shape() { |
| return shape_; |
| } |
| |
| class Compiler : public ICStubCompiler { |
| RootedShape shape_; |
| Scalar::Type type_; |
| TypedThingLayout layout_; |
| bool expectOutOfBounds_; |
| |
| protected: |
| 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: |
| 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 |
| { |
| HeapPtrShape shape_; |
| HeapPtrPropertyName name_; |
| |
| protected: |
| ICInNativeStub(ICStub::Kind kind, JitCode* stubCode, HandleShape shape, |
| HandlePropertyName name); |
| |
| public: |
| HeapPtrShape& shape() { |
| return shape_; |
| } |
| static size_t offsetOfShape() { |
| return offsetof(ICInNativeStub, shape_); |
| } |
| |
| HeapPtrPropertyName& 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; |
| |
| HeapPtrObject holder_; |
| HeapPtrShape holderShape_; |
| |
| ICIn_NativePrototype(JitCode* stubCode, HandleShape shape, HandlePropertyName name, |
| HandleObject holder, HandleShape holderShape); |
| |
| public: |
| HeapPtrObject& holder() { |
| return holder_; |
| } |
| HeapPtrShape& 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_; |
| |
| 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; |
| |
| HeapPtrPropertyName 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_; |
| } |
| HeapPtrPropertyName& 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<HeapPtrShape, 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(HeapPtrShape)); |
| } |
| }; |
| |
| 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); |
| } |
| |
| 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; |
| |
| HeapPtrShape shape_; |
| |
| ICIn_Dense(JitCode* stubCode, HandleShape shape); |
| |
| public: |
| HeapPtrShape& shape() { |
| return shape_; |
| } |
| static size_t offsetOfShape() { |
| return offsetof(ICIn_Dense, shape_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| RootedShape shape_; |
| |
| protected: |
| 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: |
| 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: |
| 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 scope object. Unlike GETPROP on an object's |
| // prototype, there is no teleporting optimization to take advantage of and |
| // shape checks are required all along the scope chain. |
| template <size_t NumHops> |
| class ICGetName_Scope : public ICMonitoredStub |
| { |
| friend class ICStubSpace; |
| |
| static const size_t MAX_HOPS = 6; |
| |
| mozilla::Array<HeapPtrShape, NumHops + 1> shapes_; |
| uint32_t offset_; |
| |
| ICGetName_Scope(JitCode* stubCode, ICStub* firstMonitorStub, |
| Handle<ShapeVector> shapes, uint32_t offset); |
| |
| static Kind GetStubKind() { |
| return (Kind) (GetName_Scope0 + NumHops); |
| } |
| |
| public: |
| void traceScopes(JSTracer* trc) { |
| for (size_t i = 0; i < NumHops + 1; i++) |
| TraceEdge(trc, &shapes_[i], "baseline-scope-stub-shape"); |
| } |
| |
| static size_t offsetOfShape(size_t index) { |
| MOZ_ASSERT(index <= NumHops); |
| return offsetof(ICGetName_Scope, shapes_) + (index * sizeof(HeapPtrShape)); |
| } |
| static size_t offsetOfOffset() { |
| return offsetof(ICGetName_Scope, offset_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| ICStub* firstMonitorStub_; |
| Rooted<ShapeVector> shapes_; |
| bool isFixedSlot_; |
| uint32_t offset_; |
| |
| protected: |
| 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::Forward<ShapeVector>(shapes)), |
| isFixedSlot_(isFixedSlot), |
| offset_(offset) |
| { |
| } |
| |
| ICStub* getStub(ICStubSpace* space) { |
| return newStub<ICGetName_Scope>(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: |
| 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: |
| 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; |
| |
| HeapValue value_; |
| |
| ICGetIntrinsic_Constant(JitCode* stubCode, const Value& value); |
| ~ICGetIntrinsic_Constant(); |
| |
| public: |
| HeapValue& value() { |
| return value_; |
| } |
| static size_t offsetOfValue() { |
| return offsetof(ICGetIntrinsic_Constant, value_); |
| } |
| |
| class Compiler : public ICStubCompiler { |
| bool generateStubCode(MacroAssembler& masm); |
| |
| HandleValue value_; |
| |
| public: |
| Compiler(JSContext* cx, HandleValue value) |
| : ICStubCompiler(cx, ICStub::GetIntrinsic_Constant, 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_; |
| 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. |
| HeapPtrObjectGroup group_; |
| HeapPtrShape shape_; |
| uint32_t offset_; |
| |
| ICSetProp_Native(JitCode* stubCode, ObjectGroup* group, Shape* shape, uint32_t offset); |
| |
| public: |
| HeapPtrObjectGroup& group() { |
| return group_; |
| } |
| HeapPtrShape& 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); |
| } |
| |
| 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. |
| HeapPtrObjectGroup group_; |
| HeapPtrShape newShape_; |
| HeapPtrObjectGroup 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_; |
| } |
| HeapPtrObjectGroup& group() { |
| return group_; |
| } |
| HeapPtrShape& newShape() { |
| return newShape_; |
| } |
| HeapPtrObjectGroup& 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<HeapPtrShape, 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(HeapPtrShape)); |
| } |
| }; |
| |
| 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); |
| } |
| |
| 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; |
| |
| HeapPtrObjectGroup 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: |
| HeapPtrObjectGroup& 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_; |
| |
| 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; |
| |
| HeapPtrShape shape_; |
| HeapPtrObjectGroup 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: |
| HeapPtrShape& shape() { |
| return shape_; |
| } |
| HeapPtrObjectGroup& 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_; |
| |
| 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). |
| HeapPtrObject holder_; |
| HeapPtrShape holderShape_; |
| |
| // Function to call. |
| HeapPtrFunction 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_; |
| } |
| HeapPtrObject& holder() { |
| return holder_; |
| } |
| HeapPtrShape& holderShape() { |
| return holderShape_; |
| } |
| HeapPtrFunction& 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: |
| 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: |
| 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_; |
| 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: |
| HeapPtrFunction callee_; |
| HeapPtrObject 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); |
| |
| HeapPtrFunction& callee() { |
| return callee_; |
| } |
| HeapPtrObject& 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_; |
| 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: |
| HeapPtrFunction callee_; |
| HeapPtrObject 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); |
| |
| HeapPtrFunction& callee() { |
| return callee_; |
| } |
| HeapPtrObject& 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_; |
| 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_; |
| HeapPtrObject 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_; |
| } |
| HeapPtrObject& 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_; |
| 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_; |
| 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_; |
| 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_; |
| bool generateStubCode(MacroAssembler& masm); |
| |
| virtual int32_t getKey() const { |
| return static_cast<int32_t>(engine_) | |
| (static_cast<int32_t>(kind) << 1); |
| } |
| |
| public: |
| |