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.h117
1 files changed, 117 insertions, 0 deletions
diff --git a/js/src/jit/Label.h b/js/src/jit/Label.h
new file mode 100644
index 000000000..b23477730
--- /dev/null
+++ b/js/src/jit/Label.h
@@ -0,0 +1,117 @@
+/* -*- 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_Label_h
+#define jit_Label_h
+
+#include "jit/Ion.h"
+
+namespace js {
+namespace jit {
+
+struct LabelBase
+{
+ protected:
+ // offset_ >= 0 means that the label is either bound or has incoming
+ // uses and needs to be bound.
+ int32_t offset_ : 31;
+ bool bound_ : 1;
+
+ // Disallow assignment.
+ void operator =(const LabelBase& label);
+ public:
+ static const int32_t INVALID_OFFSET = -1;
+
+ LabelBase() : offset_(INVALID_OFFSET), bound_(false)
+ { }
+
+ // 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_;
+ }
+ void offsetBy(int32_t delta) {
+ MOZ_ASSERT(bound() || used());
+ MOZ_ASSERT(offset() + delta >= offset(), "no overflow");
+ mozilla::DebugOnly<int32_t> oldOffset(offset());
+ offset_ += delta;
+ MOZ_ASSERT(offset_ == delta + oldOffset, "new offset fits in 31 bits");
+ }
+ // 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());
+ 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, returning the old use position in
+ // the process.
+ int32_t use(int32_t offset) {
+ MOZ_ASSERT(!bound());
+
+ int32_t old = offset_;
+ offset_ = offset;
+ MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits");
+
+ return old;
+ }
+};
+
+// 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:
+ ~Label()
+ {
+#ifdef DEBUG
+ // The assertion below doesn't hold if an error occurred.
+ JitContext* context = MaybeGetJitContext();
+ bool hadError = js::oom::HadSimulatedOOM() ||
+ (context && context->runtime && context->runtime->hadOutOfMemory());
+ MOZ_ASSERT_IF(!hadError, !used());
+#endif
+ }
+};
+
+// 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:
+ ~NonAssertingLabel()
+ {
+#ifdef DEBUG
+ if (used())
+ bind(0);
+#endif
+ }
+};
+
+} // namespace jit
+} // namespace js
+
+#endif // jit_Label_h