diff --git a/src/.clang-format b/src/.clang-format
new file mode 100644
index 0000000000000000000000000000000000000000..b1392af5d193ffd26e7d592d6bdf4d1d9ea391d6
--- /dev/null
+++ b/src/.clang-format
@@ -0,0 +1,226 @@
+---
+Language:        Cpp
+# BasedOnStyle:  Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: None
+AlignConsecutiveMacros: None
+AlignConsecutiveAssignments: None
+AlignConsecutiveBitFields: None
+AlignConsecutiveDeclarations: None
+AlignEscapedNewlines: Left
+AlignOperands:   Align
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: WithoutElse
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: Yes
+AttributeMacros:
+  - __capability
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+  AfterCaseLabel:  false
+  AfterClass:      false
+  AfterControlStatement: Never
+  AfterEnum:       false
+  AfterFunction:   false
+  AfterNamespace:  false
+  AfterObjCDeclaration: false
+  AfterStruct:     false
+  AfterUnion:      false
+  AfterExternBlock: false
+  BeforeCatch:     false
+  BeforeElse:      false
+  BeforeLambdaBody: false
+  BeforeWhile:     false
+  IndentBraces:    false
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
+  SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: None
+BreakBeforeConceptDeclarations: true
+BreakBeforeBraces: Attach
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeColon
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeColon
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit:     80
+CommentPragmas:  '^ IWYU pragma:'
+QualifierAlignment: Leave
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DeriveLineEnding: true
+DerivePointerAlignment: true
+DisableFormat:   false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+PackConstructorInitializers: NextLine
+BasedOnStyle:    ''
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+AllowAllConstructorInitializersOnNextLine: true
+FixNamespaceComments: true
+ForEachMacros:
+  - foreach
+  - Q_FOREACH
+  - BOOST_FOREACH
+IfMacros:
+  - KJ_IF_MAYBE
+IncludeBlocks:   Regroup
+IncludeCategories:
+  - Regex:           '^<ext/.*\.h>'
+    Priority:        2
+    SortPriority:    0
+    CaseSensitive:   false
+  - Regex:           '^<.*\.h>'
+    Priority:        1
+    SortPriority:    0
+    CaseSensitive:   false
+  - Regex:           '^<.*'
+    Priority:        2
+    SortPriority:    0
+    CaseSensitive:   false
+  - Regex:           '.*'
+    Priority:        3
+    SortPriority:    0
+    CaseSensitive:   false
+IncludeIsMainRegex: '([-_](test|unittest))?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseLabels: true
+IndentCaseBlocks: false
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentExternBlock: AfterExternBlock
+IndentRequires:  false
+IndentWidth:     2
+IndentWrappedFunctionNames: false
+InsertTrailingCommas: None
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+LambdaBodyIndentation: Signature
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Never
+ObjCBlockIndentWidth: 2
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PenaltyIndentedWhitespace: 0
+PointerAlignment: Left
+PPIndentWidth:   -1
+RawStringFormats:
+  - Language:        Cpp
+    Delimiters:
+      - cc
+      - CC
+      - cpp
+      - Cpp
+      - CPP
+      - 'c++'
+      - 'C++'
+    CanonicalDelimiter: ''
+    BasedOnStyle:    google
+  - Language:        TextProto
+    Delimiters:
+      - pb
+      - PB
+      - proto
+      - PROTO
+    EnclosingFunctions:
+      - EqualsProto
+      - EquivToProto
+      - PARSE_PARTIAL_TEXT_PROTO
+      - PARSE_TEST_PROTO
+      - PARSE_TEXT_PROTO
+      - ParseTextOrDie
+      - ParseTextProtoOrDie
+      - ParseTestProto
+      - ParsePartialTestProto
+    CanonicalDelimiter: pb
+    BasedOnStyle:    google
+ReferenceAlignment: Pointer
+ReflowComments:  true
+RemoveBracesLLVM: false
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SortIncludes:    CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+  AfterControlStatements: true
+  AfterForeachMacros: true
+  AfterFunctionDefinitionName: false
+  AfterFunctionDeclarationName: false
+  AfterIfMacros:   true
+  AfterOverloadedOperator: false
+  BeforeNonEmptyParentheses: false
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles:  Never
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInLineCommentPrefix:
+  Minimum:         1
+  Maximum:         -1
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpaceBeforeSquareBrackets: false
+BitFieldColonSpacing: Both
+Standard:        Auto
+StatementAttributeLikeMacros:
+  - Q_EMIT
+StatementMacros:
+  - Q_UNUSED
+  - QT_REQUIRE_VERSION
+TabWidth:        8
+UseCRLF:         false
+UseTab:          Never
+WhitespaceSensitiveMacros:
+  - STRINGIZE
+  - PP_STRINGIZE
+  - BOOST_PP_STRINGIZE
+  - NS_SWIFT_NAME
+  - CF_SWIFT_NAME
+...
+
diff --git a/src/guided_dc.cc b/src/guided_dc.cc
index 5d443d5cdb44bed323f40dc17ba37dcb26e928bb..e3d62346685841697840c01e7908cc121dfa2b9f 100644
--- a/src/guided_dc.cc
+++ b/src/guided_dc.cc
@@ -11,196 +11,34 @@
 #include <unordered_map>
 #include <vector>
 
