diff options
Diffstat (limited to 'js/src/jit/Label.h')
-rw-r--r-- | js/src/jit/Label.h | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/js/src/jit/Label.h b/js/src/jit/Label.h new file mode 100644 index 0000000000..bf78d3c5b8 --- /dev/null +++ b/js/src/jit/Label.h @@ -0,0 +1,106 @@ +/* -*- 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_Label_h +#define jit_Label_h + +#include "mozilla/Assertions.h" + +#include <stdint.h> + +namespace js { +namespace jit { + +struct LabelBase { + private: + // We use uint32_t instead of bool to ensure MSVC packs these fields + // correctly. + uint32_t bound_ : 1; + + // offset_ < INVALID_OFFSET means that the label is either bound or has + // incoming uses and needs to be bound. + uint32_t offset_ : 31; + + void operator=(const LabelBase& label) = delete; + +#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_RISCV64) + public: +#endif + static const uint32_t INVALID_OFFSET = 0x7fffffff; // UINT31_MAX. + + public: + LabelBase() : bound_(false), offset_(INVALID_OFFSET) {} + + // If the label is bound, all incoming edges have been patched and any + // future incoming edges will be immediately patched. + bool bound() const { return bound_; } + int32_t offset() const { + MOZ_ASSERT(bound() || used()); + return offset_; + } + // Returns whether the label is not bound, but has incoming uses. + bool used() const { return !bound() && offset_ < INVALID_OFFSET; } + // Binds the label, fixing its final position in the code stream. + void bind(int32_t offset) { + MOZ_ASSERT(!bound()); + MOZ_ASSERT(offset >= 0); + MOZ_ASSERT(uint32_t(offset) < INVALID_OFFSET); + offset_ = offset; + bound_ = true; + MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits"); + } + // Marks the label as neither bound nor used. + void reset() { + offset_ = INVALID_OFFSET; + bound_ = false; + } + // Sets the label's latest used position. + void use(int32_t offset) { + MOZ_ASSERT(!bound()); + MOZ_ASSERT(offset >= 0); + MOZ_ASSERT(uint32_t(offset) < INVALID_OFFSET); + offset_ = offset; + MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits"); + } +}; + +// A label represents a position in an assembly buffer that may or may not have +// already been generated. Labels can either be "bound" or "unbound", the +// former meaning that its position is known and the latter that its position +// is not yet known. +// +// A jump to an unbound label adds that jump to the label's incoming queue. A +// jump to a bound label automatically computes the jump distance. The process +// of binding a label automatically corrects all incoming jumps. +class Label : public LabelBase { + public: +#ifdef DEBUG + ~Label(); +#endif +}; + +static_assert(sizeof(Label) == sizeof(uint32_t), + "Label should have same size as uint32_t"); + +// Label's destructor asserts that if it has been used it has also been bound. +// In the case long-lived labels, however, failed compilation (e.g. OOM) will +// trigger this failure innocuously. This Label silences the assertion. +class NonAssertingLabel : public Label { + public: +#ifdef DEBUG + ~NonAssertingLabel() { + if (used()) { + bind(0); + } + } +#endif +}; + +} // namespace jit +} // namespace js + +#endif // jit_Label_h |