diff --git a/API/jsi/jsi/jsi.cpp b/API/jsi/jsi/jsi.cpp
index d7a81382e3d5d816f721d0cf5c70c209ca5ba03c..79a18a4672a65b7f49401d5f35be78813967c02e 100644
--- a/API/jsi/jsi/jsi.cpp
+++ b/API/jsi/jsi/jsi.cpp
@@ -351,6 +351,22 @@ Instrumentation& Runtime::instrumentation() {
   return sharedInstance;
 }
 
+std::vector<std::pair<std::string, Value>> Runtime::getObjectProperties(
+    const Object& object) {
+  auto propertyNames = object.getPropertyNames(*this);
+  uint32_t length = propertyNames.size(*this);
+
+  std::vector<std::pair<std::string, Value>> properties;
+  properties.reserve(length);
+
+  for (size_t i = 0; i < length; i++) {
+    auto key = propertyNames.getValueAtIndex(*this, i).asString(*this).utf8(*this);
+    auto value = object.getProperty(*this, key.c_str());
+    properties.emplace_back(key, std::move(value));
+  }
+  return properties;
+}
+
 Value Runtime::createValueFromJsonUtf8(const uint8_t* json, size_t length) {
   Function parseJson = global()
                            .getPropertyAsObject(*this, "JSON")
diff --git a/API/jsi/jsi/jsi.h b/API/jsi/jsi/jsi.h
index cbef7e252d21cf5e8fb187c3c002efaf6ca66eea..ec24b0ce9f5f3e123a6e5cb01fe4dca49cb481df 100644
--- a/API/jsi/jsi/jsi.h
+++ b/API/jsi/jsi/jsi.h
@@ -453,6 +453,9 @@ class JSI_EXPORT Runtime : public ICast {
   /// data associated with the uuid, return a null pointer.
   std::shared_ptr<void> getRuntimeData(const UUID& uuid);
 
+  virtual std::vector<std::pair<std::string, Value>> getObjectProperties(
+    const Object& object);
+
  protected:
   friend class Pointer;
   friend class PropNameID;
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab2b98017a3caf806233f9ea6bd8add882de9f85..693bdb4fda8199d4d534a73e998099d2bf342298 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -722,7 +722,7 @@ include_directories(BEFORE
   )
 
 if(HERMES_IS_ANDROID)
-  find_package(fbjni REQUIRED CONFIG)
+  #find_package(fbjni REQUIRED CONFIG)
 endif()
 
 if("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC")
@@ -741,7 +741,7 @@ add_subdirectory(lib)
 add_subdirectory(public)
 add_subdirectory(external)
 add_subdirectory(API)
-add_subdirectory(android/intltest/java/com/facebook/hermes/test)
+#add_subdirectory(android/intltest/java/com/facebook/hermes/test)
 
 if(HERMES_ENABLE_TOOLS)
   add_subdirectory(tools)
diff --git a/include/hermes/ADT/CompactArray.h b/include/hermes/ADT/CompactArray.h
index 74fc33092f401ab3a9ccc99cc71d2e3b3ab8493c..8730f800b4e93bad1922362bd77b6e511eabb59c 100644
--- a/include/hermes/ADT/CompactArray.h
+++ b/include/hermes/ADT/CompactArray.h
@@ -9,6 +9,7 @@
 #define HERMES_SUPPORT_COMPACTARRAY_H
 
 #include "hermes/Support/CheckedMalloc.h"
+#include "hermes/Support/restrace.h"
 #include "llvh/Support/ErrorHandling.h"
 
 #include <cassert>
@@ -34,8 +35,15 @@ class CompactArray {
   CompactArray(uint32_t count, Scale initScale = UINT8)
       : size_(count),
         scale_(initScale),
-        raw_(static_cast<char *>(checkedCalloc(count, 1ULL << initScale))) {}
+        raw_(static_cast<char *>(checkedCalloc(count, 1ULL << initScale))) {
+    if (raw_ != nullptr && additionalMemorySize() > 0) {
+      OH_RESTRACE(raw_, additionalMemorySize());
+    }
+  }
   ~CompactArray() {
+    if (raw_ != nullptr && additionalMemorySize() > 0) {
+      OH_RESTRACE_FREE_REGION(raw_, additionalMemorySize());
+    }
     ::free(raw_);
   }
   /// swap is the only bulk transfer method.
diff --git a/include/hermes/Support/restrace.h b/include/hermes/Support/restrace.h
new file mode 100755
index 0000000000000000000000000000000000000000..33ac20c7eb1be064c5dc38efdef6c256bef0628d
--- /dev/null
+++ b/include/hermes/Support/restrace.h
@@ -0,0 +1,56 @@
+#ifndef JS_RESTRACE_H_
+#define JS_RESTRACE_H_
+
+#include <cstddef>
+
+#define RES_RN_HERMES_HEAP (1ULL << 31)
+#define TAG_RES_RN_HERMES_HEAP ("RES_RN_HERMES_HEAP")
+
+extern "C" void restrace(
+    unsigned long long mask,
+    void *addr,
+    size_t size,
+    const char *tag,
+    bool is_using) __attribute__((weak));
+
+extern "C" void resTraceMove(
+    unsigned long long mask,
+    void *oldAddr,
+    void *newAddr,
+    size_t newSize) __attribute__((weak));
+
+extern "C" void resTraceFreeRegion(
+    unsigned long long mask,
+    void *addr,
+    size_t size) __attribute__((weak));
+
+static inline void OHRestraceAlloc(void *addr, size_t size) {
+  if (addr != nullptr && size > 0 && restrace != nullptr) {
+    restrace(RES_RN_HERMES_HEAP, addr, size, TAG_RES_RN_HERMES_HEAP, true);
+  }
+}
+
+static inline void OHRestraceMove(
+    void *oldAddr,
+    void *newAddr,
+    size_t newSize) {
+  if (newAddr != nullptr && newSize > 0 && resTraceMove != nullptr) {
+    resTraceMove(RES_RN_HERMES_HEAP, oldAddr, newAddr, newSize);
+  }
+}
+
+static inline void OHRestraceFree(void *addr, size_t size) {
+  if (addr != nullptr && size > 0 && resTraceFreeRegion != nullptr) {
+    resTraceFreeRegion(RES_RN_HERMES_HEAP, addr, size);
+  }
+}
+
+#define OH_RESTRACE(ADDR, SIZE) OHRestraceAlloc((ADDR), (SIZE))
+
+#define OH_RESTRACE_MOVE(OLD_ADDR, NEW_ADDR, NEW_SIZE) \
+  OHRestraceMove((OLD_ADDR), (NEW_ADDR), (NEW_SIZE))
+
+#define OH_RESTRACE_FREE_REGION(ADDR, SIZE) \
+  OHRestraceFree((ADDR), (SIZE))
+
+#endif // JS_RESTRACE_H_
diff --git a/include/hermes/VM/ArrayStorage.h b/include/hermes/VM/ArrayStorage.h
index 18b0f2369d2c65fd2faa582d3b86e59ecbf2b697..61f8e85e90bc55cee437f4fab02d2feaedbf57ef 100644
--- a/include/hermes/VM/ArrayStorage.h
+++ b/include/hermes/VM/ArrayStorage.h
@@ -106,6 +106,9 @@ class ArrayStorageBase final : public VariableSizeRuntimeCell,
         MayFail::Yes>(*allocSizeRes);
     if (LLVM_UNLIKELY(!cell))
       return throwAllocationFailure(runtime, capacity);
+    if (cell != nullptr && *allocSizeRes > 0) {
+      OH_RESTRACE(cell, *allocSizeRes);
+    }
     return HermesValue::encodeObjectValue(cell);
   }
 
@@ -137,6 +140,9 @@ class ArrayStorageBase final : public VariableSizeRuntimeCell,
     if (LLVM_UNLIKELY(!ptr)) {
       return throwAllocationFailure(runtime, capacity);
     }
+    if (ptr != nullptr && *allocSizeRes > 0) {
+      OH_RESTRACE(ptr, *allocSizeRes);
+    }
     return HermesValue::encodeObjectValue(ptr);
   }
 
diff --git a/include/hermes/VM/CopyableVector.h b/include/hermes/VM/CopyableVector.h
index 0efa08b32289a5e8571ab6bbb86fca8c496e4f9e..d08ca15b9f2907af3335032b8fdcc741d2b1ed06 100644
--- a/include/hermes/VM/CopyableVector.h
+++ b/include/hermes/VM/CopyableVector.h
@@ -10,6 +10,7 @@
 
 #include "hermes/Support/Algorithms.h"
 #include "hermes/Support/CheckedMalloc.h"
+#include "hermes/Support/restrace.h"
 #include "hermes/VM/GC.h"
 
 #include "llvh/Support/Compiler.h"
@@ -71,6 +72,9 @@ class CopyableVector {
       start_ = nullptr;
     } else {
       start_ = static_cast<T *>(checkedMalloc2(sizeof(T), capacity_));
+      if (start_ != nullptr && capacity_in_bytes() > 0) {
+        OH_RESTRACE(start_, capacity_in_bytes());
+      }
     }
   }
 
