@@ -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")
@@ -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;
@@ -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)
@@ -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.
new file mode 100755
@@ -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_
@@ -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);
}
@@ -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;
}
@@ -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) {
@@ -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);
}
@@ -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();
@@ -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);