-#include "./pinnedVector/pinnedVector/PinnedVector.h"
 #define USE_HPVM
 #ifdef USE_HPVM
 #include "heterocc.h"
 #endif
-
-// [cpp obj {ptr 1, ptr2}, ptr1{ptr3}.. ] -> Buffer[ cpp obj{ptr->relative
-// address}, *ptr1, *ptr2  ] Library:
-//  memory_map: tracking allocation type/size/meta_info
-//  Helper functions: do buffer management
-// Codegen:
-//  Enumerate member, call library
-// User code:
-//  Tell library/Codegen we want to serialize object
-
-using byte = char;
-
-// In a separate file ----------------------
-static std::unordered_map<void*, std::pair<const std::type_info*, size_t>>
-    hpvm_allocation_record;
-
-// Lib header provides ---------------------
-extern std::unordered_map<void*, std::pair<const std::type_info*, size_t>>
-    hpvm_allocation_record;
-
-bool is_allocated_memory(void* ptr) {
-  return hpvm_allocation_record.count(ptr);
-}
-size_t allocation_size(void* ptr) {
-  if (is_allocated_memory(ptr)) return hpvm_allocation_record[ptr].second;
-  return 0;
-}
-
-template <class T, class... Args>
-T* hpvm_new(Args... args) {
-  T* obj = new T(args...);
-  hpvm_allocation_record[obj] = {&typeid(T), sizeof(T)};
-  return obj;
-}
-
-template <class T, class... Args>
-void hpvm_delete(T* obj) {
-  hpvm_allocation_record.erase(obj);
-  delete obj;
-}
-
-// Hpvm Buf layout:
-// [header, pointer_recover_list(size_t[]), obj_buf]
-template <typename T>
-class HpvmBufHeader {
- public:
-  size_t pointer_recover_list_size;
-  size_t obj_size;
-  byte buf[];
-
-  void* get_obj_start() {
-    return buf + pointer_recover_list_size * sizeof(size_t);
-  }
-  size_t* get_pointer_list_start() { return (size_t*)buf; }
-  size_t* get_pointer_at(size_t offset) {
-    size_t* sub_ptr = (size_t*)((char*)get_obj_start() + offset);
-    return sub_ptr;
-  }
-  void to_relative_pointer(void* base) {
-    for (int i = 0; i < pointer_recover_list_size; i++) {
-      size_t pointer_offset = get_pointer_list_start()[i];
-      size_t* sub_ptr = get_pointer_at(pointer_offset);
-#ifndef USE_HPVM
-      std::cout << "To relative: " << (void*)sub_ptr[0];
-#endif
-      sub_ptr[0] -= (size_t)base;
-#ifndef USE_HPVM
-      std::cout << " -> " << (void*)sub_ptr[0] << "\n";
-#endif
-    }
-  }
-  void to_absolute_pointer(void* base, bool device = false) {
-    to_relative_pointer((void*)(-(size_t)base));
-  }
-  size_t total_size() {
-    return sizeof(*this) + pointer_recover_list_size * sizeof(size_t) +
-           obj_size;
-  }
-};
-template <typename T>
-class HpvmBuf {
- public:
-  HpvmBufHeader<T>* buf = nullptr;
-  std::vector<size_t> rel_pointer_list;
-  PinnedVector<byte> obj_data;
-
-  HpvmBuf() {
-    rel_pointer_list.reserve(1);
-    obj_data.reserve(1);
-  }
-
-  HpvmBufHeader<T>* formulate_device_buffer() {
-    if (buf) free(buf);
-    size_t buf_size = sizeof(*buf) + rel_pointer_list.size() * sizeof(size_t) +
-                      obj_data.size();
-    buf = (HpvmBufHeader<T>*)calloc(buf_size, 1);
-    buf->pointer_recover_list_size = rel_pointer_list.size();
-    buf->obj_size = obj_data.size();
-
-    std::cout << "Formulating buffer \n";
-    memcpy(buf->get_pointer_list_start(), rel_pointer_list.data(),
-           buf->pointer_recover_list_size * sizeof(size_t));
-    memcpy(buf->get_obj_start(), obj_data.data(), buf->obj_size);
-    std::cout << "We will have pointers at offsets: ";
-    for (auto i : rel_pointer_list) std::cout << (void*)i << ",";
-    std::cout << "\n";
-
-    buf->to_relative_pointer(obj_data.data());
-    return buf;
-  }
-  T* recover_host_accessible_obj() {
-    buf->to_absolute_pointer(buf->get_obj_start());
-    return (T*)buf->get_obj_start();
-  }
-
-  template <class AllocType = void>
-  AllocType* allocate(size_t size) {
-    if (size == 0) return nullptr;
-    size_t old_size = obj_data.size();
-    obj_data.resize(obj_data.size() + size);
-    std::cout << "Allocate up to:" << obj_data.size() << " bytes" << std::endl;
-    return (AllocType*)(obj_data.data() + old_size);
-  }
-
-  void register_pointer_in_buf(void* ptr_addr_in_buf) {
-    rel_pointer_list.push_back((size_t)(ptr_addr_in_buf) -
-                               (size_t)obj_data.data());
-  }
-};
-
-// Main user entry to snapshot an object into a buffer
-template <class T>
-HpvmBuf<T> hpvm_snapshot(T* original_obj) {
-  std::cout << "Snapshot: " << (void*)original_obj << std::endl;
-  HpvmBuf<T> buf;
-  hpvm_snapshot_internal(buf, original_obj);
-  std::cout << "Snapshot Done\n";
-  buf.formulate_device_buffer();
-  return buf;
-}
-
-// Allocated space at end of buffer and do trivial copy
-template <class T, class Buf>
-T* snapshot_trivial(Buf& buf, T* src) {
-  auto* dst = buf.template allocate<T>(sizeof(T));
-  memcpy(dst, src, sizeof(T));
-  return dst;
-}
-
-// User can implement this specialization for deep copy
-template <class Buf, class T>
-extern void hpvm_snapshot_custom(Buf& buf, T* dst_obj,
-                                 T* original_obj) {}
-
-// Snapshot function used internally
-template <class Buf, class T>
-extern T* hpvm_snapshot_internal(Buf& buf, T* original_obj) {
-  auto* dst = snapshot_trivial(buf, original_obj);
-  hpvm_snapshot_custom(buf, dst, original_obj);
-  return dst;
-}
-
-// Snapshot an (array of) pointer(s)
-template <class T, class Buf>
-void* snapshot_pointer(Buf& buf, T* src_ptr) {
-  if (is_allocated_memory(src_ptr)) {
-    auto* dst = hpvm_snapshot_internal(buf, src_ptr);
-    buf.register_pointer_in_buf(&dst_ptr);
-    return dst;
-  } else
-    return nullptr;
-}
-
-// Library function
-// ends----------------------------------------------------------
+#include "hpvm_dclib.hpp"
 
 // User code
 // A linked list:
 class LNode {
  public:
   int val;
+  int* other_vals = nullptr;  // arbitrary long array
+
   LNode* next = nullptr;
-  inline LNode(int v) { val = v; }
+  inline LNode(int v) {
+    val = v;
+    other_vals = hpvm_new_arr<int>(5);
+    for (int i = 0; i < 5; i++) other_vals[i] = i + 1;
+  }
+  void delta(int x) {
+    val += x;
+    for (int i = 0; i < 5; i++) other_vals[i] += x;
+  }
   void print() {
-    std::cout << "[Node " << val << "] -> ";
+    std::cout << "[Node " << val << ": ";
+    for (int i = 0; i < 5; i++) std::cout << other_vals[i] << ",";
+    std::cout << "] -> ";
+
     if (next)
       next->print();
     else
@@ -227,14 +65,12 @@ void stencil(HpvmBufHeader<LNode>* buf_header, size_t header_size) {
                                       (void*)buf_header, header_size);
   __hpvm__hint(hpvm::GPU_TARGET);
 
-  auto* root = (LNode*)(buf_header->get_obj_start());
-
-  buf_header->to_absolute_pointer(buf_header->get_obj_start(), true);
+  buf_header->to_absolute_pointer(buf_header->get_obj_start());
 
+  auto* root = (LNode*)(buf_header->get_obj_start());
   root->next->val = 100;
-
   while (root) {
-    root->val += 1;
+    root->delta(1);
     // root->val = (size_t)root->next;
     root = root->next;
   }
@@ -251,26 +87,28 @@ int main(int argc, char* argv[]) {
   host_obj->print();
 
   auto host_buf = hpvm_snapshot(host_obj);
-  size_t buf_size = host_buf.buf->total_size();
 
 #ifdef USE_HPVM
   std::cout << "Kernel launch!" << std::endl;
-  void* DFG = __hetero_launch((void*)stencil, 1, host_buf.buf, buf_size, 1,
-                              host_buf.buf, buf_size);
+  void* DFG = __hetero_launch((void*)stencil, 1, host_buf.buf,
+                              host_buf.buf->total_size(), 1, host_buf.buf,
+                              host_buf.buf->total_size());
   __hetero_wait(DFG);
 #else
+/*
   auto* buf_header = host_buf.buf;
 
-  host_buf.buf->to_absolute_pointer(buf_header->get_obj_start());
+  buf_header->to_absolute_pointer(buf_header->get_obj_start());
   LNode* root = (LNode*)buf_header->get_obj_start();
 
   while (root) {
-    root->val += 1;
+    root->delta(1);
     // root->val = (size_t)root->next;
     root = root->next;
   }
 
-  host_buf.buf->to_relative_pointer(host_buf.buf->get_obj_start());
+  buf_header->to_relative_pointer(buf_header->get_obj_start());
+        */
 #endif
 
   std::cout << "After kernel in buffer:\n";
@@ -279,12 +117,13 @@ int main(int argc, char* argv[]) {
   return 0;
 }
 // User code end---------------------
-// HPVM Codegen generates:
+// User / HPVM Codegen provides:
 template <>
 void hpvm_snapshot_custom<HpvmBuf<LNode>, LNode>(HpvmBuf<LNode>& buf,
                                                  LNode* dst_obj,
                                                  LNode* original_obj) {
   // recursive allocation & copies
-  dst_obj->next = snapshot_pointer(buf, original_obj->next);
+  snapshot_pointer(buf, dst_obj->next, original_obj->next);
+  snapshot_pointer(buf, dst_obj->other_vals, original_obj->other_vals);
 }
-// HPVM Codegen end ------------
+// User / HPVM Codegen end ------------
diff --git a/src/hpvm_dclib.hpp b/src/hpvm_dclib.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..07d4512f4b733688182d6632e735c518dbe08bee
--- /dev/null
+++ b/src/hpvm_dclib.hpp
@@ -0,0 +1,212 @@
+#include <argp.h>
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <functional>
+#include <iostream>
+#include <typeinfo>
+#include <unordered_map>
+#include <vector>
+
+#include "./pinnedVector/pinnedVector/PinnedVector.h"
+
+// [cpp obj {ptr 1, ptr2}, ptr1{ptr3}.. ] -> Buffer[ cpp obj{ptr->relative
+// address}, *ptr1, *ptr2  ] Library:
+//  memory_map: tracking allocation type/size/meta_info
+//  Helper functions: do buffer management
+// Codegen:
+//  Enumerate member, call library
+// User code:
+//  Tell library/Codegen we want to serialize object
+
+using byte = char;
+
+// In a separate file ----------------------
+static std::unordered_map<void*, std::pair<const std::type_info*, size_t>>
+    hpvm_allocation_record;
+
+// Lib header provides ---------------------
+extern std::unordered_map<void*, std::pair<const std::type_info*, size_t>>
+    hpvm_allocation_record;
+
+bool is_allocated_memory(void* ptr) {
+  return hpvm_allocation_record.count(ptr);
+}
+size_t allocation_size(void* ptr) {
+  if (is_allocated_memory(ptr)) return hpvm_allocation_record[ptr].second;
+  return 0;
+}
+
+template <class T, class... Args>
+T* hpvm_new(Args... args) {
+  T* obj = new T(args...);
+  hpvm_allocation_record[obj] = {&typeid(T), sizeof(T)};
+  return obj;
+}
+
+template <class T>
+T* hpvm_new_arr(size_t num_obj) {
+  T* obj = new T[num_obj];
+  hpvm_allocation_record[obj] = {&typeid(T), num_obj * sizeof(T)};
+  return obj;
+}
+
+template <class T, class... Args>
+void hpvm_delete(T* obj) {
+  hpvm_allocation_record.erase(obj);
+  delete obj;
+}
+template <class T, class... Args>
+void hpvm_delete_arr(T* obj) {
+  hpvm_allocation_record.erase(obj);
+  delete[] obj;
+}
+
+// Hpvm Buf layout:
+// [header, pointer_recover_list(size_t[]), obj_buf]
+template <typename T>
+class HpvmBufHeader {
+ public:
+  size_t pointer_recover_list_size;
+  size_t obj_size;
+  byte buf[];
+
+  void* get_obj_start() {
+    return buf + pointer_recover_list_size * sizeof(size_t);
+  }
+  size_t* get_pointer_list_start() { return (size_t*)buf; }
+  size_t* get_pointer_at(size_t offset) {
+    size_t* sub_ptr = (size_t*)((char*)get_obj_start() + offset);
+    return sub_ptr;
+  }
+  void to_relative_pointer(void* base) {
+    for (int i = 0; i < pointer_recover_list_size; i++) {
+      size_t pointer_offset = get_pointer_list_start()[i];
+      size_t* sub_ptr = get_pointer_at(pointer_offset);
+#ifndef USE_HPVM
+      std::cout << "To relative: " << (void*)sub_ptr[0];
+#endif
+      sub_ptr[0] -= (size_t)base;
+#ifndef USE_HPVM
+      std::cout << " -> " << (void*)sub_ptr[0] << "\n";
+#endif
+    }
+  }
+  void to_absolute_pointer(void* base) {
+    to_relative_pointer((void*)(-(long long)base));
+  }
+  size_t total_size() {
+    return sizeof(*this) + pointer_recover_list_size * sizeof(size_t) +
+           obj_size;
+  }
+};
+template <typename T>
+class HpvmBuf {
+ public:
+  HpvmBufHeader<T>* buf = nullptr;
+  std::vector<size_t> rel_pointer_list;
+  PinnedVector<byte> obj_data;
+
+  HpvmBuf() {
+    rel_pointer_list.reserve(1);
+    obj_data.reserve(1);
+  }
+
+  HpvmBufHeader<T>* formulate_device_buffer() {
+    if (buf) free(buf);
+    size_t buf_size = sizeof(*buf) + rel_pointer_list.size() * sizeof(size_t) +
+                      obj_data.size();
+    buf = (HpvmBufHeader<T>*)calloc(buf_size, 1);
+    buf->pointer_recover_list_size = rel_pointer_list.size();
+    buf->obj_size = obj_data.size();
+
+    std::cout << "Formulating buffer \n";
+    memcpy(buf->get_pointer_list_start(), rel_pointer_list.data(),
+           buf->pointer_recover_list_size * sizeof(size_t));
+    memcpy(buf->get_obj_start(), obj_data.data(), buf->obj_size);
+    std::cout << "We will have pointers at offsets: ";
+    for (auto i : rel_pointer_list) std::cout << (void*)i << ",";
+    std::cout << "\n";
+
+    buf->to_relative_pointer(obj_data.data());
+    return buf;
+  }
+  T* recover_host_accessible_obj() {
+    buf->to_absolute_pointer(buf->get_obj_start());
+    return (T*)buf->get_obj_start();
+  }
+
+  template <class AllocType = void>
+  AllocType* allocate(size_t size) {
+    if (size == 0) return nullptr;
+    size_t old_size = obj_data.size();
+    obj_data.resize(obj_data.size() + size);
+    std::cout << "Allocate up to:" << obj_data.size() << " bytes" << std::endl;
+    return (AllocType*)(obj_data.data() + old_size);
+  }
+
+  void register_pointer_in_buf(void* ptr_addr_in_buf) {
+    rel_pointer_list.push_back((size_t)(ptr_addr_in_buf) -
+                               (size_t)obj_data.data());
+  }
+};
+
+// Main user entry to snapshot an object into a buffer
+template <class T>
+HpvmBuf<T> hpvm_snapshot(T* original_obj) {
+  std::cout << "Snapshot: " << (void*)original_obj << std::endl;
+  HpvmBuf<T> buf;
+  hpvm_snapshot_internal(buf, original_obj);
+  std::cout << "Snapshot Done\n";
+  buf.formulate_device_buffer();
+  return buf;
+}
+
+// Allocated space at end of buffer and do trivial copy
+template <class T, class Buf>
+T* snapshot_trivial(Buf& buf, T* src) {
+  auto* dst = buf.template allocate<T>(sizeof(T));
+  memcpy(dst, src, sizeof(T));
+  return dst;
+}
+
+// User can implement this specialization for deep copy
+template <class Buf, class T>
+extern void hpvm_snapshot_custom(Buf& buf, T* dst_obj, T* original_obj) {}
+
+// Snapshot function used internally
+template <class Buf, class T>
+extern T* hpvm_snapshot_internal(Buf& buf, T* original_obj) {
+  auto* dst = snapshot_trivial(buf, original_obj);
+  hpvm_snapshot_custom(buf, dst, original_obj);
+  return dst;
+}
+
+// Snapshot an (array of) pointer(s)
+template <class T, class Buf>
+void snapshot_pointer(Buf& buf, T*& dst_ptr, T* src_ptr) {
+  if (int num_allocation = allocation_size(src_ptr) / sizeof(T)) {
+    std::cout << "Snapshot pointer to buffer of " << num_allocation
+              << " elems\n";
+    // Ensure array allocation is continuous
+    T* dst = nullptr;
+    for (int i = 0; i < num_allocation; i++) {
+      auto* alloc = snapshot_trivial(buf, src_ptr + i);
+      if (!dst) dst = alloc;
+    }
+
+    // Only do deep copy after continuous buffer have been allocated
+    for (int i = 0; i < num_allocation; i++)
+      hpvm_snapshot_custom(buf, dst + i, src_ptr + i);
+
+    dst_ptr = dst;
+    buf.register_pointer_in_buf(&dst_ptr);
+  } else
+    dst_ptr = nullptr;
+}
+
+// Library function
+// ends----------------------------------------------------------