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