117 lines
3.5 KiB
C++
117 lines
3.5 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* 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
|