/* -*- 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 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