| /* |
| * Copyright (C) 2025 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef SRC_PROTOVM_VM_H_ |
| #define SRC_PROTOVM_VM_H_ |
| |
| #include <memory> |
| |
| #include "perfetto/protozero/field.h" |
| |
| #include "src/protovm/error_handling.h" |
| #include "src/protovm/executor.h" |
| #include "src/protovm/parser.h" |
| |
| namespace perfetto { |
| namespace protovm { |
| |
| // A VM that executes programs defined by data sources at registration time. |
| // Used by traced to apply patches (packets overwritten in the ring buffer) to |
| // an incremental state packet, thus allowing efficient incremental tracing of |
| // Layers/Windows/Views without requiring periodic invalidation and achieve |
| // perfect interning. |
| // |
| // Overview of the VM's architecture and interactions: |
| // |
| // |
| // *********** |
| // * * |
| // * Program * |
| // * * |
| // *********** |
| // │ |
| // │ |
| // │ |
| // ┌───┴──┐ ┌────────┐ |
| // │ │ │ │ |
| // │Parser├────────────┤Executor│ |
| // │ │ │ │ |
| // └──────┘ └─┬────┬─┘ |
| // │ │ |
| // ┌─────┘ └─────┐ |
| // │ │ |
| // │ │ |
| // ┌───┴────┐ ┌───┴────┐ |
| // │ │ │ │ |
| // │RoCursor│ │RwProto │ |
| // │ │ │::Cursor│ |
| // └────┬───┘ │ │ |
| // │ └───┬────┘ |
| // │ │ |
| // │ │ |
| // │ │ |
| // ********* *************** |
| // * * * * |
| // * Patch * * Incremental * |
| // * * * state * |
| // ********* * * |
| // *************** |
| // |
| // ┌─┐ |
| // │ │ VM's component |
| // └─┘ |
| // |
| // *** |
| // * * Data |
| // *** |
| // |
| // |
| // Parser: Understands the instructions semantic and controls the program flow. |
| // It delegates to the Executor operations like navigating through the |
| // patch and incremental state data, reading values, and manipulating |
| // fields. |
| // |
| // |
| // Executor: Thin glue layer that mainly forwards data back and forth between |
| // the Parser and cursors. Mainly useful for testing, as it can |
| // be easily mocked and allows to test the Parser in isolation. |
| // |
| // |
| // RoCursor: Provides read-only access to the incoming data (the patch) to be |
| // applied. It allows to traverse the proto message structure of the |
| // patch, iterating over fields and extracting field values. |
| // |
| // |
| // RwProto::Cursor: Provides read-write access to the incremental state. It |
| // allows traversing the proto message structure of the |
| // incremental state, as well as deleting/inserting/merging |
| // fields. |
| class Vm { |
| public: |
| Vm(protozero::ConstBytes program, |
| size_t memory_limit_bytes, |
| protozero::ConstBytes initial_incremental_state = {nullptr, 0}); |
| StatusOr<void> ApplyPatch(protozero::ConstBytes packet); |
| void SerializeIncrementalState(protozero::Message*) const; |
| std::string SerializeProgram() const; |
| std::unique_ptr<Vm> CloneReadOnly() const; |
| uint64_t GetMemoryUsageBytes() const; |
| |
| private: |
| struct ReadWriteState { |
| ReadWriteState(std::string& program, |
| size_t memory_limit_bytes, |
| protozero::ConstBytes initial_incremental_state) |
| : executor{}, |
| parser{protozero::ConstBytes{ |
| reinterpret_cast<const uint8_t*>(program.data()), |
| program.size()}, |
| &executor}, |
| allocator{memory_limit_bytes}, |
| incremental_state{&allocator} { |
| if (initial_incremental_state.data) { |
| incremental_state.GetRoot().SetBytes(initial_incremental_state); |
| } |
| } |
| |
| Executor executor; |
| Parser parser; |
| Allocator allocator; |
| RwProto incremental_state; |
| }; |
| |
| struct ReadOnlyState { |
| explicit ReadOnlyState(std::string incremental_state) |
| : serialized_incremental_state(std::move(incremental_state)) {} |
| |
| std::string serialized_incremental_state; |
| }; |
| |
| // Constructor used to produce read-only copies of the ProtoVm. |
| // Private to avoid unintended copies. It should be used only for |
| // CloneReadOnly(). |
| Vm(const Vm&); |
| |
| // Constructor used only for cloning |
| explicit Vm(std::string incremental_state); |
| |
| std::string SerializeIncrementalStateAsString() const; |
| |
| std::string owned_program_; |
| std::variant<ReadWriteState, ReadOnlyState> state_; |
| }; |
| |
| } // namespace protovm |
| } // namespace perfetto |
| |
| #endif // SRC_PROTOVM_VM_H_ |