Label.h (3224B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 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 "mozilla/Assertions.h" 11 12 #include <stdint.h> 13 14 namespace js { 15 namespace jit { 16 17 struct LabelBase { 18 private: 19 // We use uint32_t instead of bool to ensure MSVC packs these fields 20 // correctly. 21 uint32_t bound_ : 1; 22 23 // offset_ < INVALID_OFFSET means that the label is either bound or has 24 // incoming uses and needs to be bound. 25 uint32_t offset_ : 31; 26 27 void operator=(const LabelBase& label) = delete; 28 29 #if defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONG64) || \ 30 defined(JS_CODEGEN_RISCV64) 31 public: 32 #endif 33 static const uint32_t INVALID_OFFSET = 0x7fffffff; // UINT31_MAX. 34 35 public: 36 LabelBase() : bound_(false), offset_(INVALID_OFFSET) {} 37 38 // If the label is bound, all incoming edges have been patched and any 39 // future incoming edges will be immediately patched. 40 bool bound() const { return bound_; } 41 int32_t offset() const { 42 MOZ_ASSERT(bound() || used()); 43 return offset_; 44 } 45 // Returns whether the label is not bound, but has incoming uses. 46 bool used() const { return !bound() && offset_ < INVALID_OFFSET; } 47 // Binds the label, fixing its final position in the code stream. 48 void bind(int32_t offset) { 49 MOZ_ASSERT(!bound()); 50 MOZ_ASSERT(offset >= 0); 51 MOZ_ASSERT(uint32_t(offset) < INVALID_OFFSET); 52 offset_ = offset; 53 bound_ = true; 54 MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits"); 55 } 56 // Marks the label as neither bound nor used. 57 void reset() { 58 offset_ = INVALID_OFFSET; 59 bound_ = false; 60 } 61 // Sets the label's latest used position. 62 void use(int32_t offset) { 63 MOZ_ASSERT(!bound()); 64 MOZ_ASSERT(offset >= 0); 65 MOZ_ASSERT(uint32_t(offset) < INVALID_OFFSET); 66 offset_ = offset; 67 MOZ_ASSERT(offset_ == offset, "offset fits in 31 bits"); 68 } 69 }; 70 71 // A label represents a position in an assembly buffer that may or may not have 72 // already been generated. Labels can either be "bound" or "unbound", the 73 // former meaning that its position is known and the latter that its position 74 // is not yet known. 75 // 76 // A jump to an unbound label adds that jump to the label's incoming queue. A 77 // jump to a bound label automatically computes the jump distance. The process 78 // of binding a label automatically corrects all incoming jumps. 79 class Label : public LabelBase { 80 public: 81 #ifdef DEBUG 82 ~Label(); 83 #endif 84 }; 85 86 static_assert(sizeof(Label) == sizeof(uint32_t), 87 "Label should have same size as uint32_t"); 88 89 // Label's destructor asserts that if it has been used it has also been bound. 90 // In the case long-lived labels, however, failed compilation (e.g. OOM) will 91 // trigger this failure innocuously. This Label silences the assertion. 92 class NonAssertingLabel : public Label { 93 public: 94 #ifdef DEBUG 95 ~NonAssertingLabel() { 96 if (used()) { 97 bind(0); 98 } 99 } 100 #endif 101 }; 102 103 } // namespace jit 104 } // namespace js 105 106 #endif // jit_Label_h