| // Copyright 2022 The Fuchsia 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 SRC_DEVELOPER_DEBUG_ZXDB_EXPR_VM_STREAM_H_ | |
| #define SRC_DEVELOPER_DEBUG_ZXDB_EXPR_VM_STREAM_H_ | |
| #include <iosfwd> | |
| #include <vector> | |
| #include "src/developer/debug/zxdb/expr/vm_op.h" | |
| namespace zxdb { | |
| // Represents a program (a stream of operations). | |
| using VmStream = std::vector<VmOp>; | |
| // Debug formatting capabilities. | |
| std::ostream& operator<<(std::ostream&, const VmOp& op); | |
| std::string VmStreamToString(const VmStream& stream); | |
| // Shared implementation for VmBytecodeForwardJump and VmBytecodeForwardJumpIfFalse below. | |
| class VmBytecodeForwardJumper { | |
| public: | |
| VmBytecodeForwardJumper() = default; | |
| VmBytecodeForwardJumper(VmStream* stream, VmOpType op); | |
| ~VmBytecodeForwardJumper(); | |
| // This will be a no-op if the source was never set (either by the constructor or SetSource()). | |
| void JumpToHere(); | |
| protected: | |
| void SetSourceAndOp(VmStream* stream, VmOpType op); | |
| private: | |
| VmStream* stream_ = nullptr; | |
| size_t jump_source_index_ = VmOp::kBadJumpDest; | |
| }; | |
| // These helper classes assist in filling out a forward jump where the destination of the jump | |
| // is not yet known. | |
| // | |
| // When used, the corresponding jump instruction is emitted with an invalid destination. When the | |
| // stream has been appended such that the destination of the jump is now the end of the stream, call | |
| // JumpToHere() which will fill in the current stream index into the destination of the previously | |
| // emitted instruction. | |
| // | |
| // "Using" means either instantiating it with the constructor that takes parameters or using | |
| // SetSource(). SetSource() is provided for jumps that may be conditionally included: if the | |
| // zero-arg constructor is called and SetSource() is never called, nothing will happen when the | |
| // destination is known. | |
| // | |
| // This will assert if you forget to call JumpToHere() and the class goes out of scope. | |
| // | |
| // stream.push_back(...); | |
| // VmBytecodeForwardJump jump_out(stream); | |
| // | |
| // stream.push_back(...); // More instructions to jump over. | |
| // | |
| // jump_out.JumpToHere(); // The previous jump should end up here. | |
| class VmBytecodeForwardJump : public VmBytecodeForwardJumper { | |
| public: | |
| VmBytecodeForwardJump() = default; | |
| explicit VmBytecodeForwardJump(VmStream* stream) | |
| : VmBytecodeForwardJumper(stream, VmOpType::kJump) {} | |
| void SetSource(VmStream* stream) { SetSourceAndOp(stream, VmOpType::kJump); } | |
| }; | |
| class VmBytecodeForwardJumpIfFalse : public VmBytecodeForwardJumper { | |
| public: | |
| VmBytecodeForwardJumpIfFalse() = default; | |
| explicit VmBytecodeForwardJumpIfFalse(VmStream* stream) | |
| : VmBytecodeForwardJumper(stream, VmOpType::kJumpIfFalse) {} | |
| void SetSource(VmStream* stream) { SetSourceAndOp(stream, VmOpType::kJumpIfFalse); } | |
| }; | |
| class VmBytecodePushBreak : public VmBytecodeForwardJumper { | |
| public: | |
| VmBytecodePushBreak() = default; | |
| explicit VmBytecodePushBreak(VmStream* stream) | |
| : VmBytecodeForwardJumper(stream, VmOpType::kPushBreak) {} | |
| void SetSource(VmStream* stream) { SetSourceAndOp(stream, VmOpType::kPushBreak); } | |
| }; | |
| } // namespace zxdb | |
| #endif // SRC_DEVELOPER_DEBUG_ZXDB_EXPR_VM_STREAM_H_ |