@@ -79,6 +83,9 @@ class CopyableVector {
     for (auto &v : *this) {
       v.~T();
     }
+    if (start_ != nullptr && capacity_in_bytes() > 0) {
+      OH_RESTRACE_FREE_REGION(start_, capacity_in_bytes());
+    }
     free(start_);
   }
 
@@ -218,13 +225,21 @@ class CopyableVector {
   /// \pre the \p newCapacity is bigger than the current capacity.
   void setCapacity(size_type newCapacity) {
     assert(newCapacity > capacity_ && "setCapacity() must grow the vector");
+    T *oldStart = start_;
+    size_type oldCapacity = capacity_;
     T *newStart = static_cast<T *>(checkedMalloc2(sizeof(T), newCapacity));
+    if (newStart != nullptr && newCapacity > 0) {
+      OH_RESTRACE(newStart, newCapacity * sizeof(T));
+    }
     for (T *src = start_, *end = start_ + size_, *target = newStart; src < end;
          ++src, ++target) {
       new (target) T(std::move(*src));
       src->~T();
     }
-    free(start_);
+    if (oldStart != nullptr && oldCapacity > 0) {
+      OH_RESTRACE_FREE_REGION(oldStart, oldCapacity * sizeof(T));
+    }
+    free(oldStart);
     start_ = newStart;
     capacity_ = newCapacity;
   }
diff --git a/lib/Support/OSCompatPosix.cpp b/lib/Support/OSCompatPosix.cpp
index 7a496e4d8..ed0a13958 100644
--- a/lib/Support/OSCompatPosix.cpp
+++ b/lib/Support/OSCompatPosix.cpp
@@ -10,6 +10,7 @@
 #include "hermes/Support/Compiler.h"
 #include "hermes/Support/ErrorHandling.h"
 #include "hermes/Support/OSCompat.h"
+#include "hermes/Support/restrace.h"
 
 #include <cassert>
 #include <fstream>
@@ -53,7 +54,7 @@
 #include <sys/prctl.h>
 #endif
 
-#ifdef __ANDROID__
+#if defined(__linux__) || defined(__ANDROID__)
 #ifndef PR_SET_VMA
 #define PR_SET_VMA 0x53564d41
 #endif
@@ -61,7 +62,7 @@
 #ifndef PR_SET_VMA_ANON_NAME
 #define PR_SET_VMA_ANON_NAME 0
 #endif
-#endif // __ANDROID__
+#endif // __linux__ || __ANDROID__
 
 #ifdef __APPLE__
 #include <TargetConditionals.h>
@@ -124,6 +125,9 @@ vm_mmap(void *addr, size_t sz, int prot, int flags, bool checkDebugLimit) {
   }
 #endif // !NDEBUG
   void *result = mmap(addr, sz, prot, flags, -1, 0);
+  if (result != MAP_FAILED && result != nullptr && sz > 0) {
+    OH_RESTRACE(result, sz);
+  }
   if (result == MAP_FAILED) {
     // Since mmap is a POSIX API, even on MacOS, errno should use the POSIX
     // generic_category.
@@ -133,6 +137,9 @@ vm_mmap(void *addr, size_t sz, int prot, int flags, bool checkDebugLimit) {
 }
 
 static void vm_munmap(void *addr, size_t sz) {
+  if (addr != nullptr && sz > 0) {
+    OH_RESTRACE_FREE_REGION(addr, sz);
+  }
   auto ret = munmap(addr, sz);
   assert(!ret && "Failed to free memory region.");
   (void)ret;
@@ -297,13 +304,13 @@ void vm_prefetch(void *p, size_t sz) {
 }
 
 void vm_name(void *p, size_t sz, const char *name) {
-#ifdef __ANDROID__
+#if defined(__linux__) || defined(__ANDROID__)
   prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, p, sz, name);
 #else
   (void)p;
   (void)sz;
   (void)name;
-#endif // __ANDROID__
+#endif // __linux__ || __ANDROID__
 }
 
 bool vm_protect(void *p, size_t sz, ProtectMode mode) {
diff --git a/lib/VM/DictPropertyMap.cpp b/lib/VM/DictPropertyMap.cpp
index f27475c1cde41f47063a2f358264323becd1aa2f..a5ebdd2478373b217ebf442cb62f5b2fadefeb91 100644
--- a/lib/VM/DictPropertyMap.cpp
+++ b/lib/VM/DictPropertyMap.cpp
@@ -50,18 +50,21 @@ CallResult<PseudoHandle<DictPropertyMap>> DictPropertyMap::create(
         " properties");
   }
   size_type hashCapacity = calcHashCapacity(capacity);
+  const auto allocSize = allocationSize(capacity, hashCapacity);
   auto *cell = runtime.makeAVariable<
       DictPropertyMap,
       HasFinalizer::No,
       LongLived::No,
       CanBeLarge::Yes,
-      MayFail::Yes>(
-      allocationSize(capacity, hashCapacity), capacity, hashCapacity);
+      MayFail::Yes>(allocSize, capacity, hashCapacity);
   if (LLVM_UNLIKELY(!cell)) {
     return runtime.raiseRangeError(
         TwineChar16("Property storage with capacity ") + capacity +
         " fails to allocate");
   }
+  if (cell != nullptr && allocSize > 0) {
+    OH_RESTRACE(cell, allocSize);
+  }
   return createPseudoHandle(cell);
 }
 
diff --git a/lib/VM/gcs/HadesGC.cpp b/lib/VM/gcs/HadesGC.cpp
index c707d64872207b86dff2984d570406f0679e019a..8e83f3e475400159728828472bfb310aa1b7537d 100644
--- a/lib/VM/gcs/HadesGC.cpp
+++ b/lib/VM/gcs/HadesGC.cpp
@@ -10,6 +10,7 @@
 #include "hermes/Support/Compiler.h"
 #include "hermes/Support/ErrorHandling.h"
 #include "hermes/Support/Statistic.h"
+#include "hermes/Support/restrace.h"
 #include "hermes/VM/AllocResult.h"
 #include "hermes/VM/CheckHeapWellFormedAcceptor.h"
 #include "hermes/VM/FillerCell.h"
@@ -50,6 +51,24 @@ static const char *kGCName =
 static const char *kCompacteeNameForCrashMgr = "COMPACT";
 static const char *kYGNameForCrashMgr = "YG";
 
+static bool shouldTraceRestraceCell(const GCCell *cell) {
+  if (cell == nullptr) {
+    return false;
+  }
+
+  switch (cell->getKind()) {
+    case CellKind::ArrayStorageKind:
+    case CellKind::ArrayStorageSmallKind:
+    case CellKind::DictPropertyMapKind:
+    // case CellKind::SegmentedArrayKind:
+    // case CellKind::SegmentedArraySmallKind:
+    // case CellKind::SegmentKind:
+    // case CellKind::SegmentSmallKind:
+      return true;
+    default:
+      return false;
+  }
+}
 // We have a target max pause time of 50ms.
 static constexpr size_t kTargetMaxPauseMs = 50;
 
@@ -511,6 +530,9 @@ class HadesGC::EvacAcceptor final : public RootAcceptor,
         "Cell must be marked when it is allocated into the old gen");
     // Copy the contents of the existing cell over before modifying it.
     std::memcpy((void *)newCell, cell, cellSize);
