@@ -435,6 +435,12 @@ struct VMFrame {
435435 *
436436 * The executable contains information (e.g. data in different memory regions)
437437 * to run in a virtual machine.
438+ *
439+ * - Global section, containing all globals.
440+ * - Constant section, storing the constant pool.
441+ * - Primitive name section, containing the function name of the primitive ops
442+ * used by the virtual machine.
443+ * - Code section, handling the VM functions and bytecode.
438444 */
439445class Executable : public ModuleNode {
440446 public:
@@ -449,6 +455,24 @@ class Executable : public ModuleNode {
449455 PackedFunc GetFunction (const std::string& name,
450456 const std::shared_ptr<ModuleNode>& sptr_to_self) final ;
451457
458+ /* !
459+ * \brief Serialize the executable into global section, constant section, and
460+ * code section.
461+ *
462+ * \return The binary representation of the VM.
463+ */
464+ TVMByteArray Save ();
465+
466+ /* !
467+ * \brief Load the saved VM executable.
468+ *
469+ * \param code The bytecode in string.
470+ * \param lib The compiled runtime library.
471+ *
472+ * \return exe The constructed executable.
473+ */
474+ static runtime::Module Load (const std::string& code, const runtime::Module lib);
475+
452476 /* !
453477 * \brief Get the serialized form of the `functions`. This is
454478 * essentially bytecode serialization.
@@ -466,6 +490,18 @@ class Executable : public ModuleNode {
466490 * Each instruction is printed in the following format:
467491 * opcode num_fields field1 ... fieldX # The text format.
468492 *
493+ * Serializing an `Instruction` requires us to deal with the bytecode. Each line
494+ * of the instructions could be serialized as the following format:
495+ * hash, opcode, f1, f2, ..., fX, field with variable length
496+ * 1. hash: the hash of the instruction. This number will be used to help us
497+ * validate if an instruction is well-formed during deserialization.
498+ * 2. opcode: the opcode code of the instruction.
499+ * 3. f1, f2, ..., fX. These fields together represent the fixed fields in
500+ * an instruction, e.g., `from` and `dst` fields of a `Move` instruction. For
501+ * example, `DLDataType` will be unpacked into three fields (code, bits, lanes).
502+ * 4. The rest of the line indicates the field with variable length, e.g.,
503+ * the shape of a tensor, the args used by an `InvokPacked` instruction, etc.
504+
469505 * The field starting from # is only used for debugging. The serialized code
470506 * doesn't contain it, therefore the deserializer doens't need to handle it.
471507 */
@@ -503,6 +539,37 @@ class Executable : public ModuleNode {
503539 std::unordered_map<std::string, Index> primitive_map;
504540 /* ! \brief The virtual machine's function table. */
505541 std::vector<VMFunction> functions;
542+
543+ private:
544+ /* ! \brief Save the globals. */
545+ void SaveGlobalSection ();
546+
547+ /* ! \brief Save the constant pool. */
548+ void SaveConstantSection ();
549+
550+ /* ! \brief Save primitive op names. */
551+ void SavePrimitiveOpNames ();
552+
553+ /* ! \brief Save the vm functions. */
554+ void SaveCodeSection ();
555+
556+ /* ! \brief Load the globals. */
557+ void LoadGlobalSection ();
558+
559+ /* ! \brief Load the constant pool. */
560+ void LoadConstantSection ();
561+
562+ /* ! \brief Load primitive op names. */
563+ void LoadPrimitiveOpNames ();
564+
565+ /* ! \brief Load the vm functions.*/
566+ void LoadCodeSection ();
567+
568+ /* ! \brief The stream used for serialization. */
569+ dmlc::Stream* strm_;
570+
571+ /* ! \brief The serialized code. */
572+ std::string code_;
506573};
507574
508575/* ! \brief The virtual machine.
0 commit comments