1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_INTERPRETER_BYTECODE_LABEL_H_ 6 #define V8_INTERPRETER_BYTECODE_LABEL_H_ 7 8 #include <algorithm> 9 10 #include "src/zone/zone-containers.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace interpreter { 15 16 class BytecodeArrayBuilder; 17 18 // A label representing a loop header in a bytecode array. It is bound before 19 // the jump is seen, so its position is always known by the time the jump is 20 // reached. 21 class V8_EXPORT_PRIVATE BytecodeLoopHeader final { 22 public: BytecodeLoopHeader()23 BytecodeLoopHeader() : offset_(kInvalidOffset) {} 24 offset()25 size_t offset() const { 26 DCHECK_NE(offset_, kInvalidOffset); 27 return offset_; 28 } 29 30 private: 31 static const size_t kInvalidOffset = static_cast<size_t>(-1); 32 bind_to(size_t offset)33 void bind_to(size_t offset) { 34 DCHECK_NE(offset, kInvalidOffset); 35 DCHECK_EQ(offset_, kInvalidOffset); 36 offset_ = offset; 37 } 38 39 // The bytecode offset of the loop header. 40 size_t offset_; 41 42 friend class BytecodeArrayWriter; 43 }; 44 45 // A label representing a forward branch target in a bytecode array. When a 46 // label is bound, it represents a known position in the bytecode array. A label 47 // can only have at most one referrer jump. 48 class V8_EXPORT_PRIVATE BytecodeLabel final { 49 public: BytecodeLabel()50 BytecodeLabel() : bound_(false), jump_offset_(kInvalidOffset) {} 51 is_bound()52 bool is_bound() const { return bound_; } jump_offset()53 size_t jump_offset() const { 54 DCHECK_NE(jump_offset_, kInvalidOffset); 55 return jump_offset_; 56 } 57 has_referrer_jump()58 bool has_referrer_jump() const { return jump_offset_ != kInvalidOffset; } 59 60 private: 61 static const size_t kInvalidOffset = static_cast<size_t>(-1); 62 bind()63 void bind() { 64 DCHECK(!bound_); 65 bound_ = true; 66 } 67 set_referrer(size_t offset)68 void set_referrer(size_t offset) { 69 DCHECK(!bound_); 70 DCHECK_NE(offset, kInvalidOffset); 71 DCHECK_EQ(jump_offset_, kInvalidOffset); 72 jump_offset_ = offset; 73 } 74 75 // Set when the label is bound (i.e. the start of the target basic block). 76 bool bound_; 77 // Set when the jump referrer is set (i.e. the location of the jump). 78 size_t jump_offset_; 79 80 friend class BytecodeArrayWriter; 81 }; 82 83 // Class representing a branch target of multiple jumps. 84 class V8_EXPORT_PRIVATE BytecodeLabels { 85 public: BytecodeLabels(Zone * zone)86 explicit BytecodeLabels(Zone* zone) : labels_(zone), is_bound_(false) {} 87 BytecodeLabels(const BytecodeLabels&) = delete; 88 BytecodeLabels& operator=(const BytecodeLabels&) = delete; 89 90 BytecodeLabel* New(); 91 92 void Bind(BytecodeArrayBuilder* builder); 93 is_bound()94 bool is_bound() const { 95 DCHECK_IMPLIES( 96 is_bound_, 97 std::all_of(labels_.begin(), labels_.end(), [](const BytecodeLabel& l) { 98 return !l.has_referrer_jump() || l.is_bound(); 99 })); 100 return is_bound_; 101 } 102 empty()103 bool empty() const { return labels_.empty(); } 104 105 private: 106 ZoneLinkedList<BytecodeLabel> labels_; 107 bool is_bound_; 108 }; 109 110 } // namespace interpreter 111 } // namespace internal 112 } // namespace v8 113 114 #endif // V8_INTERPRETER_BYTECODE_LABEL_H_ 115