diff options
Diffstat (limited to 'js/src/jit/Label.h')
-rw-r--r-- | js/src/jit/Label.h | 117 |
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 |