// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_INTERPRETER_BYTECODE_LABEL_H_ #define V8_INTERPRETER_BYTECODE_LABEL_H_ #include <algorithm> #include "src/zone/zone-containers.h" namespace v8 { namespace internal { namespace interpreter { class BytecodeArrayBuilder; // A label representing a loop header in a bytecode array. It is bound before // the jump is seen, so its position is always known by the time the jump is // reached. class V8_EXPORT_PRIVATE BytecodeLoopHeader final { public: BytecodeLoopHeader() : offset_(kInvalidOffset) {} size_t offset() const { DCHECK_NE(offset_, kInvalidOffset); return offset_; } private: static const size_t kInvalidOffset = static_cast<size_t>(-1); void bind_to(size_t offset) { DCHECK_NE(offset, kInvalidOffset); DCHECK_EQ(offset_, kInvalidOffset); offset_ = offset; } // The bytecode offset of the loop header. size_t offset_; friend class BytecodeArrayWriter; }; // A label representing a forward branch target in a bytecode array. When a // label is bound, it represents a known position in the bytecode array. A label // can only have at most one referrer jump. class V8_EXPORT_PRIVATE BytecodeLabel final { public: BytecodeLabel() : bound_(false), jump_offset_(kInvalidOffset) {} bool is_bound() const { return bound_; } size_t jump_offset() const { DCHECK_NE(jump_offset_, kInvalidOffset); return jump_offset_; } bool has_referrer_jump() const { return jump_offset_ != kInvalidOffset; } private: static const size_t kInvalidOffset = static_cast<size_t>(-1); void bind() { DCHECK(!bound_); bound_ = true; } void set_referrer(size_t offset) { DCHECK(!bound_); DCHECK_NE(offset, kInvalidOffset); DCHECK_EQ(jump_offset_, kInvalidOffset); jump_offset_ = offset; } // Set when the label is bound (i.e. the start of the target basic block). bool bound_; // Set when the jump referrer is set (i.e. the location of the jump). size_t jump_offset_; friend class BytecodeArrayWriter; }; // Class representing a branch target of multiple jumps. class V8_EXPORT_PRIVATE BytecodeLabels { public: explicit BytecodeLabels(Zone* zone) : labels_(zone), is_bound_(false) {} BytecodeLabels(const BytecodeLabels&) = delete; BytecodeLabels& operator=(const BytecodeLabels&) = delete; BytecodeLabel* New(); void Bind(BytecodeArrayBuilder* builder); bool is_bound() const { DCHECK_IMPLIES( is_bound_, std::all_of(labels_.begin(), labels_.end(), [](const BytecodeLabel& l) { return !l.has_referrer_jump() || l.is_bound(); })); return is_bound_; } bool empty() const { return labels_.empty(); } private: ZoneLinkedList<BytecodeLabel> labels_; bool is_bound_; }; } // namespace interpreter } // namespace internal } // namespace v8 #endif // V8_INTERPRETER_BYTECODE_LABEL_H_