summaryrefslogtreecommitdiffstats
path: root/js/src/jit/IonIC.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/IonIC.h')
-rw-r--r--js/src/jit/IonIC.h664
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 */