summaryrefslogtreecommitdiff
path: root/deps/v8/tools/debug_helper
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/tools/debug_helper')
-rw-r--r--deps/v8/tools/debug_helper/BUILD.gn104
-rw-r--r--deps/v8/tools/debug_helper/DEPS3
-rw-r--r--deps/v8/tools/debug_helper/README.md6
-rw-r--r--deps/v8/tools/debug_helper/debug-helper-internal.cc58
-rw-r--r--deps/v8/tools/debug_helper/debug-helper-internal.h130
-rw-r--r--deps/v8/tools/debug_helper/debug-helper.h177
-rw-r--r--deps/v8/tools/debug_helper/gen-heap-constants.py63
-rw-r--r--deps/v8/tools/debug_helper/get-object-properties.cc535
-rw-r--r--deps/v8/tools/debug_helper/heap-constants.cc51
-rw-r--r--deps/v8/tools/debug_helper/heap-constants.h28
10 files changed, 1155 insertions, 0 deletions
diff --git a/deps/v8/tools/debug_helper/BUILD.gn b/deps/v8/tools/debug_helper/BUILD.gn
new file mode 100644
index 0000000000..c81fddc9e5
--- /dev/null
+++ b/deps/v8/tools/debug_helper/BUILD.gn
@@ -0,0 +1,104 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("../../gni/snapshot_toolchain.gni")
+import("../../gni/v8.gni")
+
+config("internal_config") {
+ visibility = [ ":*" ] # Only targets in this file can depend on this.
+
+ if (is_component_build) {
+ defines = [ "BUILDING_V8_DEBUG_HELPER" ]
+ }
+
+ include_dirs = [
+ ".",
+ "../..",
+ "$target_gen_dir",
+ "$target_gen_dir/../..",
+ ]
+}
+
+# This config should be applied to code using v8_debug_helper.
+config("external_config") {
+ if (is_component_build) {
+ defines = [ "USING_V8_DEBUG_HELPER" ]
+ }
+ include_dirs = [ "." ]
+}
+
+action("run_mkgrokdump") {
+ testonly = true
+ visibility = [ ":*" ]
+
+ deps = [
+ "../../test/mkgrokdump:mkgrokdump($v8_generator_toolchain)",
+ ]
+
+ script = "../run.py"
+
+ outputs = [
+ "$target_gen_dir/v8heapconst.py",
+ ]
+
+ args = [
+ "./" + rebase_path(
+ get_label_info(
+ "../../test/mkgrokdump:mkgrokdump($v8_generator_toolchain)",
+ "root_out_dir") + "/mkgrokdump",
+ root_build_dir),
+ "--outfile",
+ rebase_path("$target_gen_dir/v8heapconst.py", root_build_dir),
+ ]
+}
+
+action("gen_heap_constants") {
+ testonly = true
+ visibility = [ ":*" ]
+ deps = [
+ ":run_mkgrokdump",
+ ]
+ script = "gen-heap-constants.py"
+ outputs = [
+ "$target_gen_dir/heap-constants-gen.cc",
+ ]
+ args = [
+ rebase_path(target_gen_dir, root_build_dir),
+ rebase_path("$target_gen_dir/heap-constants-gen.cc", root_build_dir),
+ ]
+}
+
+v8_component("v8_debug_helper") {
+ testonly = true
+
+ public = [
+ "debug-helper.h",
+ ]
+
+ sources = [
+ "$target_gen_dir/../../torque-generated/class-debug-readers-tq.cc",
+ "$target_gen_dir/../../torque-generated/class-debug-readers-tq.h",
+ "$target_gen_dir/heap-constants-gen.cc",
+ "debug-helper-internal.cc",
+ "debug-helper-internal.h",
+ "debug-helper.h",
+ "get-object-properties.cc",
+ "heap-constants.cc",
+ "heap-constants.h",
+ ]
+
+ deps = [
+ ":gen_heap_constants",
+ "../..:run_torque",
+ "../..:v8_headers",
+ "../..:v8_libbase",
+ ]
+
+ configs = [ ":internal_config" ]
+ if (v8_enable_i18n_support) {
+ configs += [ "//third_party/icu:icu_config" ]
+ }
+
+ public_configs = [ ":external_config" ]
+}
diff --git a/deps/v8/tools/debug_helper/DEPS b/deps/v8/tools/debug_helper/DEPS
new file mode 100644
index 0000000000..2c6adb4df5
--- /dev/null
+++ b/deps/v8/tools/debug_helper/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+torque-generated"
+]
diff --git a/deps/v8/tools/debug_helper/README.md b/deps/v8/tools/debug_helper/README.md
new file mode 100644
index 0000000000..bc99569c43
--- /dev/null
+++ b/deps/v8/tools/debug_helper/README.md
@@ -0,0 +1,6 @@
+# V8 debug helper
+
+This library is for debugging V8 itself, not debugging JavaScript running within
+V8. It is designed to be called from a debugger extension running within a
+native debugger such as WinDbg or LLDB. It can be used on live processes or
+crash dumps, and cannot assume that all memory is available in a dump.
diff --git a/deps/v8/tools/debug_helper/debug-helper-internal.cc b/deps/v8/tools/debug_helper/debug-helper-internal.cc
new file mode 100644
index 0000000000..ee5629b438
--- /dev/null
+++ b/deps/v8/tools/debug_helper/debug-helper-internal.cc
@@ -0,0 +1,58 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "debug-helper-internal.h"
+#include "src/common/ptr-compr-inl.h"
+#include "torque-generated/class-debug-readers-tq.h"
+
+namespace i = v8::internal;
+
+namespace v8_debug_helper_internal {
+
+bool IsPointerCompressed(uintptr_t address) {
+#if COMPRESS_POINTERS_BOOL
+ STATIC_ASSERT(i::kPtrComprHeapReservationSize == uintptr_t{1} << 32);
+ intptr_t signed_address = static_cast<intptr_t>(address);
+ return signed_address >= INT32_MIN && signed_address <= INT32_MAX;
+#else
+ return false;
+#endif
+}
+
+uintptr_t Decompress(uintptr_t address, uintptr_t any_uncompressed_ptr) {
+ if (!COMPRESS_POINTERS_BOOL || !IsPointerCompressed(address)) return address;
+ return i::DecompressTaggedAny(any_uncompressed_ptr,
+ static_cast<i::Tagged_t>(address));
+}
+
+d::PropertyKind GetArrayKind(d::MemoryAccessResult mem_result) {
+ d::PropertyKind indexed_field_kind{};
+ switch (mem_result) {
+ case d::MemoryAccessResult::kOk:
+ indexed_field_kind = d::PropertyKind::kArrayOfKnownSize;
+ break;
+ case d::MemoryAccessResult::kAddressNotValid:
+ indexed_field_kind =
+ d::PropertyKind::kArrayOfUnknownSizeDueToInvalidMemory;
+ break;
+ default:
+ indexed_field_kind =
+ d::PropertyKind::kArrayOfUnknownSizeDueToValidButInaccessibleMemory;
+ break;
+ }
+ return indexed_field_kind;
+}
+
+std::vector<std::unique_ptr<ObjectProperty>> TqObject::GetProperties(
+ d::MemoryAccessor accessor) const {
+ return std::vector<std::unique_ptr<ObjectProperty>>();
+}
+
+const char* TqObject::GetName() const { return "v8::internal::Object"; }
+
+void TqObject::Visit(TqObjectVisitor* visitor) const {
+ visitor->VisitObject(this);
+}
+
+} // namespace v8_debug_helper_internal
diff --git a/deps/v8/tools/debug_helper/debug-helper-internal.h b/deps/v8/tools/debug_helper/debug-helper-internal.h
new file mode 100644
index 0000000000..82506c0941
--- /dev/null
+++ b/deps/v8/tools/debug_helper/debug-helper-internal.h
@@ -0,0 +1,130 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines internal versions of the public API structs. These should
+// all be tidy and simple classes which maintain proper ownership (unique_ptr)
+// of each other. Each contains an instance of its corresponding public type,
+// which can be filled out with GetPublicView.
+
+#ifndef V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_INTERNAL_H_
+#define V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_INTERNAL_H_
+
+#include <string>
+#include <vector>
+
+#include "debug-helper.h"
+#include "src/objects/instance-type.h"
+
+namespace d = v8::debug_helper;
+
+namespace v8_debug_helper_internal {
+
+// A value that was read from the debuggee's memory.
+template <typename TValue>
+struct Value {
+ d::MemoryAccessResult validity;
+ TValue value;
+};
+
+class ObjectProperty {
+ public:
+ inline ObjectProperty(std::string name, std::string type,
+ std::string decompressed_type, uintptr_t address,
+ size_t num_values = 1,
+ d::PropertyKind kind = d::PropertyKind::kSingle)
+ : name_(name),
+ type_(type),
+ decompressed_type_(decompressed_type),
+ address_(address),
+ num_values_(num_values),
+ kind_(kind) {}
+
+ inline d::ObjectProperty* GetPublicView() {
+ public_view_.name = name_.c_str();
+ public_view_.type = type_.c_str();
+ public_view_.decompressed_type = decompressed_type_.c_str();
+ public_view_.address = address_;
+ public_view_.num_values = num_values_;
+ public_view_.kind = kind_;
+ return &public_view_;
+ }
+
+ private:
+ std::string name_;
+ std::string type_;
+ std::string decompressed_type_;
+ uintptr_t address_;
+ size_t num_values_;
+ d::PropertyKind kind_;
+
+ d::ObjectProperty public_view_;
+};
+
+class ObjectPropertiesResult;
+using ObjectPropertiesResultInternal = ObjectPropertiesResult;
+
+struct ObjectPropertiesResultExtended : public d::ObjectPropertiesResult {
+ ObjectPropertiesResultInternal* base; // Back reference for cleanup
+};
+
+class ObjectPropertiesResult {
+ public:
+ inline ObjectPropertiesResult(
+ d::TypeCheckResult type_check_result, std::string brief, std::string type,
+ std::vector<std::unique_ptr<ObjectProperty>> properties)
+ : type_check_result_(type_check_result),
+ brief_(brief),
+ type_(type),
+ properties_(std::move(properties)) {}
+
+ inline void Prepend(const char* prefix) { brief_ = prefix + brief_; }
+
+ inline d::ObjectPropertiesResult* GetPublicView() {
+ public_view_.type_check_result = type_check_result_;
+ public_view_.brief = brief_.c_str();
+ public_view_.type = type_.c_str();
+ public_view_.num_properties = properties_.size();
+ properties_raw_.resize(0);
+ for (const auto& property : properties_) {
+ properties_raw_.push_back(property->GetPublicView());
+ }
+ public_view_.properties = properties_raw_.data();
+ public_view_.base = this;
+ return &public_view_;
+ }
+
+ private:
+ d::TypeCheckResult type_check_result_;
+ std::string brief_;
+ std::string type_;
+ std::vector<std::unique_ptr<ObjectProperty>> properties_;
+
+ ObjectPropertiesResultExtended public_view_;
+ std::vector<d::ObjectProperty*> properties_raw_;
+};
+
+class TqObjectVisitor;
+
+// Base class representing a V8 object in the debuggee's address space.
+// Subclasses for specific object types are generated by the Torque compiler.
+class TqObject {
+ public:
+ inline TqObject(uintptr_t address) : address_(address) {}
+ virtual ~TqObject() = default;
+ virtual std::vector<std::unique_ptr<ObjectProperty>> GetProperties(
+ d::MemoryAccessor accessor) const;
+ virtual const char* GetName() const;
+ virtual void Visit(TqObjectVisitor* visitor) const;
+
+ protected:
+ uintptr_t address_;
+};
+
+bool IsPointerCompressed(uintptr_t address);
+uintptr_t Decompress(uintptr_t address, uintptr_t any_uncompressed_address);
+d::PropertyKind GetArrayKind(d::MemoryAccessResult mem_result);
+
+} // namespace v8_debug_helper_internal
+
+#endif
diff --git a/deps/v8/tools/debug_helper/debug-helper.h b/deps/v8/tools/debug_helper/debug-helper.h
new file mode 100644
index 0000000000..9bbec76c7c
--- /dev/null
+++ b/deps/v8/tools/debug_helper/debug-helper.h
@@ -0,0 +1,177 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the public interface to v8_debug_helper.
+
+#ifndef V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_H_
+#define V8_TOOLS_DEBUG_HELPER_DEBUG_HELPER_H_
+
+#include <cstdint>
+#include <memory>
+
+#if defined(_WIN32)
+
+#ifdef BUILDING_V8_DEBUG_HELPER
+#define V8_DEBUG_HELPER_EXPORT __declspec(dllexport)
+#elif USING_V8_DEBUG_HELPER
+#define V8_DEBUG_HELPER_EXPORT __declspec(dllimport)
+#else
+#define V8_DEBUG_HELPER_EXPORT
+#endif
+
+#else // defined(_WIN32)
+
+#ifdef BUILDING_V8_DEBUG_HELPER
+#define V8_DEBUG_HELPER_EXPORT __attribute__((visibility("default")))
+#else
+#define V8_DEBUG_HELPER_EXPORT
+#endif
+
+#endif // defined(_WIN32)
+
+namespace v8 {
+namespace debug_helper {
+
+// Possible results when attempting to fetch memory from the debuggee.
+enum class MemoryAccessResult {
+ kOk,
+ kAddressNotValid,
+ kAddressValidButInaccessible, // Possible in incomplete dump.
+};
+
+// Information about how this tool discovered the type of the object.
+enum class TypeCheckResult {
+ // Success cases:
+ kSmi,
+ kWeakRef,
+ kUsedMap,
+ kUsedTypeHint,
+
+ // Failure cases:
+ kUnableToDecompress, // Caller must provide the heap range somehow.
+ kObjectPointerInvalid,
+ kObjectPointerValidButInaccessible, // Possible in incomplete dump.
+ kMapPointerInvalid,
+ kMapPointerValidButInaccessible, // Possible in incomplete dump.
+ kUnknownInstanceType,
+ kUnknownTypeHint,
+};
+
+enum class PropertyKind {
+ kSingle,
+ kArrayOfKnownSize,
+ kArrayOfUnknownSizeDueToInvalidMemory,
+ kArrayOfUnknownSizeDueToValidButInaccessibleMemory,
+};
+
+struct ObjectProperty {
+ const char* name;
+
+ // Statically-determined type, such as from .tq definition.
+ const char* type;
+
+ // In some cases, |type| may be a simple type representing a compressed
+ // pointer such as v8::internal::TaggedValue. In those cases,
+ // |decompressed_type| will contain the type of the object when decompressed.
+ // Otherwise, |decompressed_type| will match |type|. In any case, it is safe
+ // to pass the |decompressed_type| value as the type_hint on a subsequent call
+ // to GetObjectProperties.
+ const char* decompressed_type;
+
+ // The address where the property value can be found in the debuggee's address
+ // space, or the address of the first value for an array.
+ uintptr_t address;
+
+ // If kind indicates an array of unknown size, num_values will be 0 and debug
+ // tools should display this property as a raw pointer. Note that there is a
+ // semantic difference between num_values=1 and kind=kSingle (normal property)
+ // versus num_values=1 and kind=kArrayOfKnownSize (one-element array).
+ size_t num_values;
+
+ PropertyKind kind;
+};
+
+struct ObjectPropertiesResult {
+ TypeCheckResult type_check_result;
+ const char* brief;
+ const char* type; // Runtime type of the object.
+ size_t num_properties;
+ ObjectProperty** properties;
+};
+
+// Copies byte_count bytes of memory from the given address in the debuggee to
+// the destination buffer.
+typedef MemoryAccessResult (*MemoryAccessor)(uintptr_t address,
+ uint8_t* destination,
+ size_t byte_count);
+
+// Additional data that can help GetObjectProperties to be more accurate. Any
+// fields you don't know can be set to zero and this library will do the best it
+// can with the information available.
+struct Roots {
+ // Beginning of allocated space for various kinds of data. These can help us
+ // to detect certain common objects that are placed in memory during startup.
+ // These values might be provided via name-value pairs in CrashPad dumps.
+ // Otherwise, they can be obtained as follows:
+ // 1. Get the Isolate pointer for the current thread. It might be somewhere on
+ // the stack, or it might be accessible from thread-local storage with the
+ // key stored in v8::internal::Isolate::isolate_key_.
+ // 2. Get isolate->heap_.map_space_->memory_chunk_list_.front_ and similar for
+ // old_space_ and read_only_space_.
+ uintptr_t map_space;
+ uintptr_t old_space;
+ uintptr_t read_only_space;
+
+ // Any valid heap pointer address. On platforms where pointer compression is
+ // enabled, this can allow us to get data from compressed pointers even if the
+ // other data above is not provided. The Isolate pointer is valid for this
+ // purpose if you have it.
+ uintptr_t any_heap_pointer;
+};
+
+} // namespace debug_helper
+} // namespace v8
+
+extern "C" {
+// Raw library interface. If possible, use functions in v8::debug_helper
+// namespace instead because they use smart pointers to prevent leaks.
+V8_DEBUG_HELPER_EXPORT v8::debug_helper::ObjectPropertiesResult*
+_v8_debug_helper_GetObjectProperties(
+ uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor,
+ const v8::debug_helper::Roots& heap_roots, const char* type_hint);
+V8_DEBUG_HELPER_EXPORT void _v8_debug_helper_Free_ObjectPropertiesResult(
+ v8::debug_helper::ObjectPropertiesResult* result);
+}
+
+namespace v8 {
+namespace debug_helper {
+
+struct DebugHelperObjectPropertiesResultDeleter {
+ void operator()(v8::debug_helper::ObjectPropertiesResult* ptr) {
+ _v8_debug_helper_Free_ObjectPropertiesResult(ptr);
+ }
+};
+using ObjectPropertiesResultPtr =
+ std::unique_ptr<ObjectPropertiesResult,
+ DebugHelperObjectPropertiesResultDeleter>;
+
+// Get information about the given object pointer, which could be:
+// - A tagged pointer, strong or weak
+// - A cleared weak pointer
+// - A compressed tagged pointer, sign-extended to 64 bits
+// - A tagged small integer
+// The type hint is only used if the object's Map is missing or corrupt. It
+// should be the fully-qualified name of a class that inherits from
+// v8::internal::Object.
+inline ObjectPropertiesResultPtr GetObjectProperties(
+ uintptr_t object, v8::debug_helper::MemoryAccessor memory_accessor,
+ const Roots& heap_roots, const char* type_hint = nullptr) {
+ return ObjectPropertiesResultPtr(_v8_debug_helper_GetObjectProperties(
+ object, memory_accessor, heap_roots, type_hint));
+}
+
+} // namespace debug_helper
+} // namespace v8
+
+#endif
diff --git a/deps/v8/tools/debug_helper/gen-heap-constants.py b/deps/v8/tools/debug_helper/gen-heap-constants.py
new file mode 100644
index 0000000000..0fd575a994
--- /dev/null
+++ b/deps/v8/tools/debug_helper/gen-heap-constants.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""This program writes a C++ file that can be used to look up whether a given
+address matches known object locations. The first argument is the directory
+containing the file v8heapconst.py; the second argument is the output .cc file.
+"""
+
+import sys
+sys.path.insert(0, sys.argv[1])
+import v8heapconst
+
+out = """
+#include <cstdint>
+#include <string>
+
+namespace v8_debug_helper_internal {
+"""
+
+def iterate_objects(target_space, camel_space_name):
+ global out
+ result = []
+ for (space, offset), (instance_type, name) in v8heapconst.KNOWN_MAPS.items():
+ if space == target_space:
+ result.append((offset, name))
+ for (space, offset), name in v8heapconst.KNOWN_OBJECTS.items():
+ if space == target_space:
+ result.append((offset, name))
+ out = out + '\nstd::string FindKnownObjectIn' + camel_space_name \
+ + '(uintptr_t offset) {\n switch (offset) {\n'
+ for offset, name in result:
+ out = out + ' case ' + str(offset) + ': return "' + name + '";\n'
+ out = out + ' default: return "";\n }\n}\n'
+
+iterate_objects('map_space', 'MapSpace')
+iterate_objects('read_only_space', 'ReadOnlySpace')
+iterate_objects('old_space', 'OldSpace')
+
+def iterate_maps(target_space, camel_space_name):
+ global out
+ out = out + '\nint FindKnownMapInstanceTypeIn' + camel_space_name \
+ + '(uintptr_t offset) {\n switch (offset) {\n'
+ for (space, offset), (instance_type, name) in v8heapconst.KNOWN_MAPS.items():
+ if space == target_space:
+ out = out + ' case ' + str(offset) + ': return ' + str(instance_type) \
+ + ';\n'
+ out = out + ' default: return -1;\n }\n}\n'
+
+iterate_maps('map_space', 'MapSpace')
+iterate_maps('read_only_space', 'ReadOnlySpace')
+
+out = out + '\n}\n'
+
+try:
+ with open(sys.argv[2], "r") as out_file:
+ if out == out_file.read():
+ sys.exit(0) # No modification needed.
+except:
+ pass # File probably doesn't exist; write it.
+with open(sys.argv[2], "w") as out_file:
+ out_file.write(out)
diff --git a/deps/v8/tools/debug_helper/get-object-properties.cc b/deps/v8/tools/debug_helper/get-object-properties.cc
new file mode 100644
index 0000000000..fbe992c40e
--- /dev/null
+++ b/deps/v8/tools/debug_helper/get-object-properties.cc
@@ -0,0 +1,535 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+
+#include "debug-helper-internal.h"
+#include "heap-constants.h"
+#include "include/v8-internal.h"
+#include "src/common/ptr-compr-inl.h"
+#include "src/objects/string-inl.h"
+#include "src/strings/unicode-inl.h"
+#include "torque-generated/class-debug-readers-tq.h"
+
+namespace i = v8::internal;
+
+namespace v8_debug_helper_internal {
+
+// INSTANCE_TYPE_CHECKERS_SINGLE_BASE, trimmed down to only classes that have
+// layouts defined in .tq files (this subset relationship is asserted below).
+// For now, this is a hand-maintained list.
+// TODO(v8:7793): Torque should know enough about instance types to generate
+// this list.
+#define TQ_INSTANCE_TYPES_SINGLE_BASE(V) \
+ V(ByteArray, BYTE_ARRAY_TYPE) \
+ V(BytecodeArray, BYTECODE_ARRAY_TYPE) \
+ V(CallHandlerInfo, CALL_HANDLER_INFO_TYPE) \
+ V(Cell, CELL_TYPE) \
+ V(DescriptorArray, DESCRIPTOR_ARRAY_TYPE) \
+ V(EmbedderDataArray, EMBEDDER_DATA_ARRAY_TYPE) \
+ V(FeedbackCell, FEEDBACK_CELL_TYPE) \
+ V(FeedbackVector, FEEDBACK_VECTOR_TYPE) \
+ V(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE) \
+ V(Foreign, FOREIGN_TYPE) \
+ V(FreeSpace, FREE_SPACE_TYPE) \
+ V(HeapNumber, HEAP_NUMBER_TYPE) \
+ V(JSArgumentsObject, JS_ARGUMENTS_TYPE) \
+ V(JSArray, JS_ARRAY_TYPE) \
+ V(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE) \
+ V(JSArrayIterator, JS_ARRAY_ITERATOR_TYPE) \
+ V(JSAsyncFromSyncIterator, JS_ASYNC_FROM_SYNC_ITERATOR_TYPE) \
+ V(JSAsyncFunctionObject, JS_ASYNC_FUNCTION_OBJECT_TYPE) \
+ V(JSAsyncGeneratorObject, JS_ASYNC_GENERATOR_OBJECT_TYPE) \
+ V(JSBoundFunction, JS_BOUND_FUNCTION_TYPE) \
+ V(JSDataView, JS_DATA_VIEW_TYPE) \
+ V(JSDate, JS_DATE_TYPE) \
+ V(JSFunction, JS_FUNCTION_TYPE) \
+ V(JSGlobalObject, JS_GLOBAL_OBJECT_TYPE) \
+ V(JSGlobalProxy, JS_GLOBAL_PROXY_TYPE) \
+ V(JSMap, JS_MAP_TYPE) \
+ V(JSMessageObject, JS_MESSAGE_OBJECT_TYPE) \
+ V(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE) \
+ V(JSPromise, JS_PROMISE_TYPE) \
+ V(JSProxy, JS_PROXY_TYPE) \
+ V(JSRegExp, JS_REGEXP_TYPE) \
+ V(JSRegExpStringIterator, JS_REGEXP_STRING_ITERATOR_TYPE) \
+ V(JSSet, JS_SET_TYPE) \
+ V(JSStringIterator, JS_STRING_ITERATOR_TYPE) \
+ V(JSTypedArray, JS_TYPED_ARRAY_TYPE) \
+ V(JSPrimitiveWrapper, JS_PRIMITIVE_WRAPPER_TYPE) \
+ V(JSFinalizationGroup, JS_FINALIZATION_GROUP_TYPE) \
+ V(JSFinalizationGroupCleanupIterator, \
+ JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE) \
+ V(JSWeakMap, JS_WEAK_MAP_TYPE) \
+ V(JSWeakRef, JS_WEAK_REF_TYPE) \
+ V(JSWeakSet, JS_WEAK_SET_TYPE) \
+ V(Map, MAP_TYPE) \
+ V(Oddball, ODDBALL_TYPE) \
+ V(PreparseData, PREPARSE_DATA_TYPE) \
+ V(PropertyArray, PROPERTY_ARRAY_TYPE) \
+ V(PropertyCell, PROPERTY_CELL_TYPE) \
+ V(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE) \
+ V(Symbol, SYMBOL_TYPE) \
+ V(WasmExceptionObject, WASM_EXCEPTION_TYPE) \
+ V(WasmGlobalObject, WASM_GLOBAL_TYPE) \
+ V(WasmMemoryObject, WASM_MEMORY_TYPE) \
+ V(WasmModuleObject, WASM_MODULE_TYPE) \
+ V(WasmTableObject, WASM_TABLE_TYPE) \
+ V(WeakArrayList, WEAK_ARRAY_LIST_TYPE) \
+ V(WeakCell, WEAK_CELL_TYPE)
+#ifdef V8_INTL_SUPPORT
+
+#define TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) \
+ TQ_INSTANCE_TYPES_SINGLE_BASE(V) \
+ V(JSV8BreakIterator, JS_INTL_V8_BREAK_ITERATOR_TYPE) \
+ V(JSCollator, JS_INTL_COLLATOR_TYPE) \
+ V(JSDateTimeFormat, JS_INTL_DATE_TIME_FORMAT_TYPE) \
+ V(JSListFormat, JS_INTL_LIST_FORMAT_TYPE) \
+ V(JSLocale, JS_INTL_LOCALE_TYPE) \
+ V(JSNumberFormat, JS_INTL_NUMBER_FORMAT_TYPE) \
+ V(JSPluralRules, JS_INTL_PLURAL_RULES_TYPE) \
+ V(JSRelativeTimeFormat, JS_INTL_RELATIVE_TIME_FORMAT_TYPE) \
+ V(JSSegmentIterator, JS_INTL_SEGMENT_ITERATOR_TYPE) \
+ V(JSSegmenter, JS_INTL_SEGMENTER_TYPE)
+
+#else
+
+#define TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) TQ_INSTANCE_TYPES_SINGLE_BASE(V)
+
+#endif // V8_INTL_SUPPORT
+
+enum class InstanceTypeCheckersSingle {
+#define ENUM_VALUE(ClassName, INSTANCE_TYPE) k##ClassName = i::INSTANCE_TYPE,
+ INSTANCE_TYPE_CHECKERS_SINGLE(ENUM_VALUE)
+#undef ENUM_VALUE
+};
+
+#define CHECK_VALUE(ClassName, INSTANCE_TYPE) \
+ static_assert( \
+ static_cast<i::InstanceType>( \
+ InstanceTypeCheckersSingle::k##ClassName) == i::INSTANCE_TYPE, \
+ "TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS must be subset of " \
+ "INSTANCE_TYPE_CHECKERS_SINGLE. Invalid class: " #ClassName);
+TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(CHECK_VALUE)
+#undef CHECK_VALUE
+
+// Adapts one STRUCT_LIST_GENERATOR entry to (Name, NAME) format.
+#define STRUCT_INSTANCE_TYPE_ADAPTER(V, NAME, Name, name) V(Name, NAME)
+
+#define TQ_INSTANCE_TYPES_SINGLE(V) \
+ TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS(V) \
+ STRUCT_LIST_GENERATOR(STRUCT_INSTANCE_TYPE_ADAPTER, V)
+
+// Likewise, these are the subset of INSTANCE_TYPE_CHECKERS_RANGE that have
+// definitions in .tq files, rearranged with more specific things first. Also
+// includes JSObject and JSReceiver, which in the runtime are optimized to use
+// a one-sided check.
+#define TQ_INSTANCE_TYPES_RANGE(V) \
+ V(Context, FIRST_CONTEXT_TYPE, LAST_CONTEXT_TYPE) \
+ V(FixedArray, FIRST_FIXED_ARRAY_TYPE, LAST_FIXED_ARRAY_TYPE) \
+ V(Microtask, FIRST_MICROTASK_TYPE, LAST_MICROTASK_TYPE) \
+ V(String, FIRST_STRING_TYPE, LAST_STRING_TYPE) \
+ V(Name, FIRST_NAME_TYPE, LAST_NAME_TYPE) \
+ V(WeakFixedArray, FIRST_WEAK_FIXED_ARRAY_TYPE, LAST_WEAK_FIXED_ARRAY_TYPE) \
+ V(JSObject, FIRST_JS_OBJECT_TYPE, LAST_JS_OBJECT_TYPE) \
+ V(JSReceiver, FIRST_JS_RECEIVER_TYPE, LAST_JS_RECEIVER_TYPE)
+
+std::string AppendAddressAndType(const std::string& brief, uintptr_t address,
+ const char* type) {
+ std::stringstream brief_stream;
+ brief_stream << "0x" << std::hex << address << " <" << type << ">";
+ return brief.empty() ? brief_stream.str()
+ : brief + " (" + brief_stream.str() + ")";
+}
+
+struct TypedObject {
+ TypedObject(d::TypeCheckResult type_check_result,
+ std::unique_ptr<TqObject> object)
+ : type_check_result(type_check_result), object(std::move(object)) {}
+ d::TypeCheckResult type_check_result;
+ std::unique_ptr<TqObject> object;
+};
+
+TypedObject GetTypedObjectByHint(uintptr_t address,
+ std::string type_hint_string) {
+#define TYPE_NAME_CASE(ClassName, ...) \
+ if (type_hint_string == "v8::internal::" #ClassName) { \
+ return {d::TypeCheckResult::kUsedTypeHint, \
+ v8::base::make_unique<Tq##ClassName>(address)}; \
+ }
+
+ TQ_INSTANCE_TYPES_SINGLE(TYPE_NAME_CASE)
+ TQ_INSTANCE_TYPES_RANGE(TYPE_NAME_CASE)
+
+#undef TYPE_NAME_CASE
+
+ return {d::TypeCheckResult::kUnknownTypeHint,
+ v8::base::make_unique<TqHeapObject>(address)};
+}
+
+TypedObject GetTypedObjectForString(uintptr_t address, i::InstanceType type) {
+ class StringGetDispatcher : public i::AllStatic {
+ public:
+#define DEFINE_METHOD(ClassName) \
+ static inline TypedObject Handle##ClassName(uintptr_t address) { \
+ return {d::TypeCheckResult::kUsedMap, \
+ v8::base::make_unique<Tq##ClassName>(address)}; \
+ }
+ STRING_CLASS_TYPES(DEFINE_METHOD)
+#undef DEFINE_METHOD
+ static inline TypedObject HandleInvalidString(uintptr_t address) {
+ return {d::TypeCheckResult::kUnknownInstanceType,
+ v8::base::make_unique<TqString>(address)};
+ }
+ };
+
+ return i::StringShape(type)
+ .DispatchToSpecificTypeWithoutCast<StringGetDispatcher, TypedObject>(
+ address);
+}
+
+TypedObject GetTypedHeapObject(uintptr_t address, d::MemoryAccessor accessor,
+ const char* type_hint) {
+ auto heap_object = v8::base::make_unique<TqHeapObject>(address);
+ Value<uintptr_t> map_ptr = heap_object->GetMapValue(accessor);
+
+ if (map_ptr.validity != d::MemoryAccessResult::kOk) {
+ return {map_ptr.validity == d::MemoryAccessResult::kAddressNotValid
+ ? d::TypeCheckResult::kObjectPointerInvalid
+ : d::TypeCheckResult::kObjectPointerValidButInaccessible,
+ std::move(heap_object)};
+ }
+ Value<i::InstanceType> type =
+ TqMap(map_ptr.value).GetInstanceTypeValue(accessor);
+
+ if (type.validity == d::MemoryAccessResult::kOk) {
+ // Dispatch to the appropriate method for each instance type. After calling
+ // the generated method to fetch properties, we can add custom properties.
+ switch (type.value) {
+#define INSTANCE_TYPE_CASE(ClassName, INSTANCE_TYPE) \
+ case i::INSTANCE_TYPE: \
+ return {d::TypeCheckResult::kUsedMap, \
+ v8::base::make_unique<Tq##ClassName>(address)};
+ TQ_INSTANCE_TYPES_SINGLE(INSTANCE_TYPE_CASE)
+#undef INSTANCE_TYPE_CASE
+
+ default:
+
+ // Special case: concrete subtypes of String are not included in the
+ // main instance type list because they use the low bits of the instance
+ // type enum as flags.
+ if (type.value <= i::LAST_STRING_TYPE) {
+ return GetTypedObjectForString(address, type.value);
+ }
+
+#define INSTANCE_RANGE_CASE(ClassName, FIRST_TYPE, LAST_TYPE) \
+ if (type.value >= i::FIRST_TYPE && type.value <= i::LAST_TYPE) { \
+ return {d::TypeCheckResult::kUsedMap, \
+ v8::base::make_unique<Tq##ClassName>(address)}; \
+ }
+ TQ_INSTANCE_TYPES_RANGE(INSTANCE_RANGE_CASE)
+#undef INSTANCE_RANGE_CASE
+
+ return {d::TypeCheckResult::kUnknownInstanceType,
+ std::move(heap_object)};
+ break;
+ }
+ } else if (type_hint != nullptr) {
+ // Try to use the provided type hint, since the real instance type is
+ // unavailable.
+ return GetTypedObjectByHint(address, type_hint);
+ } else {
+ // TODO(v8:9376): Use known maps here. If known map is just a guess (because
+ // root pointers weren't provided), then create a synthetic property with
+ // the more specific type. Then the caller could presumably ask us again
+ // with the type hint we provided. Otherwise, just go ahead and use it to
+ // generate properties.
+ return {type.validity == d::MemoryAccessResult::kAddressNotValid
+ ? d::TypeCheckResult::kMapPointerInvalid
+ : d::TypeCheckResult::kMapPointerValidButInaccessible,
+ std::move(heap_object)};
+ }
+}
+
+#undef STRUCT_INSTANCE_TYPE_ADAPTER
+#undef TQ_INSTANCE_TYPES_SINGLE_BASE
+#undef TQ_INSTANCE_TYPES_SINGLE
+#undef TQ_INSTANCE_TYPES_SINGLE_NOSTRUCTS
+#undef TQ_INSTANCE_TYPES_RANGE
+
+// An object visitor that accumulates the first few characters of a string.
+class ReadStringVisitor : public TqObjectVisitor {
+ public:
+ ReadStringVisitor(d::MemoryAccessor accessor)
+ : accessor_(accessor), index_(0), limit_(INT32_MAX), done_(false) {}
+
+ // Returns the result as UTF-8 once visiting is complete.
+ std::string GetString() {
+ std::vector<char> result(
+ string_.size() * unibrow::Utf16::kMaxExtraUtf8BytesForOneUtf16CodeUnit);
+ unsigned write_index = 0;
+ int prev_char = unibrow::Utf16::kNoPreviousCharacter;
+ for (size_t read_index = 0; read_index < string_.size(); ++read_index) {
+ uint16_t character = string_[read_index];
+ write_index +=
+ unibrow::Utf8::Encode(result.data() + write_index, character,
+ prev_char, /*replace_invalid=*/true);
+ prev_char = character;
+ }
+ return {result.data(), write_index};
+ }
+
+ template <typename T>
+ void ReadSeqString(const T* object) {
+ int32_t length = GetOrFinish(object->GetLengthValue(accessor_));
+ for (; index_ < length && index_ < limit_ && !done_; ++index_) {
+ char16_t c = static_cast<char16_t>(
+ GetOrFinish(object->GetCharsValue(accessor_, index_)));
+ if (!done_) AddCharacter(c);
+ }
+ }
+
+ void VisitSeqOneByteString(const TqSeqOneByteString* object) override {
+ ReadSeqString(object);
+ }
+
+ void VisitSeqTwoByteString(const TqSeqTwoByteString* object) override {
+ ReadSeqString(object);
+ }
+
+ void VisitConsString(const TqConsString* object) override {
+ uintptr_t first_address = GetOrFinish(object->GetFirstValue(accessor_));
+ if (done_) return;
+ auto first = GetTypedHeapObject(first_address, accessor_, nullptr).object;
+ first->Visit(this);
+ if (done_) return;
+ int32_t first_length = GetOrFinish(
+ static_cast<TqString*>(first.get())->GetLengthValue(accessor_));
+ uintptr_t second = GetOrFinish(object->GetSecondValue(accessor_));
+ if (done_) return;
+ IndexModifier modifier(this, -first_length, -first_length);
+ GetTypedHeapObject(second, accessor_, nullptr).object->Visit(this);
+ }
+
+ void VisitSlicedString(const TqSlicedString* object) override {
+ uintptr_t parent = GetOrFinish(object->GetParentValue(accessor_));
+ int32_t length = GetOrFinish(object->GetLengthValue(accessor_));
+ int32_t offset = i::PlatformSmiTagging::SmiToInt(
+ GetOrFinish(object->GetOffsetValue(accessor_)));
+ if (done_) return;
+ int32_t limit_adjust = offset + length - limit_;
+ IndexModifier modifier(this, offset, limit_adjust < 0 ? limit_adjust : 0);
+ GetTypedHeapObject(parent, accessor_, nullptr).object->Visit(this);
+ }
+
+ void VisitThinString(const TqThinString* object) override {
+ uintptr_t actual = GetOrFinish(object->GetActualValue(accessor_));
+ if (done_) return;
+ GetTypedHeapObject(actual, accessor_, nullptr).object->Visit(this);
+ }
+
+ void VisitExternalString(const TqExternalString* object) override {
+ // TODO(v8:9376): External strings are very common and important when
+ // attempting to print the source of a function in the browser. For now
+ // we're just ignoring them, but eventually we'll want some kind of
+ // mechanism where the user of this library can provide a callback function
+ // that fetches data from external strings.
+ AddEllipsisAndFinish();
+ }
+
+ void VisitObject(const TqObject* object) override {
+ // If we fail to find a specific type for a sub-object within a cons string,
+ // sliced string, or thin string, we will end up here.
+ AddEllipsisAndFinish();
+ }
+
+ private:
+ // Unpacks a value that was fetched from the debuggee. If the value indicates
+ // that it couldn't successfully fetch memory, then prevents further work.
+ template <typename T>
+ T GetOrFinish(Value<T> value) {
+ if (value.validity != d::MemoryAccessResult::kOk) {
+ AddEllipsisAndFinish();
+ }
+ return value.value;
+ }
+
+ void AddEllipsisAndFinish() {
+ if (!done_) {
+ string_ += u"...";
+ done_ = true;
+ }
+ }
+
+ void AddCharacter(char16_t c) {
+ if (string_.size() >= kMaxCharacters) {
+ AddEllipsisAndFinish();
+ } else {
+ string_.push_back(c);
+ }
+ }
+
+ // Temporarily adds offsets to both index_ and limit_, to handle ConsString
+ // and SlicedString.
+ class IndexModifier {
+ public:
+ IndexModifier(ReadStringVisitor* that, int32_t index_adjust,
+ int32_t limit_adjust)
+ : that_(that),
+ index_adjust_(index_adjust),
+ limit_adjust_(limit_adjust) {
+ that_->index_ += index_adjust_;
+ that_->limit_ += limit_adjust_;
+ }
+ ~IndexModifier() {
+ that_->index_ -= index_adjust_;
+ that_->limit_ -= limit_adjust_;
+ }
+
+ private:
+ ReadStringVisitor* that_;
+ int32_t index_adjust_;
+ int32_t limit_adjust_;
+ DISALLOW_COPY_AND_ASSIGN(IndexModifier);
+ };
+
+ static constexpr int kMaxCharacters = 80; // How many characters to print.
+
+ std::u16string string_; // Result string.
+ d::MemoryAccessor accessor_;
+ int32_t index_; // Index of next char to read.
+ int32_t limit_; // Don't read past this index (set by SlicedString).
+ bool done_; // Whether to stop further work.
+};
+
+// An object visitor that adds extra debugging information for some types.
+class AddInfoVisitor : public TqObjectVisitor {
+ public:
+ AddInfoVisitor(const std::string& brief, d::MemoryAccessor accessor)
+ : accessor_(accessor), brief_(brief) {}
+
+ // Returns the brief object description, once visiting is complete.
+ const std::string& GetBrief() { return brief_; }
+
+ void VisitString(const TqString* object) override {
+ ReadStringVisitor visitor(accessor_);
+ object->Visit(&visitor);
+ if (!brief_.empty()) brief_ += " ";
+ brief_ += "\"" + visitor.GetString() + "\"";
+ }
+
+ private:
+ d::MemoryAccessor accessor_;
+ std::string brief_;
+};
+
+std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
+ uintptr_t address, d::MemoryAccessor accessor, const char* type_hint,
+ std::string brief) {
+ TypedObject typed = GetTypedHeapObject(address, accessor, type_hint);
+
+ // TODO(v8:9376): Many object types need additional data that is not included
+ // in their Torque layout definitions. For example, JSObject has an array of
+ // in-object properties after its Torque-defined fields, which at a minimum
+ // should be represented as an array in this response. If the relevant memory
+ // is available, we should instead represent those properties (and any out-of-
+ // object properties) using their JavaScript property names.
+ AddInfoVisitor visitor(brief, accessor);
+ typed.object->Visit(&visitor);
+ brief = visitor.GetBrief();
+
+ brief = AppendAddressAndType(brief, address, typed.object->GetName());
+
+ return v8::base::make_unique<ObjectPropertiesResult>(
+ typed.type_check_result, brief, typed.object->GetName(),
+ typed.object->GetProperties(accessor));
+}
+
+std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
+ uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots,
+ const char* type_hint) {
+ // Try to figure out the heap range, for pointer compression (this is unused
+ // if pointer compression is disabled).
+ uintptr_t any_uncompressed_ptr = 0;
+ if (!IsPointerCompressed(address)) any_uncompressed_ptr = address;
+ if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.any_heap_pointer;
+ if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.map_space;
+ if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.old_space;
+ if (any_uncompressed_ptr == 0) any_uncompressed_ptr = roots.read_only_space;
+ if (any_uncompressed_ptr == 0) {
+ // We can't figure out the heap range. Just check for known objects.
+ std::string brief = FindKnownObject(address, roots);
+ brief = AppendAddressAndType(brief, address, "v8::internal::TaggedValue");
+ return v8::base::make_unique<ObjectPropertiesResult>(
+ d::TypeCheckResult::kUnableToDecompress, brief,
+ "v8::internal::TaggedValue",
+ std::vector<std::unique_ptr<ObjectProperty>>());
+ }
+
+ // TODO(v8:9376): It seems that the space roots are at predictable offsets
+ // within the heap reservation block when pointer compression is enabled, so
+ // we should be able to set those here.
+
+ address = Decompress(address, any_uncompressed_ptr);
+ // From here on all addresses should be decompressed.
+
+ // Regardless of whether we can read the object itself, maybe we can find its
+ // pointer in the list of known objects.
+ std::string brief = FindKnownObject(address, roots);
+ return GetHeapObjectProperties(address, memory_accessor, type_hint, brief);
+}
+
+std::unique_ptr<ObjectPropertiesResult> GetObjectPropertiesImpl(
+ uintptr_t address, d::MemoryAccessor memory_accessor, const d::Roots& roots,
+ const char* type_hint) {
+ std::vector<std::unique_ptr<ObjectProperty>> props;
+ if (static_cast<uint32_t>(address) == i::kClearedWeakHeapObjectLower32) {
+ return v8::base::make_unique<ObjectPropertiesResult>(
+ d::TypeCheckResult::kWeakRef, "cleared weak ref",
+ "v8::internal::HeapObject", std::move(props));
+ }
+ bool is_weak = (address & i::kHeapObjectTagMask) == i::kWeakHeapObjectTag;
+ if (is_weak) {
+ address &= ~i::kWeakHeapObjectMask;
+ }
+ if (i::Internals::HasHeapObjectTag(address)) {
+ std::unique_ptr<ObjectPropertiesResult> result =
+ GetHeapObjectProperties(address, memory_accessor, roots, type_hint);
+ if (is_weak) {
+ result->Prepend("weak ref to ");
+ }
+ return result;
+ }
+
+ // For smi values, construct a response with a description representing the
+ // untagged value.
+ int32_t value = i::PlatformSmiTagging::SmiToInt(address);
+ std::stringstream stream;
+ stream << value << " (0x" << std::hex << value << ")";
+ return v8::base::make_unique<ObjectPropertiesResult>(
+ d::TypeCheckResult::kSmi, stream.str(), "v8::internal::Smi",
+ std::move(props));
+}
+
+} // namespace v8_debug_helper_internal
+
+namespace di = v8_debug_helper_internal;
+
+extern "C" {
+V8_DEBUG_HELPER_EXPORT d::ObjectPropertiesResult*
+_v8_debug_helper_GetObjectProperties(uintptr_t object,
+ d::MemoryAccessor memory_accessor,
+ const d::Roots& heap_roots,
+ const char* type_hint) {
+ return di::GetObjectPropertiesImpl(object, memory_accessor, heap_roots,
+ type_hint)
+ .release()
+ ->GetPublicView();
+}
+V8_DEBUG_HELPER_EXPORT void _v8_debug_helper_Free_ObjectPropertiesResult(
+ d::ObjectPropertiesResult* result) {
+ std::unique_ptr<di::ObjectPropertiesResult> ptr(
+ static_cast<di::ObjectPropertiesResultExtended*>(result)->base);
+}
+}
diff --git a/deps/v8/tools/debug_helper/heap-constants.cc b/deps/v8/tools/debug_helper/heap-constants.cc
new file mode 100644
index 0000000000..2bd0420690
--- /dev/null
+++ b/deps/v8/tools/debug_helper/heap-constants.cc
@@ -0,0 +1,51 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "heap-constants.h"
+#include "src/common/globals.h"
+
+namespace d = v8::debug_helper;
+
+namespace v8_debug_helper_internal {
+
+std::string FindKnownObject(uintptr_t address, const d::Roots& roots) {
+ uintptr_t containing_page = address & ~i::kPageAlignmentMask;
+ uintptr_t offset_in_page = address & i::kPageAlignmentMask;
+
+ // If there's a match with a known root, then search only that page.
+ if (containing_page == roots.map_space) {
+ return FindKnownObjectInMapSpace(offset_in_page);
+ }
+ if (containing_page == roots.old_space) {
+ return FindKnownObjectInOldSpace(offset_in_page);
+ }
+ if (containing_page == roots.read_only_space) {
+ return FindKnownObjectInReadOnlySpace(offset_in_page);
+ }
+
+ // For any unknown roots, compile a list of things this object might be.
+ std::string result;
+ if (roots.map_space == 0) {
+ std::string sub_result = FindKnownObjectInMapSpace(offset_in_page);
+ if (!sub_result.empty()) {
+ result += "maybe " + sub_result;
+ }
+ }
+ if (roots.old_space == 0) {
+ std::string sub_result = FindKnownObjectInOldSpace(offset_in_page);
+ if (!sub_result.empty()) {
+ result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
+ }
+ }
+ if (roots.read_only_space == 0) {
+ std::string sub_result = FindKnownObjectInReadOnlySpace(offset_in_page);
+ if (!sub_result.empty()) {
+ result = (result.empty() ? "" : result + ", ") + "maybe " + sub_result;
+ }
+ }
+
+ return result;
+}
+
+} // namespace v8_debug_helper_internal
diff --git a/deps/v8/tools/debug_helper/heap-constants.h b/deps/v8/tools/debug_helper/heap-constants.h
new file mode 100644
index 0000000000..f3149bbb47
--- /dev/null
+++ b/deps/v8/tools/debug_helper/heap-constants.h
@@ -0,0 +1,28 @@
+// Copyright 2019 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_TOOLS_DEBUG_HELPER_HEAP_CONSTANTS_H_
+#define V8_TOOLS_DEBUG_HELPER_HEAP_CONSTANTS_H_
+
+#include <cstdint>
+#include <string>
+
+#include "debug-helper.h"
+
+namespace d = v8::debug_helper;
+
+namespace v8_debug_helper_internal {
+
+// Functions generated by mkgrokdump:
+std::string FindKnownObjectInOldSpace(uintptr_t offset);
+std::string FindKnownObjectInReadOnlySpace(uintptr_t offset);
+std::string FindKnownObjectInMapSpace(uintptr_t offset);
+std::string FindKnownMapInstanceTypeInMapSpace(uintptr_t offset);
+std::string FindKnownMapInstanceTypeInReadOnlySpace(uintptr_t offset);
+
+std::string FindKnownObject(uintptr_t address, const d::Roots& roots);
+
+} // namespace v8_debug_helper_internal
+
+#endif