Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef jit_Label_h
8 : #define jit_Label_h
9 :
10 : #include "jit/Ion.h"
11 :
12 : namespace js {
13 : namespace jit {
14 :
15 : struct LabelBase
16 : {
17 : protected:
18 : // offset_ >= 0 means that the label is either bound or has incoming
19 : // uses and needs to be bound.
20 : int32_t offset_ : 31;
21 : bool bound_ : 1;
22 :
23 : void operator =(const LabelBase& label) = delete;
24 :
25 : public:
26 : static const int32_t INVALID_OFFSET = -1;
27 :
28 225218 : LabelBase() : offset_(INVALID_OFFSET), bound_(false)
29 225218 : { }
30 :
31 : // If the label is bound, all incoming edges have been patched and any
32 : // future incoming edges will be immediately patched.
33 480464 : bool bound() const {
34 480464 : return bound_;
35 : }
36 42099 : int32_t offset() const {
37 42099 : MOZ_ASSERT(bound() || used());
38 42098 : return offset_;
39 : }
40 : void offsetBy(int32_t delta) {
41 : MOZ_ASSERT(bound() || used());
42 : MOZ_ASSERT(offset() + delta >= offset(), "no overflow");
43 : mozilla::DebugOnly<int32_t> oldOffset(offset());
44 : offset_ += delta;
45 : MOZ_ASSERT(offset_ == delta + oldOffset, "new offset fits in 31 bits");
46 : }
47 : // Returns whether the label is not bound, but has incoming uses.
48 227124 : bool used() const {
49 227124 : return !bound() && offset_ > INVALID_OFFSET;
50 : }
51 : // Binds the label, fixing its final position in the code stream.
52 114025 : void bind(int32_t offset) {
53 114025 : MOZ_ASSERT(!bound());
54 114026 : offset_ = offset;
55 114026 : bound_ = true;
56 114026 : MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits");
57 114026 : }
58 : // Marks the label as neither bound nor used.
59 279 : void reset() {
60 279 : offset_ = INVALID_OFFSET;
61 279 : bound_ = false;
62 279 : }
63 : // Sets the label's latest used position, returning the old use position in
64 : // the process.
65 47631 : int32_t use(int32_t offset) {
66 47631 : MOZ_ASSERT(!bound());
67 :
68 47631 : int32_t old = offset_;
69 47631 : offset_ = offset;
70 47631 : MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits");
71 :
72 47631 : return old;
73 : }
74 : };
75 :
76 : // A label represents a position in an assembly buffer that may or may not have
77 : // already been generated. Labels can either be "bound" or "unbound", the
78 : // former meaning that its position is known and the latter that its position
79 : // is not yet known.
80 : //
81 : // A jump to an unbound label adds that jump to the label's incoming queue. A
82 : // jump to a bound label automatically computes the jump distance. The process
83 : // of binding a label automatically corrects all incoming jumps.
84 225218 : class Label : public LabelBase
85 : {
86 : public:
87 59747 : ~Label()
88 59747 : {
89 : #ifdef DEBUG
90 : // The assertion below doesn't hold if an error occurred.
91 59747 : JitContext* context = MaybeGetJitContext();
92 59747 : bool hadError = js::oom::HadSimulatedOOM() ||
93 119462 : (context && context->runtime && context->runtime->hadOutOfMemory());
94 59747 : MOZ_ASSERT_IF(!hadError, !used());
95 : #endif
96 59747 : }
97 : };
98 :
99 : // Label's destructor asserts that if it has been used it has also been bound.
100 : // In the case long-lived labels, however, failed compilation (e.g. OOM) will
101 : // trigger this failure innocuously. This Label silences the assertion.
102 6742 : class NonAssertingLabel : public Label
103 : {
104 : public:
105 7321 : ~NonAssertingLabel()
106 7321 : {
107 : #ifdef DEBUG
108 7321 : if (used())
109 1 : bind(0);
110 : #endif
111 7321 : }
112 : };
113 :
114 : } // namespace jit
115 : } // namespace js
116 :
117 : #endif // jit_Label_h
|