diff options
Diffstat (limited to 'js/src/jit/IonIC.h')
-rw-r--r-- | js/src/jit/IonIC.h | 664 |
1 files changed, 664 insertions, 0 deletions
diff --git a/js/src/jit/IonIC.h b/js/src/jit/IonIC.h new file mode 100644 index 0000000000..2f5c61bcc6 --- /dev/null +++ b/js/src/jit/IonIC.h @@ -0,0 +1,664 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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_IonIC_h +#define jit_IonIC_h + +#include "jit/CacheIR.h" +#include "jit/ICState.h" +#include "jit/shared/Assembler-shared.h" + +namespace js { +namespace jit { + +class CacheIRStubInfo; +class CacheIRWriter; +class IonScript; + +// An optimized stub attached to an IonIC. +class IonICStub { + // Code to jump to when this stub fails. This is either the next optimized + // stub or the OOL fallback path. + uint8_t* nextCodeRaw_; + + // The next optimized stub in this chain, or nullptr if this is the last + // one. + IonICStub* next_; + + // Info about this stub. + CacheIRStubInfo* stubInfo_; + +#ifndef JS_64BIT + protected: // Silence Clang warning about unused private fields. + // Ensure stub data is 8-byte aligned on 32-bit. + uintptr_t padding_ = 0; +#endif + + public: + IonICStub(uint8_t* fallbackCode, CacheIRStubInfo* stubInfo) + : nextCodeRaw_(fallbackCode), next_(nullptr), stubInfo_(stubInfo) {} + + uint8_t* nextCodeRaw() const { return nextCodeRaw_; } + uint8_t** nextCodeRawPtr() { return &nextCodeRaw_; } + CacheIRStubInfo* stubInfo() const { return stubInfo_; } + IonICStub* next() const { return next_; } + + uint8_t* stubDataStart(); + + void setNext(IonICStub* next, uint8_t* nextCodeRaw) { + MOZ_ASSERT(!next_); + MOZ_ASSERT(next && nextCodeRaw); + next_ = next; + nextCodeRaw_ = nextCodeRaw; + } + + // Null out pointers when we unlink stubs, to ensure we never use + // discarded stubs. + void poison() { + nextCodeRaw_ = nullptr; + next_ = nullptr; + stubInfo_ = nullptr; + } +}; + +class IonGetPropertyIC; +class IonSetPropertyIC; +class IonGetPropSuperIC; +class IonGetNameIC; +class IonBindNameIC; +class IonGetIteratorIC; +class IonHasOwnIC; +class IonCheckPrivateFieldIC; +class IonInIC; +class IonInstanceOfIC; +class IonCompareIC; +class IonUnaryArithIC; +class IonBinaryArithIC; +class IonToPropertyKeyIC; +class IonOptimizeSpreadCallIC; +class IonCloseIterIC; + +class IonIC { + // This either points at the OOL path for the fallback path, or the code for + // the first stub. + uint8_t* codeRaw_; + + // The first optimized stub, or nullptr. + IonICStub* firstStub_; + + // Location of this IC. + JSScript* script_; + jsbytecode* pc_; + + // The offset of the rejoin location in the IonScript's code (stubs jump to + // this location). + uint32_t rejoinOffset_; + + // The offset of the OOL path in the IonScript's code that calls the IC's + // update function. + uint32_t fallbackOffset_; + + CacheKind kind_; + ICState state_; + + protected: + explicit IonIC(CacheKind kind) + : codeRaw_(nullptr), + firstStub_(nullptr), + script_(nullptr), + pc_(nullptr), + rejoinOffset_(0), + fallbackOffset_(0), + kind_(kind), + state_() {} + + void attachStub(IonICStub* newStub, JitCode* code); + + public: + void setScriptedLocation(JSScript* script, jsbytecode* pc) { + MOZ_ASSERT(!script_ && !pc_); + MOZ_ASSERT(script && pc); + script_ = script; + pc_ = pc; + } + + JSScript* script() const { + MOZ_ASSERT(script_); + return script_; + } + jsbytecode* pc() const { + MOZ_ASSERT(pc_); + return pc_; + } + + // Discard all stubs. + void discardStubs(Zone* zone, IonScript* ionScript); + + // Discard all stubs and reset the ICState. + void reset(Zone* zone, IonScript* ionScript); + + ICState& state() { return state_; } + + CacheKind kind() const { return kind_; } + uint8_t** codeRawPtr() { return &codeRaw_; } + + void setFallbackOffset(CodeOffset offset) { + fallbackOffset_ = offset.offset(); + } + void setRejoinOffset(CodeOffset offset) { rejoinOffset_ = offset.offset(); } + + void resetCodeRaw(IonScript* ionScript); + + uint8_t* fallbackAddr(IonScript* ionScript) const; + uint8_t* rejoinAddr(IonScript* ionScript) const; + + IonGetPropertyIC* asGetPropertyIC() { + MOZ_ASSERT(kind_ == CacheKind::GetProp || kind_ == CacheKind::GetElem); + return (IonGetPropertyIC*)this; + } + IonSetPropertyIC* asSetPropertyIC() { + MOZ_ASSERT(kind_ == CacheKind::SetProp || kind_ == CacheKind::SetElem); + return (IonSetPropertyIC*)this; + } + IonGetPropSuperIC* asGetPropSuperIC() { + MOZ_ASSERT(kind_ == CacheKind::GetPropSuper || + kind_ == CacheKind::GetElemSuper); + return (IonGetPropSuperIC*)this; + } + IonGetNameIC* asGetNameIC() { + MOZ_ASSERT(kind_ == CacheKind::GetName); + return (IonGetNameIC*)this; + } + IonBindNameIC* asBindNameIC() { + MOZ_ASSERT(kind_ == CacheKind::BindName); + return (IonBindNameIC*)this; + } + IonGetIteratorIC* asGetIteratorIC() { + MOZ_ASSERT(kind_ == CacheKind::GetIterator); + return (IonGetIteratorIC*)this; + } + IonOptimizeSpreadCallIC* asOptimizeSpreadCallIC() { + MOZ_ASSERT(kind_ == CacheKind::OptimizeSpreadCall); + return (IonOptimizeSpreadCallIC*)this; + } + IonHasOwnIC* asHasOwnIC() { + MOZ_ASSERT(kind_ == CacheKind::HasOwn); + return (IonHasOwnIC*)this; + } + IonCheckPrivateFieldIC* asCheckPrivateFieldIC() { + MOZ_ASSERT(kind_ == CacheKind::CheckPrivateField); + return (IonCheckPrivateFieldIC*)this; + } + IonInIC* asInIC() { + MOZ_ASSERT(kind_ == CacheKind::In); + return (IonInIC*)this; + } + IonInstanceOfIC* asInstanceOfIC() { + MOZ_ASSERT(kind_ == CacheKind::InstanceOf); + return (IonInstanceOfIC*)this; + } + IonCompareIC* asCompareIC() { + MOZ_ASSERT(kind_ == CacheKind::Compare); + return (IonCompareIC*)this; + } + IonUnaryArithIC* asUnaryArithIC() { + MOZ_ASSERT(kind_ == CacheKind::UnaryArith); + return (IonUnaryArithIC*)this; + } + IonBinaryArithIC* asBinaryArithIC() { + MOZ_ASSERT(kind_ == CacheKind::BinaryArith); + return (IonBinaryArithIC*)this; + } + IonToPropertyKeyIC* asToPropertyKeyIC() { + MOZ_ASSERT(kind_ == CacheKind::ToPropertyKey); + return (IonToPropertyKeyIC*)this; + } + IonCloseIterIC* asCloseIterIC() { + MOZ_ASSERT(kind_ == CacheKind::CloseIter); + return (IonCloseIterIC*)this; + } + + // Returns the Register to use as scratch when entering IC stubs. This + // should either be an output register or a temp. + Register scratchRegisterForEntryJump(); + + void trace(JSTracer* trc, IonScript* ionScript); + + void attachCacheIRStub(JSContext* cx, const CacheIRWriter& writer, + CacheKind kind, IonScript* ionScript, bool* attached); +}; + +class IonGetPropertyIC : public IonIC { + private: + LiveRegisterSet liveRegs_; + + TypedOrValueRegister value_; + ConstantOrRegister id_; + ValueOperand output_; + + public: + IonGetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, + TypedOrValueRegister value, const ConstantOrRegister& id, + ValueOperand output) + : IonIC(kind), + liveRegs_(liveRegs), + value_(value), + id_(id), + output_(output) {} + + TypedOrValueRegister value() const { return value_; } + ConstantOrRegister id() const { return id_; } + ValueOperand output() const { return output_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonGetPropertyIC* ic, HandleValue val, + HandleValue idVal, MutableHandleValue res); +}; + +class IonGetPropSuperIC : public IonIC { + LiveRegisterSet liveRegs_; + + Register object_; + TypedOrValueRegister receiver_; + ConstantOrRegister id_; + ValueOperand output_; + + public: + IonGetPropSuperIC(CacheKind kind, LiveRegisterSet liveRegs, Register object, + TypedOrValueRegister receiver, const ConstantOrRegister& id, + ValueOperand output) + : IonIC(kind), + liveRegs_(liveRegs), + object_(object), + receiver_(receiver), + id_(id), + output_(output) {} + + Register object() const { return object_; } + TypedOrValueRegister receiver() const { return receiver_; } + ConstantOrRegister id() const { return id_; } + ValueOperand output() const { return output_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonGetPropSuperIC* ic, HandleObject obj, + HandleValue receiver, HandleValue idVal, + MutableHandleValue res); +}; + +class IonSetPropertyIC : public IonIC { + LiveRegisterSet liveRegs_; + + Register object_; + Register temp_; + ConstantOrRegister id_; + ConstantOrRegister rhs_; + bool strict_ : 1; + + public: + IonSetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, Register object, + Register temp, const ConstantOrRegister& id, + const ConstantOrRegister& rhs, bool strict) + : IonIC(kind), + liveRegs_(liveRegs), + object_(object), + temp_(temp), + id_(id), + rhs_(rhs), + strict_(strict) {} + + LiveRegisterSet liveRegs() const { return liveRegs_; } + Register object() const { return object_; } + ConstantOrRegister id() const { return id_; } + ConstantOrRegister rhs() const { return rhs_; } + + Register temp() const { return temp_; } + + bool strict() const { return strict_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonSetPropertyIC* ic, HandleObject obj, + HandleValue idVal, HandleValue rhs); +}; + +class IonGetNameIC : public IonIC { + LiveRegisterSet liveRegs_; + + Register environment_; + ValueOperand output_; + Register temp_; + + public: + IonGetNameIC(LiveRegisterSet liveRegs, Register environment, + ValueOperand output, Register temp) + : IonIC(CacheKind::GetName), + liveRegs_(liveRegs), + environment_(environment), + output_(output), + temp_(temp) {} + + Register environment() const { return environment_; } + ValueOperand output() const { return output_; } + Register temp() const { return temp_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonGetNameIC* ic, HandleObject envChain, + MutableHandleValue res); +}; + +class IonBindNameIC : public IonIC { + LiveRegisterSet liveRegs_; + + Register environment_; + Register output_; + Register temp_; + + public: + IonBindNameIC(LiveRegisterSet liveRegs, Register environment, Register output, + Register temp) + : IonIC(CacheKind::BindName), + liveRegs_(liveRegs), + environment_(environment), + output_(output), + temp_(temp) {} + + Register environment() const { return environment_; } + Register output() const { return output_; } + Register temp() const { return temp_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + static JSObject* update(JSContext* cx, HandleScript outerScript, + IonBindNameIC* ic, HandleObject envChain); +}; + +class IonGetIteratorIC : public IonIC { + LiveRegisterSet liveRegs_; + TypedOrValueRegister value_; + Register output_; + Register temp1_; + Register temp2_; + + public: + IonGetIteratorIC(LiveRegisterSet liveRegs, TypedOrValueRegister value, + Register output, Register temp1, Register temp2) + : IonIC(CacheKind::GetIterator), + liveRegs_(liveRegs), + value_(value), + output_(output), + temp1_(temp1), + temp2_(temp2) {} + + TypedOrValueRegister value() const { return value_; } + Register output() const { return output_; } + Register temp1() const { return temp1_; } + Register temp2() const { return temp2_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + static JSObject* update(JSContext* cx, HandleScript outerScript, + IonGetIteratorIC* ic, HandleValue value); +}; + +class IonOptimizeSpreadCallIC : public IonIC { + LiveRegisterSet liveRegs_; + ValueOperand value_; + ValueOperand output_; + Register temp_; + + public: + IonOptimizeSpreadCallIC(LiveRegisterSet liveRegs, ValueOperand value, + ValueOperand output, Register temp) + : IonIC(CacheKind::OptimizeSpreadCall), + liveRegs_(liveRegs), + value_(value), + output_(output), + temp_(temp) {} + + ValueOperand value() const { return value_; } + ValueOperand output() const { return output_; } + Register temp() const { return temp_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + static bool update(JSContext* cx, HandleScript outerScript, + IonOptimizeSpreadCallIC* ic, HandleValue value, + MutableHandleValue result); +}; + +class IonHasOwnIC : public IonIC { + LiveRegisterSet liveRegs_; + + TypedOrValueRegister value_; + TypedOrValueRegister id_; + Register output_; + + public: + IonHasOwnIC(LiveRegisterSet liveRegs, TypedOrValueRegister value, + TypedOrValueRegister id, Register output) + : IonIC(CacheKind::HasOwn), + liveRegs_(liveRegs), + value_(value), + id_(id), + output_(output) {} + + TypedOrValueRegister value() const { return value_; } + TypedOrValueRegister id() const { return id_; } + Register output() const { return output_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonHasOwnIC* ic, HandleValue val, + HandleValue idVal, int32_t* res); +}; + +class IonCheckPrivateFieldIC : public IonIC { + LiveRegisterSet liveRegs_; + + TypedOrValueRegister value_; + TypedOrValueRegister id_; + Register output_; + + public: + IonCheckPrivateFieldIC(LiveRegisterSet liveRegs, TypedOrValueRegister value, + TypedOrValueRegister id, Register output) + : IonIC(CacheKind::CheckPrivateField), + liveRegs_(liveRegs), + value_(value), + id_(id), + output_(output) {} + + TypedOrValueRegister value() const { return value_; } + TypedOrValueRegister id() const { return id_; } + Register output() const { return output_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonCheckPrivateFieldIC* ic, HandleValue val, + HandleValue idVal, bool* res); +}; + +class IonInIC : public IonIC { + LiveRegisterSet liveRegs_; + + ConstantOrRegister key_; + Register object_; + Register output_; + Register temp_; + + public: + IonInIC(LiveRegisterSet liveRegs, const ConstantOrRegister& key, + Register object, Register output, Register temp) + : IonIC(CacheKind::In), + liveRegs_(liveRegs), + key_(key), + object_(object), + output_(output), + temp_(temp) {} + + ConstantOrRegister key() const { return key_; } + Register object() const { return object_; } + Register output() const { return output_; } + Register temp() const { return temp_; } + LiveRegisterSet liveRegs() const { return liveRegs_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonInIC* ic, HandleValue key, + HandleObject obj, bool* res); +}; + +class IonInstanceOfIC : public IonIC { + LiveRegisterSet liveRegs_; + + TypedOrValueRegister lhs_; + Register rhs_; + Register output_; + + public: + IonInstanceOfIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, + Register rhs, Register output) + : IonIC(CacheKind::InstanceOf), + liveRegs_(liveRegs), + lhs_(lhs), + rhs_(rhs), + output_(output) {} + + LiveRegisterSet liveRegs() const { return liveRegs_; } + TypedOrValueRegister lhs() const { return lhs_; } + Register rhs() const { return rhs_; } + Register output() const { return output_; } + + // This signature mimics that of TryAttachInstanceOfStub in baseline + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonInstanceOfIC* ic, HandleValue lhs, + HandleObject rhs, bool* attached); +}; + +class IonCompareIC : public IonIC { + LiveRegisterSet liveRegs_; + + TypedOrValueRegister lhs_; + TypedOrValueRegister rhs_; + Register output_; + + public: + IonCompareIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, + TypedOrValueRegister rhs, Register output) + : IonIC(CacheKind::Compare), + liveRegs_(liveRegs), + lhs_(lhs), + rhs_(rhs), + output_(output) {} + + LiveRegisterSet liveRegs() const { return liveRegs_; } + TypedOrValueRegister lhs() const { return lhs_; } + TypedOrValueRegister rhs() const { return rhs_; } + Register output() const { return output_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonCompareIC* stub, HandleValue lhs, + HandleValue rhs, bool* res); +}; + +class IonUnaryArithIC : public IonIC { + LiveRegisterSet liveRegs_; + + TypedOrValueRegister input_; + ValueOperand output_; + + public: + IonUnaryArithIC(LiveRegisterSet liveRegs, TypedOrValueRegister input, + ValueOperand output) + : IonIC(CacheKind::UnaryArith), + liveRegs_(liveRegs), + input_(input), + output_(output) {} + + LiveRegisterSet liveRegs() const { return liveRegs_; } + TypedOrValueRegister input() const { return input_; } + ValueOperand output() const { return output_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonUnaryArithIC* stub, HandleValue val, + MutableHandleValue res); +}; + +class IonToPropertyKeyIC : public IonIC { + LiveRegisterSet liveRegs_; + ValueOperand input_; + ValueOperand output_; + + public: + IonToPropertyKeyIC(LiveRegisterSet liveRegs, ValueOperand input, + ValueOperand output) + : IonIC(CacheKind::ToPropertyKey), + liveRegs_(liveRegs), + input_(input), + output_(output) {} + + LiveRegisterSet liveRegs() const { return liveRegs_; } + ValueOperand input() const { return input_; } + ValueOperand output() const { return output_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonToPropertyKeyIC* ic, HandleValue val, + MutableHandleValue res); +}; + +class IonBinaryArithIC : public IonIC { + LiveRegisterSet liveRegs_; + + TypedOrValueRegister lhs_; + TypedOrValueRegister rhs_; + ValueOperand output_; + + public: + IonBinaryArithIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, + TypedOrValueRegister rhs, ValueOperand output) + : IonIC(CacheKind::BinaryArith), + liveRegs_(liveRegs), + lhs_(lhs), + rhs_(rhs), + output_(output) {} + + LiveRegisterSet liveRegs() const { return liveRegs_; } + TypedOrValueRegister lhs() const { return lhs_; } + TypedOrValueRegister rhs() const { return rhs_; } + ValueOperand output() const { return output_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonBinaryArithIC* stub, HandleValue lhs, + HandleValue rhs, MutableHandleValue res); +}; + +class IonCloseIterIC : public IonIC { + LiveRegisterSet liveRegs_; + + Register iter_; + Register temp_; + CompletionKind completionKind_; + + public: + IonCloseIterIC(LiveRegisterSet liveRegs, Register iter, Register temp, + CompletionKind completionKind) + : IonIC(CacheKind::CloseIter), + liveRegs_(liveRegs), + iter_(iter), + temp_(temp), + completionKind_(completionKind) {} + + LiveRegisterSet liveRegs() const { return liveRegs_; } + Register temp() const { return temp_; } + Register iter() const { return iter_; } + CompletionKind completionKind() const { return completionKind_; } + + [[nodiscard]] static bool update(JSContext* cx, HandleScript outerScript, + IonCloseIterIC* ic, HandleObject iter); +}; + +} // namespace jit +} // namespace js + +#endif /* jit_IonIC_h */ |