1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
|