+    if (shouldTraceRestraceCell(cell) && cellSize > 0) {
+      OH_RESTRACE(newCell, cellSize);
+    }
     assert(newCell->isValid() && "Cell was copied incorrectly");
     evacuatedBytes_ += cellSize;
     CopyListCell *const copyCell = static_cast<CopyListCell *>(cell);
@@ -1104,6 +1126,9 @@ bool HadesGC::OldGen::sweepNext(bool backgroundThread) {
     segmentSweptBytes += sz;
     // Cell is dead, run its finalizer first if it has one.
     cell->getVT()->finalizeIfExists(cell, gc_);
+    if (!vmisa<FillerCell>(cell) && shouldTraceRestraceCell(cell) && sz > 0) {
+      OH_RESTRACE_FREE_REGION(cell, sz);
+    }
     if (isTracking && !vmisa<FillerCell>(cell)) {
       gc_.untrackObject(cell, sz);
     }
@@ -2606,20 +2631,24 @@ void HadesGC::youngGenCollection(
       heapBytes.after = youngGenEvacuateImpl<false>(false);
     }
     // Inform trackers about objects that died during this YG collection.
-    if (isTrackingIDs()) {
-      auto trackerCallback = [this](GCCell *cell) {
-        // The compactee might have free list cells, which are not tracked.
-        // untrackObject requires the object to have been tracked previously.
-        // So skip free list cells here.
-        if (!vmisa<OldGen::FreelistCell>(cell)) {
-          untrackObject(cell, cell->getAllocatedSize());
+    auto trackerCallback = [this](GCCell *cell) {
+      // The compactee might have free list cells, which are not tracked.
+      // untrackObject requires the object to have been tracked previously.
+      // So skip free list cells here.
+      if (!vmisa<OldGen::FreelistCell>(cell)) {
+        const auto cellSize = cell->getAllocatedSize();
+        if (shouldTraceRestraceCell(cell) && cellSize > 0) {
+          OH_RESTRACE_FREE_REGION(cell, cellSize);
+        }
+        if (isTrackingIDs()) {
+          untrackObject(cell, cellSize);
         }
-      };
-      forCompactedObjsInSegment(yg, trackerCallback, getPointerBase());
-      if (doCompaction) {
-        forCompactedObjsInSegment(
-            *compactee_.segment, trackerCallback, getPointerBase());
       }
+    };
+    forCompactedObjsInSegment(yg, trackerCallback, getPointerBase());
+    if (doCompaction) {
+      forCompactedObjsInSegment(
+        *compactee_.segment, trackerCallback, getPointerBase());
     }
     // Run finalizers for young gen objects.
     finalizeYoungGenObjects();
diff --git a/lib/VM/gcs/MallocGC.cpp b/lib/VM/gcs/MallocGC.cpp
index 9e07ee03ab5f99492971d0cf48b6bfdcc7f75322..68e20118050369c754be9a3a0514cc1db413b081 100644
--- a/lib/VM/gcs/MallocGC.cpp
+++ b/lib/VM/gcs/MallocGC.cpp
@@ -7,6 +7,7 @@
 
 #include "hermes/Support/CheckedMalloc.h"
 #include "hermes/Support/ErrorHandling.h"
+#include "hermes/Support/restrace.h"
 #include "hermes/Support/SlowAssert.h"
 #include "hermes/VM/CheckHeapWellFormedAcceptor.h"
 #include "hermes/VM/CompressedPointer.h"
@@ -28,6 +29,24 @@ namespace vm {
 
 static const char *kGCName = "malloc";
 
+static bool shouldTraceRestraceCell(const GCCell *cell) {
+  if (cell == nullptr) {
+    return false;
+  }
+
+  switch (cell->getKind()) {
+    case CellKind::ArrayStorageKind:
+    case CellKind::ArrayStorageSmallKind:
+    case CellKind::DictPropertyMapKind:
+    // case CellKind::SegmentedArrayKind:
+    // case CellKind::SegmentedArraySmallKind:
+    // case CellKind::SegmentKind:
+    // case CellKind::SegmentSmallKind:
+      return true;
+    default:
+      return false;
+  }
+}
 struct MallocGC::MarkingAcceptor final : public RootAcceptor,
                                          public WeakRootAcceptor {
   MallocGC &gc;
@@ -74,6 +93,9 @@ struct MallocGC::MarkingAcceptor final : public RootAcceptor,
           new (checkedMalloc(trimmedSize + sizeof(CellHeader))) CellHeader();
       newLocation->mark();
       memcpy(newLocation->data(), cell, trimmedSize);
+      if (shouldTraceRestraceCell(cell) && trimmedSize > 0) {
+        OH_RESTRACE(newLocation->data(), trimmedSize);
+      }
       if (origSize != trimmedSize) {
         auto *newVarCell =
             reinterpret_cast<VariableSizeRuntimeCell *>(newLocation->data());
@@ -340,6 +362,9 @@ void MallocGC::collect(std::string cause, bool /*canEffectiveOOM*/) {
           untrackObject(cell, freedSize);
         }
       }
+      if (shouldTraceRestraceCell(cell) && freedSize > 0) {
+        OH_RESTRACE_FREE_REGION(cell, freedSize);
+      }
 #ifndef NDEBUG
       // Before free'ing, fill with a dead value for debugging
       std::fill_n(reinterpret_cast<char *>(cell), freedSize, kInvalidHeapValue);